og-pilot-js 0.2.0 → 0.2.1

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 CHANGED
@@ -88,38 +88,129 @@ The client automatically injects a `path` parameter on every request:
88
88
  | `default: true` | Forces the `path` parameter to `/`, regardless of the current request (unless `path` is provided explicitly) |
89
89
  | `path: "/..."` | Uses the provided path verbatim (normalized to start with `/`), overriding auto-resolution |
90
90
 
91
- ### Setting up request context
91
+ ### Framework Integration
92
92
 
93
- To enable automatic path resolution, set the current request context in your middleware:
93
+ #### Next.js (App Router)
94
94
 
95
- **Express:**
95
+ In Next.js, the recommended approach is to use `generateMetadata` and build the
96
+ path directly from `params` and `searchParams` (no middleware needed):
96
97
 
97
98
  ```ts
98
- import { setCurrentRequest, clearCurrentRequest } from "og-pilot-js";
99
+ // app/products/[id]/page.tsx
100
+ import type { Metadata } from "next";
101
+ import { buildPathFromNextProps, createImage } from "og-pilot-js";
102
+
103
+ export async function generateMetadata(props): Promise<Metadata> {
104
+ const path = await buildPathFromNextProps("/products/[id]", props);
105
+ const imageUrl = await createImage(
106
+ {
107
+ template: "product",
108
+ title: "Product page",
109
+ },
110
+ { path }
111
+ );
112
+
113
+ return {
114
+ openGraph: {
115
+ images: [imageUrl],
116
+ },
117
+ };
118
+ }
119
+ ```
99
120
 
100
- app.use((req, res, next) => {
101
- setCurrentRequest({ url: req.originalUrl });
102
- res.on("finish", () => clearCurrentRequest());
103
- next();
104
- });
121
+ For catch-all routes:
122
+
123
+ ```ts
124
+ // app/blog/[...slug]/page.tsx
125
+ import { buildPathFromNextProps } from "og-pilot-js";
126
+
127
+ export async function generateMetadata(props) {
128
+ const path = await buildPathFromNextProps("/blog/[...slug]", props);
129
+ // => /blog/2024/launch?ref=twitter
130
+ }
105
131
  ```
106
132
 
107
- **Next.js App Router (middleware.ts):**
133
+ #### Express
108
134
 
109
135
  ```ts
110
- import { setCurrentRequest } from "og-pilot-js";
111
- import { NextResponse } from "next/server";
112
- import type { NextRequest } from "next/server";
136
+ import express from "express";
137
+ import { createExpressMiddleware } from "og-pilot-js";
138
+
139
+ const app = express();
140
+ app.use(createExpressMiddleware());
141
+
142
+ // Now path is automatically captured in all routes
143
+ app.get("/blog/:slug", async (req, res) => {
144
+ const imageUrl = await createImage({
145
+ template: "blog_post",
146
+ title: "My Blog Post",
147
+ });
148
+ // path is automatically set to /blog/:slug
149
+ });
150
+ ```
151
+
152
+ #### Nuxt (useSeoMeta)
113
153
 
