og-pilot-js 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -0
- package/dist/index.cjs +153 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +156 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,114 @@ If you omit `iat`, OG Pilot will cache the image indefinitely. Provide an `iat`
|
|
|
49
49
|
to refresh the cache daily. You can pass a `Date`, epoch seconds, or epoch
|
|
50
50
|
milliseconds (`Date.now()` is auto-converted).
|
|
51
51
|
|
|
52
|
+
## Parameters
|
|
53
|
+
|
|
54
|
+
All parameters are embedded in the signed JWT payload; the only query param is `token`.
|
|
55
|
+
The library handles `iss` (domain) and `sub` (API key prefix) automatically.
|
|
56
|
+
|
|
57
|
+
### Core parameters
|
|
58
|
+
|
|
59
|
+
| Parameter | Required | Default | Description |
|
|
60
|
+
|---------------|----------|----------|---------------------------------------------------------------|
|
|
61
|
+
| `template` | No | `"page"` | Template name |
|
|
62
|
+
| `title` | Yes | — | Primary title text |
|
|
63
|
+
| `description` | No | — | Subtitle or supporting text |
|
|
64
|
+
| `logo_url` | No | — | Logo image URL |
|
|
65
|
+
| `image_url` | No | — | Hero image URL |
|
|
66
|
+
| `bg_color` | No | — | Background color (hex format) |
|
|
67
|
+
| `text_color` | No | — | Text color (hex format) |
|
|
68
|
+
| `iat` | No | — | Issued-at timestamp for daily cache busting |
|
|
69
|
+
| `path` | No | auto-set | Request path for image rendering context (see [Path handling](#path-handling)) |
|
|
70
|
+
|
|
71
|
+
### Options
|
|
72
|
+
|
|
73
|
+
| Option | Default | Description |
|
|
74
|
+
|-----------|---------|--------------------------------------------------------------------------|
|
|
75
|
+
| `json` | `false` | When `true`, sends `Accept: application/json` and parses the JSON response |
|
|
76
|
+
| `headers` | — | Additional HTTP headers to include with the request |
|
|
77
|
+
| `default` | `false` | Forces `path` to `/` when `true`, unless a manual `path` is provided |
|
|
78
|
+
|
|
79
|
+
## Path handling
|
|
80
|
+
|
|
81
|
+
The `path` parameter enhances OG Pilot analytics by tracking which OG images perform better across different pages on your site. By capturing the request path, you get granular insights into click-through rates and engagement for each OG image.
|
|
82
|
+
|
|
83
|
+
The client automatically injects a `path` parameter on every request:
|
|
84
|
+
|
|
85
|
+
| Option | Behavior |
|
|
86
|
+
|------------------|---------------------------------------------------------------------------------------------------------|
|
|
87
|
+
| `default: false` | Uses the current request path when available (via request context), then falls back to env vars, then `/` |
|
|
88
|
+
| `default: true` | Forces the `path` parameter to `/`, regardless of the current request (unless `path` is provided explicitly) |
|
|
89
|
+
| `path: "/..."` | Uses the provided path verbatim (normalized to start with `/`), overriding auto-resolution |
|
|
90
|
+
|
|
91
|
+
### Setting up request context
|
|
92
|
+
|
|
93
|
+
To enable automatic path resolution, set the current request context in your middleware:
|
|
94
|
+
|
|
95
|
+
**Express:**
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { setCurrentRequest, clearCurrentRequest } from "og-pilot-js";
|
|
99
|
+
|
|
100
|
+
app.use((req, res, next) => {
|
|
101
|
+
setCurrentRequest({ url: req.originalUrl });
|
|
102
|
+
res.on("finish", () => clearCurrentRequest());
|
|
103
|
+
next();
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Next.js App Router (middleware.ts):**
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { setCurrentRequest } from "og-pilot-js";
|
|
111
|
+
import { NextResponse } from "next/server";
|
|
112
|
+
import type { NextRequest } from "next/server";
|
|
113
|
+
|
|
114
|
+
export function middleware(request: NextRequest) {
|
|
115
|
+
setCurrentRequest({
|
|
116
|
+
url: request.nextUrl.pathname + request.nextUrl.search
|
|
117
|
+
});
|
|
118
|
+
return NextResponse.next();
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Using withRequestContext (preferred for async safety):**
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { withRequestContext, createImage } from "og-pilot-js";
|
|
126
|
+
|
|
127
|
+
// In your request handler
|
|
128
|
+
await withRequestContext({ url: req.originalUrl }, async () => {
|
|
129
|
+
const imageUrl = await createImage({
|
|
130
|
+
template: "blog_post",
|
|
131
|
+
title: "My Blog Post"
|
|
132
|
+
});
|
|
133
|
+
// path is automatically set to req.originalUrl
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Manual path override
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const imageUrl = await createImage({
|
|
141
|
+
template: "page",
|
|
142
|
+
title: "Hello OG Pilot",
|
|
143
|
+
path: "/pricing?plan=pro"
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Default path
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const imageUrl = await createImage(
|
|
151
|
+
{
|
|
152
|
+
template: "blog_post",
|
|
153
|
+
title: "Default OG Image"
|
|
154
|
+
},
|
|
155
|
+
{ default: true }
|
|
156
|
+
);
|
|
157
|
+
// path is set to "/"
|
|
158
|
+
```
|
|
159
|
+
|
|
52
160
|
Fetch JSON metadata instead:
|
|
53
161
|
|
|
54
162
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -25,13 +25,16 @@ __export(index_exports, {
|
|
|
25
25
|
ConfigurationError: () => ConfigurationError,
|
|
26
26
|
OgPilotError: () => OgPilotError,
|
|
27
27
|
RequestError: () => RequestError,
|
|
28
|
+
clearCurrentRequest: () => clearCurrentRequest,
|
|
28
29
|
client: () => client,
|
|
29
30
|
configure: () => configure,
|
|
30
31
|
createClient: () => createClient,
|
|
31
32
|
createImage: () => createImage,
|
|
32
33
|
default: () => index_default,
|
|
33
34
|
getConfig: () => getConfig,
|
|
34
|
-
resetConfig: () => resetConfig
|
|
35
|
+
resetConfig: () => resetConfig,
|
|
36
|
+
setCurrentRequest: () => setCurrentRequest,
|
|
37
|
+
withRequestContext: () => withRequestContext
|
|
35
38
|
});
|
|
36
39
|
module.exports = __toCommonJS(index_exports);
|
|
37
40
|
|
|
@@ -126,6 +129,97 @@ async function signJwt(payload, secret) {
|
|
|
126
129
|
return `${signingInput}.${base64UrlEncodeBytes(signature)}`;
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
// src/request-context.ts
|
|
133
|
+
var asyncLocalStorage = null;
|
|
134
|
+
var fallbackRequest;
|
|
135
|
+
function createFallbackStorage() {
|
|
136
|
+
return {
|
|
137
|
+
getStore: () => fallbackRequest,
|
|
138
|
+
run: (_store, callback) => {
|
|
139
|
+
const prev = fallbackRequest;
|
|
140
|
+
fallbackRequest = _store;
|
|
141
|
+
try {
|
|
142
|
+
return callback();
|
|
143
|
+
} finally {
|
|
144
|
+
fallbackRequest = prev;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function getAsyncLocalStorage() {
|
|
150
|
+
if (asyncLocalStorage === null) {
|
|
151
|
+
try {
|
|
152
|
+
const { AsyncLocalStorage } = require("async_hooks");
|
|
153
|
+
const storage = new AsyncLocalStorage();
|
|
154
|
+
asyncLocalStorage = {
|
|
155
|
+
getStore: () => storage.getStore(),
|
|
156
|
+
run: (store, callback) => storage.run(store, callback)
|
|
157
|
+
};
|
|
158
|
+
} catch {
|
|
159
|
+
asyncLocalStorage = createFallbackStorage();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return asyncLocalStorage;
|
|
163
|
+
}
|
|
164
|
+
function setCurrentRequest(request) {
|
|
165
|
+
fallbackRequest = request;
|
|
166
|
+
}
|
|
167
|
+
function clearCurrentRequest() {
|
|
168
|
+
fallbackRequest = void 0;
|
|
169
|
+
}
|
|
170
|
+
function withRequestContext(request, callback) {
|
|
171
|
+
return getAsyncLocalStorage().run(request, callback);
|
|
172
|
+
}
|
|
173
|
+
function getCurrentRequest() {
|
|
174
|
+
const store = getAsyncLocalStorage().getStore();
|
|
175
|
+
return store ?? fallbackRequest;
|
|
176
|
+
}
|
|
177
|
+
function getCurrentPath() {
|
|
178
|
+
const request = getCurrentRequest();
|
|
179
|
+
if (request?.path) {
|
|
180
|
+
return request.path;
|
|
181
|
+
}
|
|
182
|
+
if (request?.url) {
|
|
183
|
+
return extractPathFromUrl(request.url);
|
|
184
|
+
}
|
|
185
|
+
return getPathFromEnv();
|
|
186
|
+
}
|
|
187
|
+
function extractPathFromUrl(url) {
|
|
188
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
189
|
+
try {
|
|
190
|
+
const parsed = new URL(url);
|
|
191
|
+
return parsed.pathname + parsed.search;
|
|
192
|
+
} catch {
|
|
193
|
+
return url;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return url;
|
|
197
|
+
}
|
|
198
|
+
function getPathFromEnv() {
|
|
199
|
+
if (typeof process === "undefined" || !process.env) {
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
202
|
+
const env = process.env;
|
|
203
|
+
const requestUri = env.REQUEST_URI;
|
|
204
|
+
if (requestUri && requestUri.length > 0) {
|
|
205
|
+
return requestUri;
|
|
206
|
+
}
|
|
207
|
+
const originalFullpath = env.ORIGINAL_FULLPATH;
|
|
208
|
+
if (originalFullpath && originalFullpath.length > 0) {
|
|
209
|
+
return originalFullpath;
|
|
210
|
+
}
|
|
211
|
+
const pathInfo = env.PATH_INFO;
|
|
212
|
+
if (pathInfo && pathInfo.length > 0) {
|
|
213
|
+
const queryString = env.QUERY_STRING ?? "";
|
|
214
|
+
return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;
|
|
215
|
+
}
|
|
216
|
+
const requestPath = env.REQUEST_PATH;
|
|
217
|
+
if (requestPath && requestPath.length > 0) {
|
|
218
|
+
return requestPath;
|
|
219
|
+
}
|
|
220
|
+
return void 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
129
223
|
// src/client.ts
|
|
130
224
|
var ENDPOINT_PATH = "/api/v1/images";
|
|
131
225
|
var Client = class {
|
|
@@ -133,8 +227,17 @@ var Client = class {
|
|
|
133
227
|
this.config = config instanceof Configuration ? config : new Configuration(config);
|
|
134
228
|
}
|
|
135
229
|
async createImage(params = {}, options = {}) {
|
|
136
|
-
const {
|
|
137
|
-
|
|
230
|
+
const {
|
|
231
|
+
json = false,
|
|
232
|
+
iat,
|
|
233
|
+
headers = {},
|
|
234
|
+
default: useDefault = false
|
|
235
|
+
} = options;
|
|
236
|
+
const resolvedParams = { ...params };
|
|
237
|
+
const manualPath = resolvedParams.path;
|
|
238
|
+
delete resolvedParams.path;
|
|
239
|
+
resolvedParams.path = this.resolvePath(manualPath, useDefault);
|
|
240
|
+
const url = await this.buildUrl(resolvedParams, iat);
|
|
138
241
|
const response = await this.request(url, json, headers);
|
|
139
242
|
if (json) {
|
|
140
243
|
const body = await response.text();
|
|
@@ -142,6 +245,46 @@ var Client = class {
|
|
|
142
245
|
}
|
|
143
246
|
return response.headers.get("location") ?? response.url ?? url.toString();
|
|
144
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Resolves the path parameter for the request.
|
|
250
|
+
* Priority: manual path > current request path > "/"
|
|
251
|
+
*/
|
|
252
|
+
resolvePath(manualPath, useDefault) {
|
|
253
|
+
if (manualPath !== void 0 && manualPath !== null) {
|
|
254
|
+
const pathStr = String(manualPath).trim();
|
|
255
|
+
if (pathStr.length > 0) {
|
|
256
|
+
return this.normalizePath(pathStr);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (useDefault) {
|
|
260
|
+
return "/";
|
|
261
|
+
}
|
|
262
|
+
const currentPath = getCurrentPath();
|
|
263
|
+
return this.normalizePath(currentPath);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Normalizes a path to ensure it starts with "/" and handles full URLs.
|
|
267
|
+
*/
|
|
268
|
+
normalizePath(path) {
|
|
269
|
+
if (path === void 0 || path === null) {
|
|
270
|
+
return "/";
|
|
271
|
+
}
|
|
272
|
+
let cleaned = String(path).trim();
|
|
273
|
+
if (cleaned.length === 0) {
|
|
274
|
+
return "/";
|
|
275
|
+
}
|
|
276
|
+
if (cleaned.startsWith("http://") || cleaned.startsWith("https://")) {
|
|
277
|
+
try {
|
|
278
|
+
const url = new URL(cleaned);
|
|
279
|
+
cleaned = url.pathname + url.search;
|
|
280
|
+
} catch {
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (!cleaned.startsWith("/")) {
|
|
284
|
+
cleaned = "/" + cleaned;
|
|
285
|
+
}
|
|
286
|
+
return cleaned;
|
|
287
|
+
}
|
|
145
288
|
async request(url, json, headers) {
|
|
146
289
|
const fetchImpl = this.config.fetch ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
147
290
|
if (!fetchImpl) {
|
|
@@ -282,6 +425,9 @@ var OgPilot = {
|
|
|
282
425
|
client,
|
|
283
426
|
createClient,
|
|
284
427
|
createImage,
|
|
428
|
+
setCurrentRequest,
|
|
429
|
+
clearCurrentRequest,
|
|
430
|
+
withRequestContext,
|
|
285
431
|
Configuration,
|
|
286
432
|
ConfigurationError,
|
|
287
433
|
OgPilotError,
|
|
@@ -295,11 +441,14 @@ var index_default = OgPilot;
|
|
|
295
441
|
ConfigurationError,
|
|
296
442
|
OgPilotError,
|
|
297
443
|
RequestError,
|
|
444
|
+
clearCurrentRequest,
|
|
298
445
|
client,
|
|
299
446
|
configure,
|
|
300
447
|
createClient,
|
|
301
448
|
createImage,
|
|
302
449
|
getConfig,
|
|
303
|
-
resetConfig
|
|
450
|
+
resetConfig,
|
|
451
|
+
setCurrentRequest,
|
|
452
|
+
withRequestContext
|
|
304
453
|
});
|
|
305
454
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/errors.ts","../src/jwt.ts","../src/client.ts"],"sourcesContent":["import { Client } from \"./client\";\nimport { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, OgPilotError, RequestError } from \"./errors\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (updater: (config: Configuration) => void): 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 => new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError\n};\n\nexport default OgPilot;\nexport { Client, Configuration, OgPilotConfigOptions, ConfigurationError, OgPilotError, RequestError };\nexport type { CreateImageOptions } from \"./client\";\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","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\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 = 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 { json = false, iat, headers = {} } = options;\n const url = await this.buildUrl(params ?? {}, 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 private async request(url: URL, json: boolean, headers: Record<string, string>): Promise<Response> {\n const fetchImpl = 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(params: Record<string, unknown>, iat?: number | Date): 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(params: Record<string, unknown>, iat?: number | Date): 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 (payload.iss === undefined || payload.iss === null || String(payload.iss).length === 0) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (payload.sub === undefined || payload.sub === null || String(payload.sub).length === 0) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (payload.title === undefined || payload.title === null || String(payload.title).length === 0) {\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 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":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -20,11 +20,25 @@ interface CreateImageOptions {
|
|
|
20
20
|
json?: boolean;
|
|
21
21
|
iat?: number | Date;
|
|
22
22
|
headers?: Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* When true, forces the path to "/" regardless of the current request.
|
|
25
|
+
* Useful for generating default/fallback OG images.
|
|
26
|
+
*/
|
|
27
|
+
default?: boolean;
|
|
23
28
|
}
|
|
24
29
|
declare class Client {
|
|
25
30
|
private config;
|
|
26
31
|
constructor(config?: Configuration | OgPilotConfigOptions);
|
|
27
32
|
createImage(params?: Record<string, unknown>, options?: CreateImageOptions): Promise<unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the path parameter for the request.
|
|
35
|
+
* Priority: manual path > current request path > "/"
|
|
36
|
+
*/
|
|
37
|
+
private resolvePath;
|
|
38
|
+
/**
|
|
39
|
+
* Normalizes a path to ensure it starts with "/" and handles full URLs.
|
|
40
|
+
*/
|
|
41
|
+
private normalizePath;
|
|
28
42
|
private request;
|
|
29
43
|
private buildUrl;
|
|
30
44
|
private buildPayload;
|
|
@@ -46,6 +60,61 @@ declare class RequestError extends OgPilotError {
|
|
|
46
60
|
constructor(message: string, status?: number);
|
|
47
61
|
}
|
|
48
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Request context for automatic path resolution.
|
|
65
|
+
*
|
|
66
|
+
* In Node.js environments, this uses AsyncLocalStorage to store the current
|
|
67
|
+
* request URL per async execution context. In edge runtimes or browsers,
|
|
68
|
+
* it falls back to a simple variable (not request-scoped).
|
|
69
|
+
*/
|
|
70
|
+
type RequestInfo = {
|
|
71
|
+
url?: string;
|
|
72
|
+
path?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Sets the current request context for automatic path resolution.
|
|
76
|
+
* Call this in your middleware/handler before using OG Pilot.
|
|
77
|
+
*
|
|
78
|
+
* @example Express middleware
|
|
79
|
+
* ```ts
|
|
80
|
+
* app.use((req, res, next) => {
|
|
81
|
+
* setCurrentRequest({ url: req.originalUrl });
|
|
82
|
+
* next();
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example Next.js middleware
|
|
87
|
+
* ```ts
|
|
88
|
+
* export function middleware(request: NextRequest) {
|
|
89
|
+
* setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });
|
|
90
|
+
* return NextResponse.next();
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function setCurrentRequest(request: RequestInfo): void;
|
|
95
|
+
/**
|
|
96
|
+
* Clears the current request context.
|
|
97
|
+
* Call this after the request is complete if using setCurrentRequest directly.
|
|
98
|
+
*/
|
|
99
|
+
declare function clearCurrentRequest(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Runs a callback with the given request context.
|
|
102
|
+
* The context is automatically cleared after the callback completes.
|
|
103
|
+
* This is the preferred method for setting request context.
|
|
104
|
+
*
|
|
105
|
+
* @example Express middleware
|
|
106
|
+
* ```ts
|
|
107
|
+
* import { withRequestContext } from "og-pilot-js";
|
|
108
|
+
*
|
|
109
|
+
* app.use((req, res, next) => {
|
|
110
|
+
* withRequestContext({ url: req.originalUrl }, () => {
|
|
111
|
+
* next();
|
|
112
|
+
* });
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function withRequestContext<T>(request: RequestInfo, callback: () => T): T;
|
|
117
|
+
|
|
49
118
|
declare const configure: (updater: (config: Configuration) => void) => Configuration;
|
|
50
119
|
declare const resetConfig: () => void;
|
|
51
120
|
declare const getConfig: () => Configuration;
|
|
@@ -59,10 +128,13 @@ declare const OgPilot: {
|
|
|
59
128
|
client: () => Client;
|
|
60
129
|
createClient: (options?: OgPilotConfigOptions) => Client;
|
|
61
130
|
createImage: (params?: Record<string, unknown>, options?: Parameters<Client["createImage"]>[1]) => ReturnType<Client["createImage"]>;
|
|
131
|
+
setCurrentRequest: typeof setCurrentRequest;
|
|
132
|
+
clearCurrentRequest: typeof clearCurrentRequest;
|
|
133
|
+
withRequestContext: typeof withRequestContext;
|
|
62
134
|
Configuration: typeof Configuration;
|
|
63
135
|
ConfigurationError: typeof ConfigurationError;
|
|
64
136
|
OgPilotError: typeof OgPilotError;
|
|
65
137
|
RequestError: typeof RequestError;
|
|
66
138
|
};
|
|
67
139
|
|
|
68
|
-
export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig };
|
|
140
|
+
export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, clearCurrentRequest, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig, setCurrentRequest, withRequestContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -20,11 +20,25 @@ interface CreateImageOptions {
|
|
|
20
20
|
json?: boolean;
|
|
21
21
|
iat?: number | Date;
|
|
22
22
|
headers?: Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* When true, forces the path to "/" regardless of the current request.
|
|
25
|
+
* Useful for generating default/fallback OG images.
|
|
26
|
+
*/
|
|
27
|
+
default?: boolean;
|
|
23
28
|
}
|
|
24
29
|
declare class Client {
|
|
25
30
|
private config;
|
|
26
31
|
constructor(config?: Configuration | OgPilotConfigOptions);
|
|
27
32
|
createImage(params?: Record<string, unknown>, options?: CreateImageOptions): Promise<unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the path parameter for the request.
|
|
35
|
+
* Priority: manual path > current request path > "/"
|
|
36
|
+
*/
|
|
37
|
+
private resolvePath;
|
|
38
|
+
/**
|
|
39
|
+
* Normalizes a path to ensure it starts with "/" and handles full URLs.
|
|
40
|
+
*/
|
|
41
|
+
private normalizePath;
|
|
28
42
|
private request;
|
|
29
43
|
private buildUrl;
|
|
30
44
|
private buildPayload;
|
|
@@ -46,6 +60,61 @@ declare class RequestError extends OgPilotError {
|
|
|
46
60
|
constructor(message: string, status?: number);
|
|
47
61
|
}
|
|
48
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Request context for automatic path resolution.
|
|
65
|
+
*
|
|
66
|
+
* In Node.js environments, this uses AsyncLocalStorage to store the current
|
|
67
|
+
* request URL per async execution context. In edge runtimes or browsers,
|
|
68
|
+
* it falls back to a simple variable (not request-scoped).
|
|
69
|
+
*/
|
|
70
|
+
type RequestInfo = {
|
|
71
|
+
url?: string;
|
|
72
|
+
path?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Sets the current request context for automatic path resolution.
|
|
76
|
+
* Call this in your middleware/handler before using OG Pilot.
|
|
77
|
+
*
|
|
78
|
+
* @example Express middleware
|
|
79
|
+
* ```ts
|
|
80
|
+
* app.use((req, res, next) => {
|
|
81
|
+
* setCurrentRequest({ url: req.originalUrl });
|
|
82
|
+
* next();
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example Next.js middleware
|
|
87
|
+
* ```ts
|
|
88
|
+
* export function middleware(request: NextRequest) {
|
|
89
|
+
* setCurrentRequest({ url: request.nextUrl.pathname + request.nextUrl.search });
|
|
90
|
+
* return NextResponse.next();
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function setCurrentRequest(request: RequestInfo): void;
|
|
95
|
+
/**
|
|
96
|
+
* Clears the current request context.
|
|
97
|
+
* Call this after the request is complete if using setCurrentRequest directly.
|
|
98
|
+
*/
|
|
99
|
+
declare function clearCurrentRequest(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Runs a callback with the given request context.
|
|
102
|
+
* The context is automatically cleared after the callback completes.
|
|
103
|
+
* This is the preferred method for setting request context.
|
|
104
|
+
*
|
|
105
|
+
* @example Express middleware
|
|
106
|
+
* ```ts
|
|
107
|
+
* import { withRequestContext } from "og-pilot-js";
|
|
108
|
+
*
|
|
109
|
+
* app.use((req, res, next) => {
|
|
110
|
+
* withRequestContext({ url: req.originalUrl }, () => {
|
|
111
|
+
* next();
|
|
112
|
+
* });
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function withRequestContext<T>(request: RequestInfo, callback: () => T): T;
|
|
117
|
+
|
|
49
118
|
declare const configure: (updater: (config: Configuration) => void) => Configuration;
|
|
50
119
|
declare const resetConfig: () => void;
|
|
51
120
|
declare const getConfig: () => Configuration;
|
|
@@ -59,10 +128,13 @@ declare const OgPilot: {
|
|
|
59
128
|
client: () => Client;
|
|
60
129
|
createClient: (options?: OgPilotConfigOptions) => Client;
|
|
61
130
|
createImage: (params?: Record<string, unknown>, options?: Parameters<Client["createImage"]>[1]) => ReturnType<Client["createImage"]>;
|
|
131
|
+
setCurrentRequest: typeof setCurrentRequest;
|
|
132
|
+
clearCurrentRequest: typeof clearCurrentRequest;
|
|
133
|
+
withRequestContext: typeof withRequestContext;
|
|
62
134
|
Configuration: typeof Configuration;
|
|
63
135
|
ConfigurationError: typeof ConfigurationError;
|
|
64
136
|
OgPilotError: typeof OgPilotError;
|
|
65
137
|
RequestError: typeof RequestError;
|
|
66
138
|
};
|
|
67
139
|
|
|
68
|
-
export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig };
|
|
140
|
+
export { Client, Configuration, ConfigurationError, type CreateImageOptions, type OgPilotConfigOptions, OgPilotError, RequestError, clearCurrentRequest, client, configure, createClient, createImage, OgPilot as default, getConfig, resetConfig, setCurrentRequest, withRequestContext };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/config.ts
|
|
2
9
|
var DEFAULT_BASE_URL = "https://ogpilot.com";
|
|
3
10
|
function readEnv(key) {
|
|
@@ -89,6 +96,97 @@ async function signJwt(payload, secret) {
|
|
|
89
96
|
return `${signingInput}.${base64UrlEncodeBytes(signature)}`;
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
// src/request-context.ts
|
|
100
|
+
var asyncLocalStorage = null;
|
|
101
|
+
var fallbackRequest;
|
|
102
|
+
function createFallbackStorage() {
|
|
103
|
+
return {
|
|
104
|
+
getStore: () => fallbackRequest,
|
|
105
|
+
run: (_store, callback) => {
|
|
106
|
+
const prev = fallbackRequest;
|
|
107
|
+
fallbackRequest = _store;
|
|
108
|
+
try {
|
|
109
|
+
return callback();
|
|
110
|
+
} finally {
|
|
111
|
+
fallbackRequest = prev;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function getAsyncLocalStorage() {
|
|
117
|
+
if (asyncLocalStorage === null) {
|
|
118
|
+
try {
|
|
119
|
+
const { AsyncLocalStorage } = __require("async_hooks");
|
|
120
|
+
const storage = new AsyncLocalStorage();
|
|
121
|
+
asyncLocalStorage = {
|
|
122
|
+
getStore: () => storage.getStore(),
|
|
123
|
+
run: (store, callback) => storage.run(store, callback)
|
|
124
|
+
};
|
|
125
|
+
} catch {
|
|
126
|
+
asyncLocalStorage = createFallbackStorage();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return asyncLocalStorage;
|
|
130
|
+
}
|
|
131
|
+
function setCurrentRequest(request) {
|
|
132
|
+
fallbackRequest = request;
|
|
133
|
+
}
|
|
134
|
+
function clearCurrentRequest() {
|
|
135
|
+
fallbackRequest = void 0;
|
|
136
|
+
}
|
|
137
|
+
function withRequestContext(request, callback) {
|
|
138
|
+
return getAsyncLocalStorage().run(request, callback);
|
|
139
|
+
}
|
|
140
|
+
function getCurrentRequest() {
|
|
141
|
+
const store = getAsyncLocalStorage().getStore();
|
|
142
|
+
return store ?? fallbackRequest;
|
|
143
|
+
}
|
|
144
|
+
function getCurrentPath() {
|
|
145
|
+
const request = getCurrentRequest();
|
|
146
|
+
if (request?.path) {
|
|
147
|
+
return request.path;
|
|
148
|
+
}
|
|
149
|
+
if (request?.url) {
|
|
150
|
+
return extractPathFromUrl(request.url);
|
|
151
|
+
}
|
|
152
|
+
return getPathFromEnv();
|
|
153
|
+
}
|
|
154
|
+
function extractPathFromUrl(url) {
|
|
155
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
156
|
+
try {
|
|
157
|
+
const parsed = new URL(url);
|
|
158
|
+
return parsed.pathname + parsed.search;
|
|
159
|
+
} catch {
|
|
160
|
+
return url;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return url;
|
|
164
|
+
}
|
|
165
|
+
function getPathFromEnv() {
|
|
166
|
+
if (typeof process === "undefined" || !process.env) {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
const env = process.env;
|
|
170
|
+
const requestUri = env.REQUEST_URI;
|
|
171
|
+
if (requestUri && requestUri.length > 0) {
|
|
172
|
+
return requestUri;
|
|
173
|
+
}
|
|
174
|
+
const originalFullpath = env.ORIGINAL_FULLPATH;
|
|
175
|
+
if (originalFullpath && originalFullpath.length > 0) {
|
|
176
|
+
return originalFullpath;
|
|
177
|
+
}
|
|
178
|
+
const pathInfo = env.PATH_INFO;
|
|
179
|
+
if (pathInfo && pathInfo.length > 0) {
|
|
180
|
+
const queryString = env.QUERY_STRING ?? "";
|
|
181
|
+
return queryString.length > 0 ? `${pathInfo}?${queryString}` : pathInfo;
|
|
182
|
+
}
|
|
183
|
+
const requestPath = env.REQUEST_PATH;
|
|
184
|
+
if (requestPath && requestPath.length > 0) {
|
|
185
|
+
return requestPath;
|
|
186
|
+
}
|
|
187
|
+
return void 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
92
190
|
// src/client.ts
|
|
93
191
|
var ENDPOINT_PATH = "/api/v1/images";
|
|
94
192
|
var Client = class {
|
|
@@ -96,8 +194,17 @@ var Client = class {
|
|
|
96
194
|
this.config = config instanceof Configuration ? config : new Configuration(config);
|
|
97
195
|
}
|
|
98
196
|
async createImage(params = {}, options = {}) {
|
|
99
|
-
const {
|
|
100
|
-
|
|
197
|
+
const {
|
|
198
|
+
json = false,
|
|
199
|
+
iat,
|
|
200
|
+
headers = {},
|
|
201
|
+
default: useDefault = false
|
|
202
|
+
} = options;
|
|
203
|
+
const resolvedParams = { ...params };
|
|
204
|
+
const manualPath = resolvedParams.path;
|
|
205
|
+
delete resolvedParams.path;
|
|
206
|
+
resolvedParams.path = this.resolvePath(manualPath, useDefault);
|
|
207
|
+
const url = await this.buildUrl(resolvedParams, iat);
|
|
101
208
|
const response = await this.request(url, json, headers);
|
|
102
209
|
if (json) {
|
|
103
210
|
const body = await response.text();
|
|
@@ -105,6 +212,46 @@ var Client = class {
|
|
|
105
212
|
}
|
|
106
213
|
return response.headers.get("location") ?? response.url ?? url.toString();
|
|
107
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Resolves the path parameter for the request.
|
|
217
|
+
* Priority: manual path > current request path > "/"
|
|
218
|
+
*/
|
|
219
|
+
resolvePath(manualPath, useDefault) {
|
|
220
|
+
if (manualPath !== void 0 && manualPath !== null) {
|
|
221
|
+
const pathStr = String(manualPath).trim();
|
|
222
|
+
if (pathStr.length > 0) {
|
|
223
|
+
return this.normalizePath(pathStr);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (useDefault) {
|
|
227
|
+
return "/";
|
|
228
|
+
}
|
|
229
|
+
const currentPath = getCurrentPath();
|
|
230
|
+
return this.normalizePath(currentPath);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Normalizes a path to ensure it starts with "/" and handles full URLs.
|
|
234
|
+
*/
|
|
235
|
+
normalizePath(path) {
|
|
236
|
+
if (path === void 0 || path === null) {
|
|
237
|
+
return "/";
|
|
238
|
+
}
|
|
239
|
+
let cleaned = String(path).trim();
|
|
240
|
+
if (cleaned.length === 0) {
|
|
241
|
+
return "/";
|
|
242
|
+
}
|
|
243
|
+
if (cleaned.startsWith("http://") || cleaned.startsWith("https://")) {
|
|
244
|
+
try {
|
|
245
|
+
const url = new URL(cleaned);
|
|
246
|
+
cleaned = url.pathname + url.search;
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (!cleaned.startsWith("/")) {
|
|
251
|
+
cleaned = "/" + cleaned;
|
|
252
|
+
}
|
|
253
|
+
return cleaned;
|
|
254
|
+
}
|
|
108
255
|
async request(url, json, headers) {
|
|
109
256
|
const fetchImpl = this.config.fetch ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
110
257
|
if (!fetchImpl) {
|
|
@@ -245,6 +392,9 @@ var OgPilot = {
|
|
|
245
392
|
client,
|
|
246
393
|
createClient,
|
|
247
394
|
createImage,
|
|
395
|
+
setCurrentRequest,
|
|
396
|
+
clearCurrentRequest,
|
|
397
|
+
withRequestContext,
|
|
248
398
|
Configuration,
|
|
249
399
|
ConfigurationError,
|
|
250
400
|
OgPilotError,
|
|
@@ -257,12 +407,15 @@ export {
|
|
|
257
407
|
ConfigurationError,
|
|
258
408
|
OgPilotError,
|
|
259
409
|
RequestError,
|
|
410
|
+
clearCurrentRequest,
|
|
260
411
|
client,
|
|
261
412
|
configure,
|
|
262
413
|
createClient,
|
|
263
414
|
createImage,
|
|
264
415
|
index_default as default,
|
|
265
416
|
getConfig,
|
|
266
|
-
resetConfig
|
|
417
|
+
resetConfig,
|
|
418
|
+
setCurrentRequest,
|
|
419
|
+
withRequestContext
|
|
267
420
|
};
|
|
268
421
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/jwt.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","import { Configuration, OgPilotConfigOptions } from \"./config\";\nimport { ConfigurationError, RequestError } from \"./errors\";\nimport { signJwt } from \"./jwt\";\n\nexport interface CreateImageOptions {\n json?: boolean;\n iat?: number | Date;\n headers?: Record<string, string>;\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 = 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 { json = false, iat, headers = {} } = options;\n const url = await this.buildUrl(params ?? {}, 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 private async request(url: URL, json: boolean, headers: Record<string, string>): Promise<Response> {\n const fetchImpl = 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(params: Record<string, unknown>, iat?: number | Date): 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(params: Record<string, unknown>, iat?: number | Date): 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 (payload.iss === undefined || payload.iss === null || String(payload.iss).length === 0) {\n throw new ConfigurationError(\"OG Pilot domain is missing\");\n }\n\n if (payload.sub === undefined || payload.sub === null || String(payload.sub).length === 0) {\n throw new ConfigurationError(\"OG Pilot API key prefix is missing\");\n }\n\n if (payload.title === undefined || payload.title === null || String(payload.title).length === 0) {\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\";\n\nlet defaultConfig = new Configuration();\n\nexport const configure = (updater: (config: Configuration) => void): 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 => new Client(options);\n\nconst OgPilot = {\n configure,\n resetConfig,\n getConfig,\n client,\n createClient,\n createImage,\n Configuration,\n ConfigurationError,\n OgPilotError,\n RequestError\n};\n\nexport default OgPilot;\nexport { Client, Configuration, OgPilotConfigOptions, ConfigurationError, OgPilotError, RequestError };\nexport type { CreateImageOptions } from \"./client\";\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\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":[]}
|