-
Notifications
You must be signed in to change notification settings - Fork 2
Feat/explicit http url + direct webhook public key #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
35c9043
b855795
36135ea
6b05e25
ed9dfbb
5321d91
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@scrawn/core": patch | ||
| --- | ||
|
|
||
| feat: pass in httpurl and webhook public key to constructor | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,6 +114,7 @@ const log = new ScrawnLogger("Scrawn"); | |
| * const biller = scrawn({ | ||
| * apiKey: process.env.SCRAWN_KEY, | ||
| * baseURL: 'http://localhost:8069', | ||
| * httpUrl: 'http://localhost:8070', | ||
| * tags: ["PREMIUM_CALL", "EXTRA_FEE"] as const, | ||
| * }); | ||
| * | ||
|
|
@@ -205,23 +206,27 @@ export class Scrawn< | |
| * | ||
| * @param config - Configuration object | ||
| * @param config.apiKey - Your Scrawn API key for authentication | ||
| * @param config.baseURL - Base URL for the Scrawn API (e.g., 'https://api.scrawn.dev') | ||
| * @param config.baseURL - Base URL for the Scrawn gRPC API (e.g., 'http://localhost:8069') | ||
| * @param config.httpUrl - HTTP URL for the Scrawn HTTP API (e.g., 'http://localhost:8070') | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const scrawn = new Scrawn({ | ||
| * apiKey: 'sk_test_...', | ||
| * baseURL: 'https://api.scrawn.dev' | ||
| * baseURL: 'http://localhost:8069', | ||
| * httpUrl: 'http://localhost:8070', | ||
| * }); | ||
| * await scrawn.init(); | ||
| * ``` | ||
| */ | ||
| constructor(config: { | ||
| apiKey: AllCredentials["apiKey"]; | ||
| baseURL: string; | ||
| httpUrl: string; | ||
| secure?: boolean; | ||
| credentials?: import("@grpc/grpc-js").ChannelCredentials; | ||
| retryCount?: number; | ||
| webhookPublicKey?: string; | ||
| }) { | ||
| try { | ||
| // Validate configuration | ||
|
|
@@ -243,9 +248,21 @@ export class Scrawn< | |
| ); | ||
| } | ||
|
|
||
| if (!config.httpUrl || typeof config.httpUrl !== "string") { | ||
| throw new ScrawnConfigError( | ||
| "httpUrl is required and must be a string", | ||
| { | ||
| details: { provided: typeof config.httpUrl }, | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| this.apiKey = config.apiKey; | ||
| this.retryCount = config.retryCount ?? 2; | ||
| this.httpUrl = this.buildHttpUrl(config.baseURL); | ||
| this.httpUrl = config.httpUrl; | ||
| if (config.webhookPublicKey) { | ||
| this.cachedPublicKey = config.webhookPublicKey; | ||
| } | ||
|
Comment on lines
+263
to
+265
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The key is cached as-is without any format check. If a caller pastes a malformed or empty-after-trim key, |
||
| this.grpcClient = new GrpcClient(this.parseURLToTarget(config.baseURL), { | ||
| secure: config.secure ?? true, | ||
| credentials: config.credentials, | ||
|
|
@@ -268,16 +285,6 @@ export class Scrawn< | |
| : `${baseURL}:${ScrawnConfig.grpc.defaultPort}`; | ||
| } | ||
|
|
||
| private buildHttpUrl(baseURL: string): string { | ||
| if (baseURL.includes("://")) { | ||
| const url = new URL(baseURL); | ||
| return `http://${url.hostname}:8070`; | ||
| } | ||
|
|
||
| const host = baseURL.includes(":") ? baseURL.split(":")[0] : baseURL; | ||
| return `http://${host}:8070`; | ||
| } | ||
|
|
||
| /** | ||
| * Create a type-safe tag reference. | ||
| * | ||
|
|
@@ -1307,6 +1314,7 @@ export class Scrawn< | |
| export interface ScrawnInitConfig { | ||
| apiKey: string; | ||
| baseURL: string; | ||
| httpUrl: string; | ||
| secure?: boolean; | ||
| credentials?: import("@grpc/grpc-js").ChannelCredentials; | ||
| tags?: readonly string[]; | ||
|
|
@@ -1317,6 +1325,12 @@ export interface ScrawnInitConfig { | |
| * Each event also gets a manual `.retry()` context in the onError callback. | ||
| */ | ||
| retryCount?: number; | ||
| /** | ||
| * Optional webhook public key to skip fetching it from the backend. | ||
| * The dashboard displays this key — paste it here to avoid an extra HTTP | ||
| * call on every cold start of biller.webhook(). | ||
| */ | ||
| webhookPublicKey?: string; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1333,6 +1347,7 @@ export interface ScrawnInitConfig { | |
| * const biller = scrawn({ | ||
| * apiKey: process.env.SCRAWN_KEY, | ||
| * baseURL: process.env.SCRAWN_BASE_URL, | ||
| * httpUrl: process.env.SCRAWN_HTTP_URL, | ||
| * tags: ["PREMIUM_CALL", "EXTRA_FEE"] as const, | ||
| * expressions: ["MY_EXPR"] as const, | ||
| * }); | ||
|
|
@@ -1363,8 +1378,10 @@ export function scrawn( | |
| return new Scrawn({ | ||
| apiKey: config.apiKey as AllCredentials["apiKey"], | ||
| baseURL: config.baseURL, | ||
| httpUrl: config.httpUrl, | ||
| secure: config.secure, | ||
| credentials: config.credentials, | ||
| retryCount: config.retryCount, | ||
| webhookPublicKey: config.webhookPublicKey, | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,6 +59,9 @@ describe("Scrawn", () => { | |
| const biller = scrawn({ | ||
| apiKey: validKey, | ||
| baseURL: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| }); | ||
|
Comment on lines
59
to
65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The same This pattern repeats across at least five test cases in this file. |
||
| attachMockClient(biller); | ||
|
|
||
|
|
@@ -77,6 +80,8 @@ describe("Scrawn", () => { | |
| const biller = scrawn({ | ||
| apiKey: validKey, | ||
| baseURL: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| }); | ||
| attachMockClient(biller); | ||
|
|
||
|
|
@@ -93,6 +98,8 @@ describe("Scrawn", () => { | |
| const biller = scrawn({ | ||
| apiKey: validKey, | ||
| baseURL: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| }); | ||
| attachMockClient(biller); | ||
| const link = await biller.collectPayment("user_1"); | ||
|
|
@@ -112,6 +119,8 @@ describe("Scrawn", () => { | |
| const biller = scrawn({ | ||
| apiKey: validKey, | ||
| baseURL: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| }); | ||
| attachMockClient(biller); | ||
|
|
||
|
|
@@ -124,6 +133,8 @@ describe("Scrawn", () => { | |
| const biller = scrawn({ | ||
| apiKey: validKey, | ||
| baseURL: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| httpUrl: "https://api.example", | ||
| retryCount: 0, | ||
| }); | ||
| const onError = vi.fn(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
httpUrlas a required constructor argument is a breaking change: any existing caller that does not passhttpUrlwill now receive aScrawnConfigErrorat runtime. Under semantic versioning this requires at least aminorbump; if the library is already at a stable major version it may warrant amajorbump. Apatchrelease communicates bug fixes or non-breaking additions, which does not describe this change.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!