114
- export function middleware(request: NextRequest) {
115
- setCurrentRequest({
116
- url: request.nextUrl.pathname + request.nextUrl.search
154
+ Nuxt recommends `useSeoMeta` for SEO tags. You can generate the OG image URL
155
+ server-side and pass it directly:
156
+
157
+ ```vue
158
+ <!-- app/pages/products/[id].vue -->
159
+ <script setup lang="ts">
160
+ import { createImage } from "og-pilot-js";
161
+
162
+ const route = useRoute();
163
+
164
+ if (import.meta.server) {
165
+ const imageUrl = await createImage(
166
+ {
167
+ template: "product",
168
+ title: "Product page",
169
+ },
170
+ { path: route.fullPath }
171
+ );
172
+
173
+ useSeoMeta({
174
+ title: "Product page",
175
+ ogTitle: "Product page",
176
+ ogImage: imageUrl,
177
+ twitterCard: "summary_large_image",
117
178
  });
118
- return NextResponse.next();
119
179
  }
180
+ </script>
181
+ ```
182
+
183
+ If you need reactive metadata, pass a computed getter:
184
+
185
+ ```vue
186
+ <script setup lang="ts">
187
+ const title = ref("My title");
188
+
189
+ useSeoMeta({
190
+ title,
191
+ ogTitle: () => title.value,
192
+ });
193
+ </script>
120
194
  ```
121
195
 
122
- **Using withRequestContext (preferred for async safety):**
196
+ #### Other Frameworks
197
+
198
+ For SvelteKit, Remix, or other frameworks, use `withRequestContext` in your server middleware:
199
+
200
+ ```ts
201
+ // SvelteKit hooks (src/hooks.server.ts)
202
+ import { setCurrentRequest } from "og-pilot-js";
203
+ import type { Handle } from "@sveltejs/kit";
204
+
205
+ export const handle: Handle = async ({ event, resolve }) => {
206
+ setCurrentRequest({ url: event.url.pathname + event.url.search });
207
+ return resolve(event);
208
+ };
209
+ ```
210
+
211
+ #### Using withRequestContext (async-safe)
212
+
213
+ For fine-grained control or when middleware isn't suitable:
123
214
 
124
215
  ```ts
125
216
  import { withRequestContext, createImage } from "og-pilot-js";
package/dist/index.cjs CHANGED
@@ -25,13 +25,17 @@ __export(index_exports, {
25
25
  ConfigurationError: () => ConfigurationError,
26
26
  OgPilotError: () => OgPilotError,
27
27
  RequestError: () => RequestError,
28
+ buildPathFromNextParams: () => buildPathFromNextParams,
29
+ buildPathFromNextProps: () => buildPathFromNextProps,
28
30
  clearCurrentRequest: () => clearCurrentRequest,
29
31
  client: () => client,
30
32
  configure: () => configure,
31
33
  createClient: () => createClient,
34
+ createExpressMiddleware: () => createExpressMiddleware,
32
35
  createImage: () => createImage,
33
36
  default: () => index_default,
34
37
  getConfig: () => getConfig,
38
+ getPathFromExpressRequest: () => getPathFromExpressRequest,
35
39
  resetConfig: () => resetConfig,
36
40
  setCurrentRequest: () => setCurrentRequest,
37
41
  withRequestContext: () => withRequestContext
@@ -184,6 +188,75 @@ function getCurrentPath() {
184
188
  }
185
189
  return getPathFromEnv();
186
190
  }
191
+ async function buildPathFromNextProps(routePattern, props) {
192
+ const params = await props.params;
193
+ const searchParams = props.searchParams ? await props.searchParams : void 0;
194
+ return buildPathFromNextParams(routePattern, params, searchParams);
195
+ }
196
+ function buildPathFromNextParams(routePattern, params, searchParams) {
197
+ const segments = routePattern.split("/").filter((segment) => segment.length > 0);
198
+ const builtSegments = [];
199
+ for (const segment of segments) {
200
+ const catchAllMatch = segment.match(/^\[\.\.\.(.+)\]$/);
201
+ const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.(.+)\]\]$/);
202
+ const paramMatch = segment.match(/^\[(.+)\]$/);
203
+ if (optionalCatchAllMatch) {
204
+ const key = optionalCatchAllMatch[1];
205
+ const value = params[key];
206
+ if (value === void 0) {
207
+ continue;
208
+ }
209
+ if (Array.isArray(value)) {
210
+ builtSegments.push(...value);
211
+ } else {
212
+ builtSegments.push(value);
213
+ }
214
+ continue;
215
+ }
216
+ if (catchAllMatch) {
217
+ const key = catchAllMatch[1];
218
+ const value = params[key];
219
+ if (value === void 0) {
220
+ continue;
221
+ }
222
+ if (Array.isArray(value)) {
223
+ builtSegments.push(...value);
224
+ } else {
225
+ builtSegments.push(value);
226
+ }
227
+ continue;
228
+ }
229
+ if (paramMatch) {
230
+ const key = paramMatch[1];
231
+ const value = params[key];
232
+ if (value === void 0) {
233
+ continue;
234
+ }
235
+ if (Array.isArray(value)) {
236
+ builtSegments.push(value.join("/"));
237
+ } else {
238
+ builtSegments.push(value);
239
+ }
240
+ continue;
241
+ }
242
+ builtSegments.push(segment);
243
+ }
244
+ const path = `/${builtSegments.join("/")}`;
245
+ const query = serializeSearchParams(searchParams);
246
+ return query.length > 0 ? `${path}?${query}` : path;
247
+ }
248
+ function createExpressMiddleware() {
249
+ return (req, _res, next) => {
250
+ setCurrentRequest({
251
+ url: req.originalUrl || req.url,
252
+ path: req.originalUrl || req.url
253
+ });
254
+ next();
255
+ };
256
+ }
257
+ function getPathFromExpressRequest(req) {
258
+ return req.originalUrl || req.url || "/";
259
+ }
187
260
  function extractPathFromUrl(url) {
188
261
  if (url.startsWith("http://") || url.startsWith("https://")) {
189
262
  try {
@@ -195,6 +268,28 @@ function extractPathFromUrl(url) {
195
268
  }
196
269
  return url;
197
270
  }
271
+ function serializeSearchParams(searchParams) {
272
+ if (!searchParams) {
273
+ return "";
274
+ }
275
+ if (searchParams instanceof URLSearchParams) {
276
+ return searchParams.toString();
277
+ }
278
+ const params = new URLSearchParams();
279
+ for (const [key, value] of Object.entries(searchParams)) {
280
+ if (value === void 0) {
281
+ continue;
282
+ }
283
+ if (Array.isArray(value)) {
284
+ for (const entry of value) {
285
+ params.append(key, entry);
286
+ }
287
+ } else {
288
+ params.append(key, value);
289
+ }
290
+ }
291
+ return params.toString();
292
+ }
198
293
  function getPathFromEnv() {
199
294
  if (typeof process === "undefined" || !process.env) {
200
295
  return void 0;
@@ -428,6 +523,10 @@ var OgPilot = {
428
523
  setCurrentRequest,
429
524
  clearCurrentRequest,
430
525
  withRequestContext,
526
+ createExpressMiddleware,
527
+ getPathFromExpressRequest,
528
+ buildPathFromNextProps,
529
+ buildPathFromNextParams,
431
530
  Configuration,
432
531
  ConfigurationError,
433
532
  OgPilotError,
@@ -441,12 +540,16 @@ var index_default = OgPilot;
441
540
  ConfigurationError,
442
541
  OgPilotError,
443
542
  RequestError,
543
+ buildPathFromNextParams,
544
+ buildPathFromNextProps,
444
545
  clearCurrentRequest,
445
546
  client,
446
547
  configure,
447
548
  createClient,
549
+ createExpressMiddleware,
448
550
  createImage,
449
551
  getConfig,
552
+ getPathFromExpressRequest,
450
553
  resetConfig,
451
554
  setCurrentRequest,
452
555
  withRequestContext
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/errors.ts","../src/jwt.ts","../src/request-context.ts","../src/client.ts"],"sourcesContent":["import { Client } from \"./client\";\nimport { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, OgPilotError, RequestError } from \"./errors\";\nimport {\n clearCurrentRequest,\n setCurrentRequest,\n withRequestContext,\n} from \"./request-context\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (\n updater: (config: Configuration) => void\n): Configuration => {\n updater(defaultConfig);\n return defaultConfig;\n};\n\nexport const resetConfig = (): void => {\n defaultConfig = new Configuration();\n};\n\nexport const getConfig = (): Configuration => defaultConfig;\n\nexport const client = (): Client => new Client(defaultConfig);\n\nexport const createImage = (\n params: Record<string, unknown> = {},\n options: Parameters<Client[\"createImage\"]>[1] = {}\n): ReturnType<Client[\"createImage\"]> => client().createImage(params, options);\n\nexport const createClient = (options: OgPilotConfigOptions = {}): Client =>\n new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n setCurrentRequest,\n clearCurrentRequest,\n withRequestContext,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError,\n};\n\nexport default OgPilot;\nexport type { CreateImageOptions } from \"./client\";\nexport {\n clearCurrentRequest,\n Client,\n Configuration,\n ConfigurationError,\n OgPilotConfigOptions,\n OgPilotError,\n RequestError,\n setCurrentRequest,\n withRequestContext,\n};\n","export interface OgPilotConfigOptions {\n apiKey?: string;\n domain?: string;\n baseUrl?: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = \"https://ogpilot.com\";\n\nfunction readEnv(key: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[key];\n }\n\n return undefined;\n}\n\nexport class Configuration {\n apiKey?: string;\n domain?: string;\n baseUrl: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n\n constructor(options: OgPilotConfigOptions = {}) {\n this.apiKey = options.apiKey ?? readEnv(\"OG_PILOT_API_KEY\");\n this.domain = options.domain ?? readEnv(\"OG_PILOT_DOMAIN\");\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.openTimeoutMs = options.openTimeoutMs ?? 5000;\n this.readTimeoutMs = options.readTimeoutMs ?? 10000;\n this.fetch = options.fetch;\n }\n}\n","export class OgPilotError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OgPilotError\";\n }\n}\n\nexport class ConfigurationError extends OgPilotError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class RequestError extends OgPilotError {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"RequestError\";\n this.status = status;\n }\n}\n","const encoder = new TextEncoder();\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n\n if (typeof btoa === \"undefined\") {\n throw new Error(\"btoa is not available in this environment\");\n }\n\n return btoa(binary);\n}\n\nfunction base64UrlEncodeBytes(bytes: Uint8Array): string {\n return toBase64(bytes).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction base64UrlEncodeString(value: string): string {\n return base64UrlEncodeBytes(encoder.encode(value));\n}\n\nfunction getSubtleCrypto(): SubtleCrypto | null {\n if (typeof globalThis !== \"undefined\" && globalThis.crypto && globalThis.crypto.subtle) {\n return globalThis.crypto.subtle;\n }\n\n return null;\n}\n\nasync function hmacSha256(data: string, secret: string): Promise<Uint8Array> {\n const subtle = getSubtleCrypto();\n\n if (!subtle) {\n throw new Error(\"Web Crypto API is not available; requires a Node 18+ or Edge runtime.\");\n }\n\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await subtle.sign(\"HMAC\", key, encoder.encode(data));\n return new Uint8Array(signature);\n}\n\nexport async function signJwt(payload: Record<string, unknown>, secret: string): Promise<string> {\n const header = { alg: \"HS256\", typ: \"JWT\" };\n const encodedHeader = base64UrlEncodeString(JSON.stringify(header));\n const encodedPayload = base64UrlEncodeString(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = await hmacSha256(signingInput, secret);\n\n return `${signingInput}.${base64UrlEncodeBytes(signature)}`;\n}\n","/**\n * Request context for automatic path resolution.\n *\n * In Node.js environments, this uses AsyncLocalStorage to store the current\n * request URL per async execution context. In edge runtimes or browsers,\n * it falls back to a simple variable (not request-scoped).\n */\n\ntype RequestInfo = {\n url?: string;\n path?: string;\n};\n\ninterface AsyncStorage {\n getStore: () => RequestInfo | undefined;\n run: <T>(store: RequestInfo, callback: () => T) => T;\n}\n\n// Try to use AsyncLocalStorage if available (Node.js 12.17+)\nlet asyncLocalStorage: AsyncStorage | null = null;\n\n// Fallback for environments without AsyncLocalStorage\nlet fallbackRequest: RequestInfo | undefined;\n\n// Create a fallback implementation\nfunction createFallbackStorage(): AsyncStorage {\n return {\n getStore: () => fallbackRequest,\n run: <T>(_store: RequestInfo, callback: () => T): T => {\n const prev = fallbackRequest;\n fallbackRequest = _store;\n try {\n return callback();\n } finally {\n fallbackRequest = prev;\n }\n },\n };\n}\n\n// Lazy initialization to avoid issues in environments where async_hooks isn't available\nfunction getAsyncLocalStorage(): AsyncStorage {\n if (asyncLocalStorage === null) {\n try {\n // Dynamic import to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { AsyncLocalStorage } = require(\"async_hooks\");\n const storage = new AsyncLocalStorage();\n asyncLocalStorage = {\n getStore: () => storage.getStore() as RequestInfo | undefined,\n run: <T>(store: RequestInfo, callback: () => T): T =>\n storage.run(store, callback),\n };\n } catch {\n // AsyncLocalStorage not available, use fallback\n asyncLocalStorage = createFallbackStorage();\n }\n }\n return asyncLocalStorage!;\n}\n\n/**\n * Sets the current request context for automatic path resolution.\n * Call this in your middleware/handler before using OG Pilot.\n *\n * @example Express middleware\n * ```ts\n * app.use((req, res, next) => {\n * setCurrentRequest({ url: req.originalUrl });\n * next();\n * });\n * ```\n *\n * @example Next.js middleware\n * ```ts\n * export function middleware(request: NextRequest) {\n * setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });\n * return NextResponse.next();\n * }\n * ```\n */\nexport function setCurrentRequest(request: RequestInfo): void {\n fallbackRequest = request;\n}\n\n/**\n * Clears the current request context.\n * Call this after the request is complete if using setCurrentRequest directly.\n */\nexport function clearCurrentRequest(): void {\n fallbackRequest = undefined;\n}\n\n/**\n * Runs a callback with the given request context.\n * The context is automatically cleared after the callback completes.\n * This is the preferred method for setting request context.\n *\n * @example Express middleware\n * ```ts\n * import { withRequestContext } from \"og-pilot-js\";\n *\n * app.use((req, res, next) => {\n * withRequestContext({ url: req.originalUrl }, () => {\n * next();\n * });\n * });\n * ```\n */\nexport function withRequestContext<T>(\n request: RequestInfo,\n callback: () => T\n): T {\n return getAsyncLocalStorage().run(request, callback);\n}\n\n/**\n * Gets the current request info from context.\n * @internal\n */\nexport function getCurrentRequest(): RequestInfo | undefined {\n // Try AsyncLocalStorage first, then fallback\n const store = getAsyncLocalStorage().getStore();\n return store ?? fallbackRequest;\n}\n\n/**\n * Gets the current request path from context or environment.\n * @internal\n */\nexport function getCurrentPath(): string | undefined {\n const request = getCurrentRequest();\n\n if (request?.path) {\n return request.path;\n }\n\n if (request?.url) {\n return extractPathFromUrl(request.url);\n }\n\n // Fallback to environment variables (similar to Ruby's env_fullpath)\n return getPathFromEnv();\n}\n\nfunction extractPathFromUrl(url: string): string {\n // Handle full URLs\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n try {\n const parsed = new URL(url);\n return parsed.pathname + parsed.search;\n } catch {\n return url;\n }\n }\n\n return url;\n}\n\nfunction getPathFromEnv(): string | undefined {\n if (typeof process === \"undefined\" || !process.env) {\n return undefined;\n }\n\n const env = process.env;\n\n // Check various environment variables (similar to Ruby implementation)\n const requestUri = env.REQUEST_URI;\n if (requestUri && requestUri.length > 0) {\n return requestUri;\n }\n\n const originalFullpath = env.ORIGINAL_FULLPATH;\n if (originalFullpath && originalFullpath.length > 0) {\n return originalFullpath;\n }\n\n const pathInfo = env.PATH_INFO;\n if (pathInfo && pathInfo.length > 0) {\n const queryString = env.QUERY_STRING ?? \"\";\n return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;\n }\n\n const requestPath = env.REQUEST_PATH;\n if (requestPath && requestPath.length > 0) {\n return requestPath;\n }\n\n return undefined;\n}\n","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\nimport { getCurrentPath } from \"./request-context\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\n /**\n * When true, forces the path to \"/\" regardless of the current request.\n * Useful for generating default/fallback OG images.\n */\n default?: boolean;\n}\n\nconst ENDPOINT_PATH = \"/api/v1/images\";\n\nexport class Client {\n private config: Configuration;\n\n constructor(config: Configuration | OgPilotConfigOptions = {}) {\n this.config =\n config instanceof Configuration ? config : new Configuration(config);\n }\n\n async createImage(\n params: Record<string, unknown> = {},\n options: CreateImageOptions = {}\n ): Promise<unknown> {\n const {\n json = false,\n iat,\n headers = {},\n default: useDefault = false,\n } = options;\n\n // Always include a path; manual overrides win, otherwise resolve from the current request.\n const resolvedParams = { ...params };\n const manualPath = resolvedParams.path;\n delete resolvedParams.path;\n resolvedParams.path = this.resolvePath(manualPath, useDefault);\n\n const url = await this.buildUrl(resolvedParams, iat);\n const response = await this.request(url, json, headers);\n\n if (json) {\n const body = await response.text();\n return JSON.parse(body);\n }\n\n return response.headers.get(\"location\") ?? response.url ?? url.toString();\n }\n\n /**\n * Resolves the path parameter for the request.\n * Priority: manual path > current request path > \"/\"\n */\n private resolvePath(manualPath: unknown, useDefault: boolean): string {\n // Manual path always wins if provided\n if (manualPath !== undefined && manualPath !== null) {\n const pathStr = String(manualPath).trim();\n if (pathStr.length > 0) {\n return this.normalizePath(pathStr);\n }\n }\n\n // If default is true, return \"/\"\n if (useDefault) {\n return \"/\";\n }\n\n // Try to get path from current request context\n const currentPath = getCurrentPath();\n return this.normalizePath(currentPath);\n }\n\n /**\n * Normalizes a path to ensure it starts with \"/\" and handles full URLs.\n */\n private normalizePath(path: string | undefined | null): string {\n if (path === undefined || path === null) {\n return \"/\";\n }\n\n let cleaned = String(path).trim();\n if (cleaned.length === 0) {\n return \"/\";\n }\n\n // Extract path from full URLs\n if (cleaned.startsWith(\"http://\") || cleaned.startsWith(\"https://\")) {\n try {\n const url = new URL(cleaned);\n cleaned = url.pathname + url.search;\n } catch {\n // Keep as-is if URL parsing fails\n }\n }\n\n // Ensure path starts with \"/\"\n if (!cleaned.startsWith(\"/\")) {\n cleaned = \"/\" + cleaned;\n }\n\n return cleaned;\n }\n\n private async request(\n url: URL,\n json: boolean,\n headers: Record<string, string>\n ): Promise<Response> {\n const fetchImpl =\n this.config.fetch ?? (typeof fetch !== \"undefined\" ? fetch : undefined);\n\n if (!fetchImpl) {\n throw new ConfigurationError(\n \"Fetch API is not available; provide a fetch implementation in the configuration.\"\n );\n }\n\n const requestHeaders = new Headers();\n if (json) {\n requestHeaders.set(\"Accept\", \"application/json\");\n }\n\n Object.entries(headers).forEach(([key, value]) => {\n requestHeaders.set(key, value);\n });\n\n const timeoutMs = this.totalTimeoutMs();\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs && timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n try {\n const response = await fetchImpl(url.toString(), {\n method: \"GET\",\n headers: requestHeaders,\n redirect: \"manual\",\n signal: controller.signal,\n });\n\n if (response.status >= 400) {\n const body = await response.text().catch(() => \"\");\n throw new RequestError(\n `OG Pilot request failed with status ${response.status}: ${body}`,\n response.status\n );\n }\n\n return response;\n } catch (error) {\n if (error instanceof RequestError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new RequestError(`OG Pilot request timed out: ${error.message}`);\n }\n\n if (error instanceof Error) {\n throw new RequestError(`OG Pilot request failed: ${error.message}`);\n }\n\n throw new RequestError(\"OG Pilot request failed.\");\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async buildUrl(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Promise<URL> {\n const payload = this.buildPayload(params, iat);\n const token = await signJwt(payload, this.apiKey());\n const url = new URL(ENDPOINT_PATH, this.config.baseUrl);\n url.searchParams.set(\"token\", token);\n return url;\n }\n\n private buildPayload(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Record<string, unknown> {\n const payload: Record<string, unknown> = { ...params };\n\n if (iat !== undefined && iat !== null) {\n payload.iat = normalizeIat(iat);\n }\n\n if (payload.iss === undefined || payload.iss === null) {\n payload.iss = this.domain();\n }\n\n if (payload.sub === undefined || payload.sub === null) {\n payload.sub = this.apiKeyPrefix();\n }\n\n this.validatePayload(payload);\n return payload;\n }\n\n private validatePayload(payload: Record<string, unknown>): void {\n if (\n payload.iss === undefined ||\n payload.iss === null ||\n String(payload.iss).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (\n payload.sub === undefined ||\n payload.sub === null ||\n String(payload.sub).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (\n payload.title === undefined ||\n payload.title === null ||\n String(payload.title).length === 0\n ) {\n throw new Error(\"OG Pilot title is required\");\n }\n }\n\n private apiKey(): string {\n if (this.config.apiKey !== undefined && this.config.apiKey !== null) {\n return this.config.apiKey;\n }\n\n throw new ConfigurationError(\"OG Pilot API key is missing\");\n }\n\n private domain(): string {\n if (this.config.domain !== undefined && this.config.domain !== null) {\n return this.config.domain;\n }\n\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n private apiKeyPrefix(): string {\n return this.apiKey().slice(0, 8);\n }\n\n private totalTimeoutMs(): number | undefined {\n const openTimeoutMs = this.config.openTimeoutMs;\n const readTimeoutMs = this.config.readTimeoutMs;\n\n if (openTimeoutMs === undefined && readTimeoutMs === undefined) {\n return undefined;\n }\n\n const open = typeof openTimeoutMs === \"number\" ? openTimeoutMs : 0;\n const read = typeof readTimeoutMs === \"number\" ? readTimeoutMs : 0;\n return open + read;\n }\n}\n\nfunction normalizeIat(iat: number | Date): number {\n if (iat instanceof Date) {\n return Math.floor(iat.getTime() / 1000);\n }\n\n if (iat > 100000000000) {\n return Math.floor(iat / 1000);\n }\n\n return Math.floor(iat);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/errors.ts","../src/jwt.ts","../src/request-context.ts","../src/client.ts"],"sourcesContent":["import { Client } from \"./client\";\nimport { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, OgPilotError, RequestError } from \"./errors\";\nimport {\n buildPathFromNextParams,\n buildPathFromNextProps,\n clearCurrentRequest,\n createExpressMiddleware,\n getPathFromExpressRequest,\n setCurrentRequest,\n withRequestContext,\n} from \"./request-context\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (\n updater: (config: Configuration) => void\n): Configuration => {\n updater(defaultConfig);\n return defaultConfig;\n};\n\nexport const resetConfig = (): void => {\n defaultConfig = new Configuration();\n};\n\nexport const getConfig = (): Configuration => defaultConfig;\n\nexport const client = (): Client => new Client(defaultConfig);\n\nexport const createImage = (\n params: Record<string, unknown> = {},\n options: Parameters<Client[\"createImage\"]>[1] = {}\n): ReturnType<Client[\"createImage\"]> => client().createImage(params, options);\n\nexport const createClient = (options: OgPilotConfigOptions = {}): Client =>\n new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n setCurrentRequest,\n clearCurrentRequest,\n withRequestContext,\n createExpressMiddleware,\n getPathFromExpressRequest,\n buildPathFromNextProps,\n buildPathFromNextParams,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError,\n};\n\nexport default OgPilot;\nexport type { CreateImageOptions } from \"./client\";\nexport type {\n NextMetadataProps,\n NextParams,\n NextSearchParams,\n} from \"./request-context\";\nexport {\n buildPathFromNextParams,\n buildPathFromNextProps,\n clearCurrentRequest,\n Client,\n Configuration,\n ConfigurationError,\n createExpressMiddleware,\n getPathFromExpressRequest,\n OgPilotConfigOptions,\n OgPilotError,\n RequestError,\n setCurrentRequest,\n withRequestContext,\n};\n","export interface OgPilotConfigOptions {\n apiKey?: string;\n domain?: string;\n baseUrl?: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = \"https://ogpilot.com\";\n\nfunction readEnv(key: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[key];\n }\n\n return undefined;\n}\n\nexport class Configuration {\n apiKey?: string;\n domain?: string;\n baseUrl: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n\n constructor(options: OgPilotConfigOptions = {}) {\n this.apiKey = options.apiKey ?? readEnv(\"OG_PILOT_API_KEY\");\n this.domain = options.domain ?? readEnv(\"OG_PILOT_DOMAIN\");\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.openTimeoutMs = options.openTimeoutMs ?? 5000;\n this.readTimeoutMs = options.readTimeoutMs ?? 10000;\n this.fetch = options.fetch;\n }\n}\n","export class OgPilotError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OgPilotError\";\n }\n}\n\nexport class ConfigurationError extends OgPilotError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class RequestError extends OgPilotError {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"RequestError\";\n this.status = status;\n }\n}\n","const encoder = new TextEncoder();\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n\n if (typeof btoa === \"undefined\") {\n throw new Error(\"btoa is not available in this environment\");\n }\n\n return btoa(binary);\n}\n\nfunction base64UrlEncodeBytes(bytes: Uint8Array): string {\n return toBase64(bytes).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction base64UrlEncodeString(value: string): string {\n return base64UrlEncodeBytes(encoder.encode(value));\n}\n\nfunction getSubtleCrypto(): SubtleCrypto | null {\n if (typeof globalThis !== \"undefined\" && globalThis.crypto && globalThis.crypto.subtle) {\n return globalThis.crypto.subtle;\n }\n\n return null;\n}\n\nasync function hmacSha256(data: string, secret: string): Promise<Uint8Array> {\n const subtle = getSubtleCrypto();\n\n if (!subtle) {\n throw new Error(\"Web Crypto API is not available; requires a Node 18+ or Edge runtime.\");\n }\n\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await subtle.sign(\"HMAC\", key, encoder.encode(data));\n return new Uint8Array(signature);\n}\n\nexport async function signJwt(payload: Record<string, unknown>, secret: string): Promise<string> {\n const header = { alg: \"HS256\", typ: \"JWT\" };\n const encodedHeader = base64UrlEncodeString(JSON.stringify(header));\n const encodedPayload = base64UrlEncodeString(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = await hmacSha256(signingInput, secret);\n\n return `${signingInput}.${base64UrlEncodeBytes(signature)}`;\n}\n","/**\n * Request context for automatic path resolution.\n *\n * In Node.js environments, this uses AsyncLocalStorage to store the current\n * request URL per async execution context. In edge runtimes or browsers,\n * it falls back to a simple variable (not request-scoped).\n */\n\ntype RequestInfo = {\n url?: string;\n path?: string;\n};\n\ninterface AsyncStorage {\n getStore: () => RequestInfo | undefined;\n run: <T>(store: RequestInfo, callback: () => T) => T;\n}\n\n// Try to use AsyncLocalStorage if available (Node.js 12.17+)\nlet asyncLocalStorage: AsyncStorage | null = null;\n\n// Fallback for environments without AsyncLocalStorage\nlet fallbackRequest: RequestInfo | undefined;\n\n// Create a fallback implementation\nfunction createFallbackStorage(): AsyncStorage {\n return {\n getStore: () => fallbackRequest,\n run: <T>(_store: RequestInfo, callback: () => T): T => {\n const prev = fallbackRequest;\n fallbackRequest = _store;\n try {\n return callback();\n } finally {\n fallbackRequest = prev;\n }\n },\n };\n}\n\n// Lazy initialization to avoid issues in environments where async_hooks isn't available\nfunction getAsyncLocalStorage(): AsyncStorage {\n if (asyncLocalStorage === null) {\n try {\n // Dynamic import to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { AsyncLocalStorage } = require(\"async_hooks\");\n const storage = new AsyncLocalStorage();\n asyncLocalStorage = {\n getStore: () => storage.getStore() as RequestInfo | undefined,\n run: <T>(store: RequestInfo, callback: () => T): T =>\n storage.run(store, callback),\n };\n } catch {\n // AsyncLocalStorage not available, use fallback\n asyncLocalStorage = createFallbackStorage();\n }\n }\n return asyncLocalStorage!;\n}\n\n/**\n * Sets the current request context for automatic path resolution.\n * Call this in your middleware/handler before using OG Pilot.\n *\n * @example Express middleware\n * ```ts\n * app.use((req, res, next) => {\n * setCurrentRequest({ url: req.originalUrl });\n * next();\n * });\n * ```\n *\n * @example Next.js middleware\n * ```ts\n * export function middleware(request: NextRequest) {\n * setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });\n * return NextResponse.next();\n * }\n * ```\n */\nexport function setCurrentRequest(request: RequestInfo): void {\n fallbackRequest = request;\n}\n\n/**\n * Clears the current request context.\n * Call this after the request is complete if using setCurrentRequest directly.\n */\nexport function clearCurrentRequest(): void {\n fallbackRequest = undefined;\n}\n\n/**\n * Runs a callback with the given request context.\n * The context is automatically cleared after the callback completes.\n * This is the preferred method for setting request context.\n *\n * @example Express middleware\n * ```ts\n * import { withRequestContext } from \"og-pilot-js\";\n *\n * app.use((req, res, next) => {\n * withRequestContext({ url: req.originalUrl }, () => {\n * next();\n * });\n * });\n * ```\n */\nexport function withRequestContext<T>(\n request: RequestInfo,\n callback: () => T\n): T {\n return getAsyncLocalStorage().run(request, callback);\n}\n\n/**\n * Gets the current request info from context.\n * @internal\n */\nexport function getCurrentRequest(): RequestInfo | undefined {\n // Try AsyncLocalStorage first, then fallback\n const store = getAsyncLocalStorage().getStore();\n return store ?? fallbackRequest;\n}\n\n/**\n * Gets the current request path from context or environment.\n * @internal\n */\nexport function getCurrentPath(): string | undefined {\n const request = getCurrentRequest();\n\n if (request?.path) {\n return request.path;\n }\n\n if (request?.url) {\n return extractPathFromUrl(request.url);\n }\n\n // Fallback to environment variables (similar to Ruby's env_fullpath)\n return getPathFromEnv();\n}\n\n// ============================================================================\n// Framework-specific helpers\n// ============================================================================\n\nexport type NextParamValue = string | string[] | undefined;\nexport type NextParams = Record<string, NextParamValue>;\nexport type NextSearchParams = Record<string, NextParamValue>;\nexport type NextMetadataProps = {\n params: NextParams | Promise<NextParams>;\n searchParams?: NextSearchParams | Promise<NextSearchParams>;\n};\n\n/**\n * Builds a URL path for Next.js App Router routes.\n *\n * Pass your route pattern (e.g. \"/products/[id]\") and Next.js params/searchParams.\n * This avoids middleware and fits naturally inside generateMetadata().\n *\n * @example app/products/[id]/page.tsx\n * ```ts\n * import { buildPathFromNextProps } from \"og-pilot-js\";\n *\n * export async function generateMetadata(props) {\n * const path = await buildPathFromNextProps(\"/products/[id]\", props);\n * // => \"/products/123?ref=twitter\"\n * }\n * ```\n */\nexport async function buildPathFromNextProps(\n routePattern: string,\n props: NextMetadataProps\n): Promise<string> {\n const params = await props.params;\n const searchParams = props.searchParams\n ? await props.searchParams\n : undefined;\n return buildPathFromNextParams(routePattern, params, searchParams);\n}\n\n/**\n * Builds a URL path for Next.js App Router routes from params/searchParams.\n *\n * @example\n * ```ts\n * const path = buildPathFromNextParams(\n * \"/blog/[...slug]\",\n * { slug: [\"2024\", \"launch\"] },\n * { ref: \"twitter\" }\n * );\n * // => \"/blog/2024/launch?ref=twitter\"\n * ```\n */\nexport function buildPathFromNextParams(\n routePattern: string,\n params: NextParams,\n searchParams?: NextSearchParams\n): string {\n const segments = routePattern\n .split(\"/\")\n .filter((segment) => segment.length > 0);\n const builtSegments: string[] = [];\n\n for (const segment of segments) {\n const catchAllMatch = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n const optionalCatchAllMatch = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n const paramMatch = segment.match(/^\\[(.+)\\]$/);\n\n if (optionalCatchAllMatch) {\n const key = optionalCatchAllMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(...value);\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n if (catchAllMatch) {\n const key = catchAllMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(...value);\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n if (paramMatch) {\n const key = paramMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(value.join(\"/\"));\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n builtSegments.push(segment);\n }\n\n const path = `/${builtSegments.join(\"/\")}`;\n const query = serializeSearchParams(searchParams);\n return query.length > 0 ? `${path}?${query}` : path;\n}\n\n/**\n * Creates an Express/Connect middleware that automatically sets request context.\n *\n * @example Express\n * ```ts\n * import express from \"express\";\n * import { createExpressMiddleware } from \"og-pilot-js\";\n *\n * const app = express();\n * app.use(createExpressMiddleware());\n * ```\n */\nexport function createExpressMiddleware(): ExpressMiddleware {\n return (req, _res, next) => {\n setCurrentRequest({\n url: req.originalUrl || req.url,\n path: req.originalUrl || req.url,\n });\n next();\n };\n}\n\n/**\n * Helper to extract path from an Express/Node.js request object.\n */\nexport function getPathFromExpressRequest(req: ExpressRequest): string {\n return req.originalUrl || req.url || \"/\";\n}\n\n// Type definitions for framework compatibility\n// These are minimal to avoid requiring framework dependencies\n\ninterface ExpressRequest {\n originalUrl?: string;\n url?: string;\n}\n\ntype ExpressMiddleware = (\n req: ExpressRequest,\n res: unknown,\n next: () => void\n) => void;\n\nfunction extractPathFromUrl(url: string): string {\n // Handle full URLs\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n try {\n const parsed = new URL(url);\n return parsed.pathname + parsed.search;\n } catch {\n return url;\n }\n }\n\n return url;\n}\n\nfunction serializeSearchParams(\n searchParams?: NextSearchParams | URLSearchParams\n): string {\n if (!searchParams) {\n return \"\";\n }\n\n if (searchParams instanceof URLSearchParams) {\n return searchParams.toString();\n }\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n params.append(key, entry);\n }\n } else {\n params.append(key, value);\n }\n }\n\n return params.toString();\n}\n\nfunction getPathFromEnv(): string | undefined {\n if (typeof process === \"undefined\" || !process.env) {\n return undefined;\n }\n\n const env = process.env;\n\n // Check various environment variables (similar to Ruby implementation)\n const requestUri = env.REQUEST_URI;\n if (requestUri && requestUri.length > 0) {\n return requestUri;\n }\n\n const originalFullpath = env.ORIGINAL_FULLPATH;\n if (originalFullpath && originalFullpath.length > 0) {\n return originalFullpath;\n }\n\n const pathInfo = env.PATH_INFO;\n if (pathInfo && pathInfo.length > 0) {\n const queryString = env.QUERY_STRING ?? \"\";\n return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;\n }\n\n const requestPath = env.REQUEST_PATH;\n if (requestPath && requestPath.length > 0) {\n return requestPath;\n }\n\n return undefined;\n}\n","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\nimport { getCurrentPath } from \"./request-context\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\n /**\n * When true, forces the path to \"/\" regardless of the current request.\n * Useful for generating default/fallback OG images.\n */\n default?: boolean;\n}\n\nconst ENDPOINT_PATH = \"/api/v1/images\";\n\nexport class Client {\n private config: Configuration;\n\n constructor(config: Configuration | OgPilotConfigOptions = {}) {\n this.config =\n config instanceof Configuration ? config : new Configuration(config);\n }\n\n async createImage(\n params: Record<string, unknown> = {},\n options: CreateImageOptions = {}\n ): Promise<unknown> {\n const {\n json = false,\n iat,\n headers = {},\n default: useDefault = false,\n } = options;\n\n // Always include a path; manual overrides win, otherwise resolve from the current request.\n const resolvedParams = { ...params };\n const manualPath = resolvedParams.path;\n delete resolvedParams.path;\n resolvedParams.path = this.resolvePath(manualPath, useDefault);\n\n const url = await this.buildUrl(resolvedParams, iat);\n const response = await this.request(url, json, headers);\n\n if (json) {\n const body = await response.text();\n return JSON.parse(body);\n }\n\n return response.headers.get(\"location\") ?? response.url ?? url.toString();\n }\n\n /**\n * Resolves the path parameter for the request.\n * Priority: manual path > current request path > \"/\"\n */\n private resolvePath(manualPath: unknown, useDefault: boolean): string {\n // Manual path always wins if provided\n if (manualPath !== undefined && manualPath !== null) {\n const pathStr = String(manualPath).trim();\n if (pathStr.length > 0) {\n return this.normalizePath(pathStr);\n }\n }\n\n // If default is true, return \"/\"\n if (useDefault) {\n return \"/\";\n }\n\n // Try to get path from current request context\n const currentPath = getCurrentPath();\n return this.normalizePath(currentPath);\n }\n\n /**\n * Normalizes a path to ensure it starts with \"/\" and handles full URLs.\n */\n private normalizePath(path: string | undefined | null): string {\n if (path === undefined || path === null) {\n return \"/\";\n }\n\n let cleaned = String(path).trim();\n if (cleaned.length === 0) {\n return \"/\";\n }\n\n // Extract path from full URLs\n if (cleaned.startsWith(\"http://\") || cleaned.startsWith(\"https://\")) {\n try {\n const url = new URL(cleaned);\n cleaned = url.pathname + url.search;\n } catch {\n // Keep as-is if URL parsing fails\n }\n }\n\n // Ensure path starts with \"/\"\n if (!cleaned.startsWith(\"/\")) {\n cleaned = \"/\" + cleaned;\n }\n\n return cleaned;\n }\n\n private async request(\n url: URL,\n json: boolean,\n headers: Record<string, string>\n ): Promise<Response> {\n const fetchImpl =\n this.config.fetch ?? (typeof fetch !== \"undefined\" ? fetch : undefined);\n\n if (!fetchImpl) {\n throw new ConfigurationError(\n \"Fetch API is not available; provide a fetch implementation in the configuration.\"\n );\n }\n\n const requestHeaders = new Headers();\n if (json) {\n requestHeaders.set(\"Accept\", \"application/json\");\n }\n\n Object.entries(headers).forEach(([key, value]) => {\n requestHeaders.set(key, value);\n });\n\n const timeoutMs = this.totalTimeoutMs();\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs && timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n try {\n const response = await fetchImpl(url.toString(), {\n method: \"GET\",\n headers: requestHeaders,\n redirect: \"manual\",\n signal: controller.signal,\n });\n\n if (response.status >= 400) {\n const body = await response.text().catch(() => \"\");\n throw new RequestError(\n `OG Pilot request failed with status ${response.status}: ${body}`,\n response.status\n );\n }\n\n return response;\n } catch (error) {\n if (error instanceof RequestError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new RequestError(`OG Pilot request timed out: ${error.message}`);\n }\n\n if (error instanceof Error) {\n throw new RequestError(`OG Pilot request failed: ${error.message}`);\n }\n\n throw new RequestError(\"OG Pilot request failed.\");\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async buildUrl(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Promise<URL> {\n const payload = this.buildPayload(params, iat);\n const token = await signJwt(payload, this.apiKey());\n const url = new URL(ENDPOINT_PATH, this.config.baseUrl);\n url.searchParams.set(\"token\", token);\n return url;\n }\n\n private buildPayload(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Record<string, unknown> {\n const payload: Record<string, unknown> = { ...params };\n\n if (iat !== undefined && iat !== null) {\n payload.iat = normalizeIat(iat);\n }\n\n if (payload.iss === undefined || payload.iss === null) {\n payload.iss = this.domain();\n }\n\n if (payload.sub === undefined || payload.sub === null) {\n payload.sub = this.apiKeyPrefix();\n }\n\n this.validatePayload(payload);\n return payload;\n }\n\n private validatePayload(payload: Record<string, unknown>): void {\n if (\n payload.iss === undefined ||\n payload.iss === null ||\n String(payload.iss).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (\n payload.sub === undefined ||\n payload.sub === null ||\n String(payload.sub).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (\n payload.title === undefined ||\n payload.title === null ||\n String(payload.title).length === 0\n ) {\n throw new Error(\"OG Pilot title is required\");\n }\n }\n\n private apiKey(): string {\n if (this.config.apiKey !== undefined && this.config.apiKey !== null) {\n return this.config.apiKey;\n }\n\n throw new ConfigurationError(\"OG Pilot API key is missing\");\n }\n\n private domain(): string {\n if (this.config.domain !== undefined && this.config.domain !== null) {\n return this.config.domain;\n }\n\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n private apiKeyPrefix(): string {\n return this.apiKey().slice(0, 8);\n }\n\n private totalTimeoutMs(): number | undefined {\n const openTimeoutMs = this.config.openTimeoutMs;\n const readTimeoutMs = this.config.readTimeoutMs;\n\n if (openTimeoutMs === undefined && readTimeoutMs === undefined) {\n return undefined;\n }\n\n const open = typeof openTimeoutMs === \"number\" ? openTimeoutMs : 0;\n const read = typeof readTimeoutMs === \"number\" ? readTimeoutMs : 0;\n return open + read;\n }\n}\n\nfunction normalizeIat(iat: number | Date): number {\n if (iat instanceof Date) {\n return Math.floor(iat.getTime() / 1000);\n }\n\n if (iat > 100000000000) {\n return Math.floor(iat / 1000);\n }\n\n return Math.floor(iat);\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -114,6 +114,66 @@ declare function clearCurrentRequest(): void;
114
114
  * ```
115
115
  */
116
116
  declare function withRequestContext<T>(request: RequestInfo, callback: () => T): T;
117
+ type NextParamValue = string | string[] | undefined;
118
+ type NextParams = Record<string, NextParamValue>;
119
+ type NextSearchParams = Record<string, NextParamValue>;
120
+ type NextMetadataProps = {
121
+ params: NextParams | Promise<NextParams>;
122
+ searchParams?: NextSearchParams | Promise<NextSearchParams>;
123
+ };
124
+ /**
125
+ * Builds a URL path for Next.js App Router routes.
126
+ *
127
+ * Pass your route pattern (e.g. "/products/[id]") and Next.js params/searchParams.
128
+ * This avoids middleware and fits naturally inside generateMetadata().
129
+ *
130
+ * @example app/products/[id]/page.tsx
131
+ * ```ts
132
+ * import { buildPathFromNextProps } from "og-pilot-js";
133
+ *
134
+ * export async function generateMetadata(props) {
135
+ * const path = await buildPathFromNextProps("/products/[id]", props);
136
+ * // => "/products/123?ref=twitter"
137
+ * }
138
+ * ```
139
+ */
140
+ declare function buildPathFromNextProps(routePattern: string, props: NextMetadataProps): Promise<string>;
141
+ /**
142
+ * Builds a URL path for Next.js App Router routes from params/searchParams.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * const path = buildPathFromNextParams(
147
+ * "/blog/[...slug]",
148
+ * { slug: ["2024", "launch"] },
149
+ * { ref: "twitter" }
150
+ * );
151
+ * // => "/blog/2024/launch?ref=twitter"
152
+ * ```
153
+ */
154
+ declare function buildPathFromNextParams(routePattern: string, params: NextParams, searchParams?: NextSearchParams): string;
155
+ /**
156
+ * Creates an Express/Connect middleware that automatically sets request context.
157
+ *
158
+ * @example Express
159
+ * ```ts
160
+ * import express from "express";
161
+ * import { createExpressMiddleware } from "og-pilot-js";
162
+ *
163
+ * const app = express();
164
+ * app.use(createExpressMiddleware());
165
+ * ```
166
+ */
167
+ declare function createExpressMiddleware(): ExpressMiddleware;
168
+ /**
169
+ * Helper to extract path from an Express/Node.js request object.
170
+ */
171
+ declare function getPathFromExpressRequest(req: ExpressRequest): string;
172
+ interface ExpressRequest {
173
+ originalUrl?: string;
174
+ url?: string;
175
+ }
176
+ type ExpressMiddleware = (req: ExpressRequest, res: unknown, next: () => void) => void;
117
177
 
118
178
  declare const configure: (updater: (config: Configuration) => void) => Configuration;
119
179
  declare const resetConfig: () => void;
@@ -131,10 +191,14 @@ declare const OgPilot: {
131
191
  setCurrentRequest: typeof setCurrentRequest;
132
192
  clearCurrentRequest: typeof clearCurrentRequest;
133
193
  withRequestContext: typeof withRequestContext;
194
+ createExpressMiddleware: typeof createExpressMiddleware;
195
+ getPathFromExpressRequest: typeof getPathFromExpressRequest;
196
+ buildPathFromNextProps: typeof buildPathFromNextProps;
197
+ buildPathFromNextParams: typeof buildPathFromNextParams;
134
198
  Configuration: typeof Configuration;
135
199
  ConfigurationError: typeof ConfigurationError;
136
200
  OgPilotError: typeof OgPilotError;
137
201
  RequestError: typeof RequestError;
138
202
  };
139
203
 
140
- export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, clearCurrentRequest, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig, setCurrentRequest, withRequestContext };
204
+ export { Client, Configuration, ConfigurationError, type CreateImageOptions, type NextMetadataProps, type NextParams, type NextSearchParams, type OgPilotConfigOptions, OgPilotError, RequestError, buildPathFromNextParams, buildPathFromNextProps, clearCurrentRequest, client, configure, createClient, createExpressMiddleware, createImage, OgPilot as default, getConfig, getPathFromExpressRequest, resetConfig, setCurrentRequest, withRequestContext };
package/dist/index.d.ts CHANGED
@@ -114,6 +114,66 @@ declare function clearCurrentRequest(): void;
114
114
  * ```
115
115
  */
116
116
  declare function withRequestContext<T>(request: RequestInfo, callback: () => T): T;
117
+ type NextParamValue = string | string[] | undefined;
118
+ type NextParams = Record<string, NextParamValue>;
119
+ type NextSearchParams = Record<string, NextParamValue>;
120
+ type NextMetadataProps = {
121
+ params: NextParams | Promise<NextParams>;
122
+ searchParams?: NextSearchParams | Promise<NextSearchParams>;
123
+ };
124
+ /**
125
+ * Builds a URL path for Next.js App Router routes.
126
+ *
127
+ * Pass your route pattern (e.g. "/products/[id]") and Next.js params/searchParams.
128
+ * This avoids middleware and fits naturally inside generateMetadata().
129
+ *
130
+ * @example app/products/[id]/page.tsx
131
+ * ```ts
132
+ * import { buildPathFromNextProps } from "og-pilot-js";
133
+ *
134
+ * export async function generateMetadata(props) {
135
+ * const path = await buildPathFromNextProps("/products/[id]", props);
136
+ * // => "/products/123?ref=twitter"
137
+ * }
138
+ * ```
139
+ */
140
+ declare function buildPathFromNextProps(routePattern: string, props: NextMetadataProps): Promise<string>;
141
+ /**
142
+ * Builds a URL path for Next.js App Router routes from params/searchParams.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * const path = buildPathFromNextParams(
147
+ * "/blog/[...slug]",
148
+ * { slug: ["2024", "launch"] },
149
+ * { ref: "twitter" }
150
+ * );
151
+ * // => "/blog/2024/launch?ref=twitter"
152
+ * ```
153
+ */
154
+ declare function buildPathFromNextParams(routePattern: string, params: NextParams, searchParams?: NextSearchParams): string;
155
+ /**
156
+ * Creates an Express/Connect middleware that automatically sets request context.
157
+ *
158
+ * @example Express
159
+ * ```ts
160
+ * import express from "express";
161
+ * import { createExpressMiddleware } from "og-pilot-js";
162
+ *
163
+ * const app = express();
164
+ * app.use(createExpressMiddleware());
165
+ * ```
166
+ */
167
+ declare function createExpressMiddleware(): ExpressMiddleware;
168
+ /**
169
+ * Helper to extract path from an Express/Node.js request object.
170
+ */
171
+ declare function getPathFromExpressRequest(req: ExpressRequest): string;
172
+ interface ExpressRequest {
173
+ originalUrl?: string;
174
+ url?: string;
175
+ }
176
+ type ExpressMiddleware = (req: ExpressRequest, res: unknown, next: () => void) => void;
117
177
 
118
178
  declare const configure: (updater: (config: Configuration) => void) => Configuration;
119
179
  declare const resetConfig: () => void;
@@ -131,10 +191,14 @@ declare const OgPilot: {
131
191
  setCurrentRequest: typeof setCurrentRequest;
132
192
  clearCurrentRequest: typeof clearCurrentRequest;
133
193
  withRequestContext: typeof withRequestContext;
194
+ createExpressMiddleware: typeof createExpressMiddleware;
195
+ getPathFromExpressRequest: typeof getPathFromExpressRequest;
196
+ buildPathFromNextProps: typeof buildPathFromNextProps;
197
+ buildPathFromNextParams: typeof buildPathFromNextParams;
134
198
  Configuration: typeof Configuration;
135
199
  ConfigurationError: typeof ConfigurationError;
136
200
  OgPilotError: typeof OgPilotError;
137
201
  RequestError: typeof RequestError;
138
202
  };
139
203
 
140
- export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, clearCurrentRequest, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig, setCurrentRequest, withRequestContext };
204
+ export { Client, Configuration, ConfigurationError, type CreateImageOptions, type NextMetadataProps, type NextParams, type NextSearchParams, type OgPilotConfigOptions, OgPilotError, RequestError, buildPathFromNextParams, buildPathFromNextProps, clearCurrentRequest, client, configure, createClient, createExpressMiddleware, createImage, OgPilot as default, getConfig, getPathFromExpressRequest, resetConfig, setCurrentRequest, withRequestContext };
package/dist/index.js CHANGED
@@ -151,6 +151,75 @@ function getCurrentPath() {
151
151
  }
152
152
  return getPathFromEnv();
153
153
  }
154
+ async function buildPathFromNextProps(routePattern, props) {
155
+ const params = await props.params;
156
+ const searchParams = props.searchParams ? await props.searchParams : void 0;
157
+ return buildPathFromNextParams(routePattern, params, searchParams);
158
+ }
159
+ function buildPathFromNextParams(routePattern, params, searchParams) {
160
+ const segments = routePattern.split("/").filter((segment) => segment.length > 0);
161
+ const builtSegments = [];
162
+ for (const segment of segments) {
163
+ const catchAllMatch = segment.match(/^\[\.\.\.(.+)\]$/);
164
+ const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.(.+)\]\]$/);
165
+ const paramMatch = segment.match(/^\[(.+)\]$/);
166
+ if (optionalCatchAllMatch) {
167
+ const key = optionalCatchAllMatch[1];
168
+ const value = params[key];
169
+ if (value === void 0) {
170
+ continue;
171
+ }
172
+ if (Array.isArray(value)) {
173
+ builtSegments.push(...value);
174
+ } else {
175
+ builtSegments.push(value);
176
+ }
177
+ continue;
178
+ }
179
+ if (catchAllMatch) {
180
+ const key = catchAllMatch[1];
181
+ const value = params[key];
182
+ if (value === void 0) {
183
+ continue;
184
+ }
185
+ if (Array.isArray(value)) {
186
+ builtSegments.push(...value);
187
+ } else {
188
+ builtSegments.push(value);
189
+ }
190
+ continue;
191
+ }
192
+ if (paramMatch) {
193
+ const key = paramMatch[1];
194
+ const value = params[key];
195
+ if (value === void 0) {
196
+ continue;
197
+ }
198
+ if (Array.isArray(value)) {
199
+ builtSegments.push(value.join("/"));
200
+ } else {
201
+ builtSegments.push(value);
202
+ }
203
+ continue;
204
+ }
205
+ builtSegments.push(segment);
206
+ }
207
+ const path = `/${builtSegments.join("/")}`;
208
+ const query = serializeSearchParams(searchParams);
209
+ return query.length > 0 ? `${path}?${query}` : path;
210
+ }
211
+ function createExpressMiddleware() {
212
+ return (req, _res, next) => {
213
+ setCurrentRequest({
214
+ url: req.originalUrl || req.url,
215
+ path: req.originalUrl || req.url
216
+ });
217
+ next();
218
+ };
219
+ }
220
+ function getPathFromExpressRequest(req) {
221
+ return req.originalUrl || req.url || "/";
222
+ }
154
223
  function extractPathFromUrl(url) {
155
224
  if (url.startsWith("http://") || url.startsWith("https://")) {
156
225
  try {
@@ -162,6 +231,28 @@ function extractPathFromUrl(url) {
162
231
  }
163
232
  return url;
164
233
  }
234
+ function serializeSearchParams(searchParams) {
235
+ if (!searchParams) {
236
+ return "";
237
+ }
238
+ if (searchParams instanceof URLSearchParams) {
239
+ return searchParams.toString();
240
+ }
241
+ const params = new URLSearchParams();
242
+ for (const [key, value] of Object.entries(searchParams)) {
243
+ if (value === void 0) {
244
+ continue;
245
+ }
246
+ if (Array.isArray(value)) {
247
+ for (const entry of value) {
248
+ params.append(key, entry);
249
+ }
250
+ } else {
251
+ params.append(key, value);
252
+ }
253
+ }
254
+ return params.toString();
255
+ }
165
256
  function getPathFromEnv() {
166
257
  if (typeof process === "undefined" || !process.env) {
167
258
  return void 0;
@@ -395,6 +486,10 @@ var OgPilot = {
395
486
  setCurrentRequest,
396
487
  clearCurrentRequest,
397
488
  withRequestContext,
489
+ createExpressMiddleware,
490
+ getPathFromExpressRequest,
491
+ buildPathFromNextProps,
492
+ buildPathFromNextParams,
398
493
  Configuration,
399
494
  ConfigurationError,
400
495
  OgPilotError,
@@ -407,13 +502,17 @@ export {
407
502
  ConfigurationError,
408
503
  OgPilotError,
409
504
  RequestError,
505
+ buildPathFromNextParams,
506
+ buildPathFromNextProps,
410
507
  clearCurrentRequest,
411
508
  client,
412
509
  configure,
413
510
  createClient,
511
+ createExpressMiddleware,
414
512
  createImage,
415
513
  index_default as default,
416
514
  getConfig,
515
+ getPathFromExpressRequest,
417
516
  resetConfig,
418
517
  setCurrentRequest,
419
518
  withRequestContext
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/jwt.ts","../src/request-context.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["export interface OgPilotConfigOptions {\n apiKey?: string;\n domain?: string;\n baseUrl?: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = \"https://ogpilot.com\";\n\nfunction readEnv(key: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[key];\n }\n\n return undefined;\n}\n\nexport class Configuration {\n apiKey?: string;\n domain?: string;\n baseUrl: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n\n constructor(options: OgPilotConfigOptions = {}) {\n this.apiKey = options.apiKey ?? readEnv(\"OG_PILOT_API_KEY\");\n this.domain = options.domain ?? readEnv(\"OG_PILOT_DOMAIN\");\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.openTimeoutMs = options.openTimeoutMs ?? 5000;\n this.readTimeoutMs = options.readTimeoutMs ?? 10000;\n this.fetch = options.fetch;\n }\n}\n","export class OgPilotError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OgPilotError\";\n }\n}\n\nexport class ConfigurationError extends OgPilotError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class RequestError extends OgPilotError {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"RequestError\";\n this.status = status;\n }\n}\n","const encoder = new TextEncoder();\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n\n if (typeof btoa === \"undefined\") {\n throw new Error(\"btoa is not available in this environment\");\n }\n\n return btoa(binary);\n}\n\nfunction base64UrlEncodeBytes(bytes: Uint8Array): string {\n return toBase64(bytes).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction base64UrlEncodeString(value: string): string {\n return base64UrlEncodeBytes(encoder.encode(value));\n}\n\nfunction getSubtleCrypto(): SubtleCrypto | null {\n if (typeof globalThis !== \"undefined\" && globalThis.crypto && globalThis.crypto.subtle) {\n return globalThis.crypto.subtle;\n }\n\n return null;\n}\n\nasync function hmacSha256(data: string, secret: string): Promise<Uint8Array> {\n const subtle = getSubtleCrypto();\n\n if (!subtle) {\n throw new Error(\"Web Crypto API is not available; requires a Node 18+ or Edge runtime.\");\n }\n\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await subtle.sign(\"HMAC\", key, encoder.encode(data));\n return new Uint8Array(signature);\n}\n\nexport async function signJwt(payload: Record<string, unknown>, secret: string): Promise<string> {\n const header = { alg: \"HS256\", typ: \"JWT\" };\n const encodedHeader = base64UrlEncodeString(JSON.stringify(header));\n const encodedPayload = base64UrlEncodeString(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = await hmacSha256(signingInput, secret);\n\n return `${signingInput}.${base64UrlEncodeBytes(signature)}`;\n}\n","/**\n * Request context for automatic path resolution.\n *\n * In Node.js environments, this uses AsyncLocalStorage to store the current\n * request URL per async execution context. In edge runtimes or browsers,\n * it falls back to a simple variable (not request-scoped).\n */\n\ntype RequestInfo = {\n url?: string;\n path?: string;\n};\n\ninterface AsyncStorage {\n getStore: () => RequestInfo | undefined;\n run: <T>(store: RequestInfo, callback: () => T) => T;\n}\n\n// Try to use AsyncLocalStorage if available (Node.js 12.17+)\nlet asyncLocalStorage: AsyncStorage | null = null;\n\n// Fallback for environments without AsyncLocalStorage\nlet fallbackRequest: RequestInfo | undefined;\n\n// Create a fallback implementation\nfunction createFallbackStorage(): AsyncStorage {\n return {\n getStore: () => fallbackRequest,\n run: <T>(_store: RequestInfo, callback: () => T): T => {\n const prev = fallbackRequest;\n fallbackRequest = _store;\n try {\n return callback();\n } finally {\n fallbackRequest = prev;\n }\n },\n };\n}\n\n// Lazy initialization to avoid issues in environments where async_hooks isn't available\nfunction getAsyncLocalStorage(): AsyncStorage {\n if (asyncLocalStorage === null) {\n try {\n // Dynamic import to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { AsyncLocalStorage } = require(\"async_hooks\");\n const storage = new AsyncLocalStorage();\n asyncLocalStorage = {\n getStore: () => storage.getStore() as RequestInfo | undefined,\n run: <T>(store: RequestInfo, callback: () => T): T =>\n storage.run(store, callback),\n };\n } catch {\n // AsyncLocalStorage not available, use fallback\n asyncLocalStorage = createFallbackStorage();\n }\n }\n return asyncLocalStorage!;\n}\n\n/**\n * Sets the current request context for automatic path resolution.\n * Call this in your middleware/handler before using OG Pilot.\n *\n * @example Express middleware\n * ```ts\n * app.use((req, res, next) => {\n * setCurrentRequest({ url: req.originalUrl });\n * next();\n * });\n * ```\n *\n * @example Next.js middleware\n * ```ts\n * export function middleware(request: NextRequest) {\n * setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });\n * return NextResponse.next();\n * }\n * ```\n */\nexport function setCurrentRequest(request: RequestInfo): void {\n fallbackRequest = request;\n}\n\n/**\n * Clears the current request context.\n * Call this after the request is complete if using setCurrentRequest directly.\n */\nexport function clearCurrentRequest(): void {\n fallbackRequest = undefined;\n}\n\n/**\n * Runs a callback with the given request context.\n * The context is automatically cleared after the callback completes.\n * This is the preferred method for setting request context.\n *\n * @example Express middleware\n * ```ts\n * import { withRequestContext } from \"og-pilot-js\";\n *\n * app.use((req, res, next) => {\n * withRequestContext({ url: req.originalUrl }, () => {\n * next();\n * });\n * });\n * ```\n */\nexport function withRequestContext<T>(\n request: RequestInfo,\n callback: () => T\n): T {\n return getAsyncLocalStorage().run(request, callback);\n}\n\n/**\n * Gets the current request info from context.\n * @internal\n */\nexport function getCurrentRequest(): RequestInfo | undefined {\n // Try AsyncLocalStorage first, then fallback\n const store = getAsyncLocalStorage().getStore();\n return store ?? fallbackRequest;\n}\n\n/**\n * Gets the current request path from context or environment.\n * @internal\n */\nexport function getCurrentPath(): string | undefined {\n const request = getCurrentRequest();\n\n if (request?.path) {\n return request.path;\n }\n\n if (request?.url) {\n return extractPathFromUrl(request.url);\n }\n\n // Fallback to environment variables (similar to Ruby's env_fullpath)\n return getPathFromEnv();\n}\n\nfunction extractPathFromUrl(url: string): string {\n // Handle full URLs\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n try {\n const parsed = new URL(url);\n return parsed.pathname + parsed.search;\n } catch {\n return url;\n }\n }\n\n return url;\n}\n\nfunction getPathFromEnv(): string | undefined {\n if (typeof process === \"undefined\" || !process.env) {\n return undefined;\n }\n\n const env = process.env;\n\n // Check various environment variables (similar to Ruby implementation)\n const requestUri = env.REQUEST_URI;\n if (requestUri && requestUri.length > 0) {\n return requestUri;\n }\n\n const originalFullpath = env.ORIGINAL_FULLPATH;\n if (originalFullpath && originalFullpath.length > 0) {\n return originalFullpath;\n }\n\n const pathInfo = env.PATH_INFO;\n if (pathInfo && pathInfo.length > 0) {\n const queryString = env.QUERY_STRING ?? \"\";\n return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;\n }\n\n const requestPath = env.REQUEST_PATH;\n if (requestPath && requestPath.length > 0) {\n return requestPath;\n }\n\n return undefined;\n}\n","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\nimport { getCurrentPath } from \"./request-context\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\n /**\n * When true, forces the path to \"/\" regardless of the current request.\n * Useful for generating default/fallback OG images.\n */\n default?: boolean;\n}\n\nconst ENDPOINT_PATH = \"/api/v1/images\";\n\nexport class Client {\n private config: Configuration;\n\n constructor(config: Configuration | OgPilotConfigOptions = {}) {\n this.config =\n config instanceof Configuration ? config : new Configuration(config);\n }\n\n async createImage(\n params: Record<string, unknown> = {},\n options: CreateImageOptions = {}\n ): Promise<unknown> {\n const {\n json = false,\n iat,\n headers = {},\n default: useDefault = false,\n } = options;\n\n // Always include a path; manual overrides win, otherwise resolve from the current request.\n const resolvedParams = { ...params };\n const manualPath = resolvedParams.path;\n delete resolvedParams.path;\n resolvedParams.path = this.resolvePath(manualPath, useDefault);\n\n const url = await this.buildUrl(resolvedParams, iat);\n const response = await this.request(url, json, headers);\n\n if (json) {\n const body = await response.text();\n return JSON.parse(body);\n }\n\n return response.headers.get(\"location\") ?? response.url ?? url.toString();\n }\n\n /**\n * Resolves the path parameter for the request.\n * Priority: manual path > current request path > \"/\"\n */\n private resolvePath(manualPath: unknown, useDefault: boolean): string {\n // Manual path always wins if provided\n if (manualPath !== undefined && manualPath !== null) {\n const pathStr = String(manualPath).trim();\n if (pathStr.length > 0) {\n return this.normalizePath(pathStr);\n }\n }\n\n // If default is true, return \"/\"\n if (useDefault) {\n return \"/\";\n }\n\n // Try to get path from current request context\n const currentPath = getCurrentPath();\n return this.normalizePath(currentPath);\n }\n\n /**\n * Normalizes a path to ensure it starts with \"/\" and handles full URLs.\n */\n private normalizePath(path: string | undefined | null): string {\n if (path === undefined || path === null) {\n return \"/\";\n }\n\n let cleaned = String(path).trim();\n if (cleaned.length === 0) {\n return \"/\";\n }\n\n // Extract path from full URLs\n if (cleaned.startsWith(\"http://\") || cleaned.startsWith(\"https://\")) {\n try {\n const url = new URL(cleaned);\n cleaned = url.pathname + url.search;\n } catch {\n // Keep as-is if URL parsing fails\n }\n }\n\n // Ensure path starts with \"/\"\n if (!cleaned.startsWith(\"/\")) {\n cleaned = \"/\" + cleaned;\n }\n\n return cleaned;\n }\n\n private async request(\n url: URL,\n json: boolean,\n headers: Record<string, string>\n ): Promise<Response> {\n const fetchImpl =\n this.config.fetch ?? (typeof fetch !== \"undefined\" ? fetch : undefined);\n\n if (!fetchImpl) {\n throw new ConfigurationError(\n \"Fetch API is not available; provide a fetch implementation in the configuration.\"\n );\n }\n\n const requestHeaders = new Headers();\n if (json) {\n requestHeaders.set(\"Accept\", \"application/json\");\n }\n\n Object.entries(headers).forEach(([key, value]) => {\n requestHeaders.set(key, value);\n });\n\n const timeoutMs = this.totalTimeoutMs();\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs && timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n try {\n const response = await fetchImpl(url.toString(), {\n method: \"GET\",\n headers: requestHeaders,\n redirect: \"manual\",\n signal: controller.signal,\n });\n\n if (response.status >= 400) {\n const body = await response.text().catch(() => \"\");\n throw new RequestError(\n `OG Pilot request failed with status ${response.status}: ${body}`,\n response.status\n );\n }\n\n return response;\n } catch (error) {\n if (error instanceof RequestError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new RequestError(`OG Pilot request timed out: ${error.message}`);\n }\n\n if (error instanceof Error) {\n throw new RequestError(`OG Pilot request failed: ${error.message}`);\n }\n\n throw new RequestError(\"OG Pilot request failed.\");\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async buildUrl(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Promise<URL> {\n const payload = this.buildPayload(params, iat);\n const token = await signJwt(payload, this.apiKey());\n const url = new URL(ENDPOINT_PATH, this.config.baseUrl);\n url.searchParams.set(\"token\", token);\n return url;\n }\n\n private buildPayload(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Record<string, unknown> {\n const payload: Record<string, unknown> = { ...params };\n\n if (iat !== undefined && iat !== null) {\n payload.iat = normalizeIat(iat);\n }\n\n if (payload.iss === undefined || payload.iss === null) {\n payload.iss = this.domain();\n }\n\n if (payload.sub === undefined || payload.sub === null) {\n payload.sub = this.apiKeyPrefix();\n }\n\n this.validatePayload(payload);\n return payload;\n }\n\n private validatePayload(payload: Record<string, unknown>): void {\n if (\n payload.iss === undefined ||\n payload.iss === null ||\n String(payload.iss).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (\n payload.sub === undefined ||\n payload.sub === null ||\n String(payload.sub).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (\n payload.title === undefined ||\n payload.title === null ||\n String(payload.title).length === 0\n ) {\n throw new Error(\"OG Pilot title is required\");\n }\n }\n\n private apiKey(): string {\n if (this.config.apiKey !== undefined && this.config.apiKey !== null) {\n return this.config.apiKey;\n }\n\n throw new ConfigurationError(\"OG Pilot API key is missing\");\n }\n\n private domain(): string {\n if (this.config.domain !== undefined && this.config.domain !== null) {\n return this.config.domain;\n }\n\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n private apiKeyPrefix(): string {\n return this.apiKey().slice(0, 8);\n }\n\n private totalTimeoutMs(): number | undefined {\n const openTimeoutMs = this.config.openTimeoutMs;\n const readTimeoutMs = this.config.readTimeoutMs;\n\n if (openTimeoutMs === undefined && readTimeoutMs === undefined) {\n return undefined;\n }\n\n const open = typeof openTimeoutMs === \"number\" ? openTimeoutMs : 0;\n const read = typeof readTimeoutMs === \"number\" ? readTimeoutMs : 0;\n return open + read;\n }\n}\n\nfunction normalizeIat(iat: number | Date): number {\n if (iat instanceof Date) {\n return Math.floor(iat.getTime() / 1000);\n }\n\n if (iat > 100000000000) {\n return Math.floor(iat / 1000);\n }\n\n return Math.floor(iat);\n}\n","import { Client } from \"./client\";\nimport { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, OgPilotError, RequestError } from \"./errors\";\nimport {\n clearCurrentRequest,\n setCurrentRequest,\n withRequestContext,\n} from \"./request-context\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (\n updater: (config: Configuration) => void\n): Configuration => {\n updater(defaultConfig);\n return defaultConfig;\n};\n\nexport const resetConfig = (): void => {\n defaultConfig = new Configuration();\n};\n\nexport const getConfig = (): Configuration => defaultConfig;\n\nexport const client = (): Client => new Client(defaultConfig);\n\nexport const createImage = (\n params: Record<string, unknown> = {},\n options: Parameters<Client[\"createImage\"]>[1] = {}\n): ReturnType<Client[\"createImage\"]> => client().createImage(params, options);\n\nexport const createClient = (options: OgPilotConfigOptions = {}): Client =>\n new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n setCurrentRequest,\n clearCurrentRequest,\n withRequestContext,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError,\n};\n\nexport default OgPilot;\nexport type { CreateImageOptions } from \"./client\";\nexport {\n clearCurrentRequest,\n Client,\n Configuration,\n ConfigurationError,\n OgPilotConfigOptions,\n OgPilotError,\n RequestError,\n setCurrentRequest,\n withRequestContext,\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/jwt.ts","../src/request-context.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["export interface OgPilotConfigOptions {\n apiKey?: string;\n domain?: string;\n baseUrl?: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = \"https://ogpilot.com\";\n\nfunction readEnv(key: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[key];\n }\n\n return undefined;\n}\n\nexport class Configuration {\n apiKey?: string;\n domain?: string;\n baseUrl: string;\n openTimeoutMs?: number;\n readTimeoutMs?: number;\n fetch?: typeof fetch;\n\n constructor(options: OgPilotConfigOptions = {}) {\n this.apiKey = options.apiKey ?? readEnv(\"OG_PILOT_API_KEY\");\n this.domain = options.domain ?? readEnv(\"OG_PILOT_DOMAIN\");\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.openTimeoutMs = options.openTimeoutMs ?? 5000;\n this.readTimeoutMs = options.readTimeoutMs ?? 10000;\n this.fetch = options.fetch;\n }\n}\n","export class OgPilotError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OgPilotError\";\n }\n}\n\nexport class ConfigurationError extends OgPilotError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class RequestError extends OgPilotError {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"RequestError\";\n this.status = status;\n }\n}\n","const encoder = new TextEncoder();\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n\n if (typeof btoa === \"undefined\") {\n throw new Error(\"btoa is not available in this environment\");\n }\n\n return btoa(binary);\n}\n\nfunction base64UrlEncodeBytes(bytes: Uint8Array): string {\n return toBase64(bytes).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction base64UrlEncodeString(value: string): string {\n return base64UrlEncodeBytes(encoder.encode(value));\n}\n\nfunction getSubtleCrypto(): SubtleCrypto | null {\n if (typeof globalThis !== \"undefined\" && globalThis.crypto && globalThis.crypto.subtle) {\n return globalThis.crypto.subtle;\n }\n\n return null;\n}\n\nasync function hmacSha256(data: string, secret: string): Promise<Uint8Array> {\n const subtle = getSubtleCrypto();\n\n if (!subtle) {\n throw new Error(\"Web Crypto API is not available; requires a Node 18+ or Edge runtime.\");\n }\n\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await subtle.sign(\"HMAC\", key, encoder.encode(data));\n return new Uint8Array(signature);\n}\n\nexport async function signJwt(payload: Record<string, unknown>, secret: string): Promise<string> {\n const header = { alg: \"HS256\", typ: \"JWT\" };\n const encodedHeader = base64UrlEncodeString(JSON.stringify(header));\n const encodedPayload = base64UrlEncodeString(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = await hmacSha256(signingInput, secret);\n\n return `${signingInput}.${base64UrlEncodeBytes(signature)}`;\n}\n","/**\n * Request context for automatic path resolution.\n *\n * In Node.js environments, this uses AsyncLocalStorage to store the current\n * request URL per async execution context. In edge runtimes or browsers,\n * it falls back to a simple variable (not request-scoped).\n */\n\ntype RequestInfo = {\n url?: string;\n path?: string;\n};\n\ninterface AsyncStorage {\n getStore: () => RequestInfo | undefined;\n run: <T>(store: RequestInfo, callback: () => T) => T;\n}\n\n// Try to use AsyncLocalStorage if available (Node.js 12.17+)\nlet asyncLocalStorage: AsyncStorage | null = null;\n\n// Fallback for environments without AsyncLocalStorage\nlet fallbackRequest: RequestInfo | undefined;\n\n// Create a fallback implementation\nfunction createFallbackStorage(): AsyncStorage {\n return {\n getStore: () => fallbackRequest,\n run: <T>(_store: RequestInfo, callback: () => T): T => {\n const prev = fallbackRequest;\n fallbackRequest = _store;\n try {\n return callback();\n } finally {\n fallbackRequest = prev;\n }\n },\n };\n}\n\n// Lazy initialization to avoid issues in environments where async_hooks isn't available\nfunction getAsyncLocalStorage(): AsyncStorage {\n if (asyncLocalStorage === null) {\n try {\n // Dynamic import to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { AsyncLocalStorage } = require(\"async_hooks\");\n const storage = new AsyncLocalStorage();\n asyncLocalStorage = {\n getStore: () => storage.getStore() as RequestInfo | undefined,\n run: <T>(store: RequestInfo, callback: () => T): T =>\n storage.run(store, callback),\n };\n } catch {\n // AsyncLocalStorage not available, use fallback\n asyncLocalStorage = createFallbackStorage();\n }\n }\n return asyncLocalStorage!;\n}\n\n/**\n * Sets the current request context for automatic path resolution.\n * Call this in your middleware/handler before using OG Pilot.\n *\n * @example Express middleware\n * ```ts\n * app.use((req, res, next) => {\n * setCurrentRequest({ url: req.originalUrl });\n * next();\n * });\n * ```\n *\n * @example Next.js middleware\n * ```ts\n * export function middleware(request: NextRequest) {\n * setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });\n * return NextResponse.next();\n * }\n * ```\n */\nexport function setCurrentRequest(request: RequestInfo): void {\n fallbackRequest = request;\n}\n\n/**\n * Clears the current request context.\n * Call this after the request is complete if using setCurrentRequest directly.\n */\nexport function clearCurrentRequest(): void {\n fallbackRequest = undefined;\n}\n\n/**\n * Runs a callback with the given request context.\n * The context is automatically cleared after the callback completes.\n * This is the preferred method for setting request context.\n *\n * @example Express middleware\n * ```ts\n * import { withRequestContext } from \"og-pilot-js\";\n *\n * app.use((req, res, next) => {\n * withRequestContext({ url: req.originalUrl }, () => {\n * next();\n * });\n * });\n * ```\n */\nexport function withRequestContext<T>(\n request: RequestInfo,\n callback: () => T\n): T {\n return getAsyncLocalStorage().run(request, callback);\n}\n\n/**\n * Gets the current request info from context.\n * @internal\n */\nexport function getCurrentRequest(): RequestInfo | undefined {\n // Try AsyncLocalStorage first, then fallback\n const store = getAsyncLocalStorage().getStore();\n return store ?? fallbackRequest;\n}\n\n/**\n * Gets the current request path from context or environment.\n * @internal\n */\nexport function getCurrentPath(): string | undefined {\n const request = getCurrentRequest();\n\n if (request?.path) {\n return request.path;\n }\n\n if (request?.url) {\n return extractPathFromUrl(request.url);\n }\n\n // Fallback to environment variables (similar to Ruby's env_fullpath)\n return getPathFromEnv();\n}\n\n// ============================================================================\n// Framework-specific helpers\n// ============================================================================\n\nexport type NextParamValue = string | string[] | undefined;\nexport type NextParams = Record<string, NextParamValue>;\nexport type NextSearchParams = Record<string, NextParamValue>;\nexport type NextMetadataProps = {\n params: NextParams | Promise<NextParams>;\n searchParams?: NextSearchParams | Promise<NextSearchParams>;\n};\n\n/**\n * Builds a URL path for Next.js App Router routes.\n *\n * Pass your route pattern (e.g. \"/products/[id]\") and Next.js params/searchParams.\n * This avoids middleware and fits naturally inside generateMetadata().\n *\n * @example app/products/[id]/page.tsx\n * ```ts\n * import { buildPathFromNextProps } from \"og-pilot-js\";\n *\n * export async function generateMetadata(props) {\n * const path = await buildPathFromNextProps(\"/products/[id]\", props);\n * // => \"/products/123?ref=twitter\"\n * }\n * ```\n */\nexport async function buildPathFromNextProps(\n routePattern: string,\n props: NextMetadataProps\n): Promise<string> {\n const params = await props.params;\n const searchParams = props.searchParams\n ? await props.searchParams\n : undefined;\n return buildPathFromNextParams(routePattern, params, searchParams);\n}\n\n/**\n * Builds a URL path for Next.js App Router routes from params/searchParams.\n *\n * @example\n * ```ts\n * const path = buildPathFromNextParams(\n * \"/blog/[...slug]\",\n * { slug: [\"2024\", \"launch\"] },\n * { ref: \"twitter\" }\n * );\n * // => \"/blog/2024/launch?ref=twitter\"\n * ```\n */\nexport function buildPathFromNextParams(\n routePattern: string,\n params: NextParams,\n searchParams?: NextSearchParams\n): string {\n const segments = routePattern\n .split(\"/\")\n .filter((segment) => segment.length > 0);\n const builtSegments: string[] = [];\n\n for (const segment of segments) {\n const catchAllMatch = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n const optionalCatchAllMatch = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n const paramMatch = segment.match(/^\\[(.+)\\]$/);\n\n if (optionalCatchAllMatch) {\n const key = optionalCatchAllMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(...value);\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n if (catchAllMatch) {\n const key = catchAllMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(...value);\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n if (paramMatch) {\n const key = paramMatch[1];\n const value = params[key];\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n builtSegments.push(value.join(\"/\"));\n } else {\n builtSegments.push(value);\n }\n continue;\n }\n\n builtSegments.push(segment);\n }\n\n const path = `/${builtSegments.join(\"/\")}`;\n const query = serializeSearchParams(searchParams);\n return query.length > 0 ? `${path}?${query}` : path;\n}\n\n/**\n * Creates an Express/Connect middleware that automatically sets request context.\n *\n * @example Express\n * ```ts\n * import express from \"express\";\n * import { createExpressMiddleware } from \"og-pilot-js\";\n *\n * const app = express();\n * app.use(createExpressMiddleware());\n * ```\n */\nexport function createExpressMiddleware(): ExpressMiddleware {\n return (req, _res, next) => {\n setCurrentRequest({\n url: req.originalUrl || req.url,\n path: req.originalUrl || req.url,\n });\n next();\n };\n}\n\n/**\n * Helper to extract path from an Express/Node.js request object.\n */\nexport function getPathFromExpressRequest(req: ExpressRequest): string {\n return req.originalUrl || req.url || \"/\";\n}\n\n// Type definitions for framework compatibility\n// These are minimal to avoid requiring framework dependencies\n\ninterface ExpressRequest {\n originalUrl?: string;\n url?: string;\n}\n\ntype ExpressMiddleware = (\n req: ExpressRequest,\n res: unknown,\n next: () => void\n) => void;\n\nfunction extractPathFromUrl(url: string): string {\n // Handle full URLs\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n try {\n const parsed = new URL(url);\n return parsed.pathname + parsed.search;\n } catch {\n return url;\n }\n }\n\n return url;\n}\n\nfunction serializeSearchParams(\n searchParams?: NextSearchParams | URLSearchParams\n): string {\n if (!searchParams) {\n return \"\";\n }\n\n if (searchParams instanceof URLSearchParams) {\n return searchParams.toString();\n }\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n params.append(key, entry);\n }\n } else {\n params.append(key, value);\n }\n }\n\n return params.toString();\n}\n\nfunction getPathFromEnv(): string | undefined {\n if (typeof process === \"undefined\" || !process.env) {\n return undefined;\n }\n\n const env = process.env;\n\n // Check various environment variables (similar to Ruby implementation)\n const requestUri = env.REQUEST_URI;\n if (requestUri && requestUri.length > 0) {\n return requestUri;\n }\n\n const originalFullpath = env.ORIGINAL_FULLPATH;\n if (originalFullpath && originalFullpath.length > 0) {\n return originalFullpath;\n }\n\n const pathInfo = env.PATH_INFO;\n if (pathInfo && pathInfo.length > 0) {\n const queryString = env.QUERY_STRING ?? \"\";\n return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;\n }\n\n const requestPath = env.REQUEST_PATH;\n if (requestPath && requestPath.length > 0) {\n return requestPath;\n }\n\n return undefined;\n}\n","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\nimport { getCurrentPath } from \"./request-context\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\n /**\n * When true, forces the path to \"/\" regardless of the current request.\n * Useful for generating default/fallback OG images.\n */\n default?: boolean;\n}\n\nconst ENDPOINT_PATH = \"/api/v1/images\";\n\nexport class Client {\n private config: Configuration;\n\n constructor(config: Configuration | OgPilotConfigOptions = {}) {\n this.config =\n config instanceof Configuration ? config : new Configuration(config);\n }\n\n async createImage(\n params: Record<string, unknown> = {},\n options: CreateImageOptions = {}\n ): Promise<unknown> {\n const {\n json = false,\n iat,\n headers = {},\n default: useDefault = false,\n } = options;\n\n // Always include a path; manual overrides win, otherwise resolve from the current request.\n const resolvedParams = { ...params };\n const manualPath = resolvedParams.path;\n delete resolvedParams.path;\n resolvedParams.path = this.resolvePath(manualPath, useDefault);\n\n const url = await this.buildUrl(resolvedParams, iat);\n const response = await this.request(url, json, headers);\n\n if (json) {\n const body = await response.text();\n return JSON.parse(body);\n }\n\n return response.headers.get(\"location\") ?? response.url ?? url.toString();\n }\n\n /**\n * Resolves the path parameter for the request.\n * Priority: manual path > current request path > \"/\"\n */\n private resolvePath(manualPath: unknown, useDefault: boolean): string {\n // Manual path always wins if provided\n if (manualPath !== undefined && manualPath !== null) {\n const pathStr = String(manualPath).trim();\n if (pathStr.length > 0) {\n return this.normalizePath(pathStr);\n }\n }\n\n // If default is true, return \"/\"\n if (useDefault) {\n return \"/\";\n }\n\n // Try to get path from current request context\n const currentPath = getCurrentPath();\n return this.normalizePath(currentPath);\n }\n\n /**\n * Normalizes a path to ensure it starts with \"/\" and handles full URLs.\n */\n private normalizePath(path: string | undefined | null): string {\n if (path === undefined || path === null) {\n return \"/\";\n }\n\n let cleaned = String(path).trim();\n if (cleaned.length === 0) {\n return \"/\";\n }\n\n // Extract path from full URLs\n if (cleaned.startsWith(\"http://\") || cleaned.startsWith(\"https://\")) {\n try {\n const url = new URL(cleaned);\n cleaned = url.pathname + url.search;\n } catch {\n // Keep as-is if URL parsing fails\n }\n }\n\n // Ensure path starts with \"/\"\n if (!cleaned.startsWith(\"/\")) {\n cleaned = \"/\" + cleaned;\n }\n\n return cleaned;\n }\n\n private async request(\n url: URL,\n json: boolean,\n headers: Record<string, string>\n ): Promise<Response> {\n const fetchImpl =\n this.config.fetch ?? (typeof fetch !== \"undefined\" ? fetch : undefined);\n\n if (!fetchImpl) {\n throw new ConfigurationError(\n \"Fetch API is not available; provide a fetch implementation in the configuration.\"\n );\n }\n\n const requestHeaders = new Headers();\n if (json) {\n requestHeaders.set(\"Accept\", \"application/json\");\n }\n\n Object.entries(headers).forEach(([key, value]) => {\n requestHeaders.set(key, value);\n });\n\n const timeoutMs = this.totalTimeoutMs();\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs && timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n try {\n const response = await fetchImpl(url.toString(), {\n method: \"GET\",\n headers: requestHeaders,\n redirect: \"manual\",\n signal: controller.signal,\n });\n\n if (response.status >= 400) {\n const body = await response.text().catch(() => \"\");\n throw new RequestError(\n `OG Pilot request failed with status ${response.status}: ${body}`,\n response.status\n );\n }\n\n return response;\n } catch (error) {\n if (error instanceof RequestError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new RequestError(`OG Pilot request timed out: ${error.message}`);\n }\n\n if (error instanceof Error) {\n throw new RequestError(`OG Pilot request failed: ${error.message}`);\n }\n\n throw new RequestError(\"OG Pilot request failed.\");\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async buildUrl(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Promise<URL> {\n const payload = this.buildPayload(params, iat);\n const token = await signJwt(payload, this.apiKey());\n const url = new URL(ENDPOINT_PATH, this.config.baseUrl);\n url.searchParams.set(\"token\", token);\n return url;\n }\n\n private buildPayload(\n params: Record<string, unknown>,\n iat?: number | Date\n ): Record<string, unknown> {\n const payload: Record<string, unknown> = { ...params };\n\n if (iat !== undefined && iat !== null) {\n payload.iat = normalizeIat(iat);\n }\n\n if (payload.iss === undefined || payload.iss === null) {\n payload.iss = this.domain();\n }\n\n if (payload.sub === undefined || payload.sub === null) {\n payload.sub = this.apiKeyPrefix();\n }\n\n this.validatePayload(payload);\n return payload;\n }\n\n private validatePayload(payload: Record<string, unknown>): void {\n if (\n payload.iss === undefined ||\n payload.iss === null ||\n String(payload.iss).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (\n payload.sub === undefined ||\n payload.sub === null ||\n String(payload.sub).length === 0\n ) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (\n payload.title === undefined ||\n payload.title === null ||\n String(payload.title).length === 0\n ) {\n throw new Error(\"OG Pilot title is required\");\n }\n }\n\n private apiKey(): string {\n if (this.config.apiKey !== undefined && this.config.apiKey !== null) {\n return this.config.apiKey;\n }\n\n throw new ConfigurationError(\"OG Pilot API key is missing\");\n }\n\n private domain(): string {\n if (this.config.domain !== undefined && this.config.domain !== null) {\n return this.config.domain;\n }\n\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n private apiKeyPrefix(): string {\n return this.apiKey().slice(0, 8);\n }\n\n private totalTimeoutMs(): number | undefined {\n const openTimeoutMs = this.config.openTimeoutMs;\n const readTimeoutMs = this.config.readTimeoutMs;\n\n if (openTimeoutMs === undefined && readTimeoutMs === undefined) {\n return undefined;\n }\n\n const open = typeof openTimeoutMs === \"number\" ? openTimeoutMs : 0;\n const read = typeof readTimeoutMs === \"number\" ? readTimeoutMs : 0;\n return open + read;\n }\n}\n\nfunction normalizeIat(iat: number | Date): number {\n if (iat instanceof Date) {\n return Math.floor(iat.getTime() / 1000);\n }\n\n if (iat > 100000000000) {\n return Math.floor(iat / 1000);\n }\n\n return Math.floor(iat);\n}\n","import { Client } from \"./client\";\nimport { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, OgPilotError, RequestError } from \"./errors\";\nimport {\n buildPathFromNextParams,\n buildPathFromNextProps,\n clearCurrentRequest,\n createExpressMiddleware,\n getPathFromExpressRequest,\n setCurrentRequest,\n withRequestContext,\n} from \"./request-context\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (\n updater: (config: Configuration) => void\n): Configuration => {\n updater(defaultConfig);\n return defaultConfig;\n};\n\nexport const resetConfig = (): void => {\n defaultConfig = new Configuration();\n};\n\nexport const getConfig = (): Configuration => defaultConfig;\n\nexport const client = (): Client => new Client(defaultConfig);\n\nexport const createImage = (\n params: Record<string, unknown> = {},\n options: Parameters<Client[\"createImage\"]>[1] = {}\n): ReturnType<Client[\"createImage\"]> => client().createImage(params, options);\n\nexport const createClient = (options: OgPilotConfigOptions = {}): Client =>\n new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n setCurrentRequest,\n clearCurrentRequest,\n withRequestContext,\n createExpressMiddleware,\n getPathFromExpressRequest,\n buildPathFromNextProps,\n buildPathFromNextParams,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError,\n};\n\nexport default OgPilot;\nexport type { CreateImageOptions } from \"./client\";\nexport type {\n NextMetadataProps,\n NextParams,\n NextSearchParams,\n} from \"./request-context\";\nexport {\n buildPathFromNextParams,\n buildPathFromNextProps,\n clearCurrentRequest,\n Client,\n Configuration,\n ConfigurationError,\n createExpressMiddleware,\n getPathFromExpressRequest,\n OgPilotConfigOptions,\n OgPilotError,\n RequestError,\n setCurrentRequest,\n withRequestContext,\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "og-pilot-js",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "JavaScript/TypeScript client for the OG Pilot Open Graph image generator.",
5
5
  "license": "MIT",
6
6
  "author": "Sunergos IT LLC",