@farm.js/unkey 0.1.0-beta.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Farm.js Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @farm.js/unkey
2
+
3
+ Unkey integration for Farm.js
4
+
5
+ Farm.js is currently in beta.
6
+
7
+ ```bash
8
+ npm install @farm.js/unkey@beta
9
+ ```
10
+
11
+ See the [Farm.js repository](https://github.com/farming-labs/farm.js) for documentation, examples, and support.
@@ -0,0 +1,463 @@
1
+ import { type FarmIntegrationHandlerContext, type FarmIntegrationLogger } from "@farm.js/core";
2
+ export interface UnkeyAPIEnvelope<TData> {
3
+ meta?: {
4
+ requestId?: string;
5
+ [key: string]: unknown;
6
+ };
7
+ data: TData;
8
+ }
9
+ export interface UnkeyRatelimitRequest {
10
+ name: string;
11
+ limit?: number;
12
+ duration?: number;
13
+ cost?: number;
14
+ autoApply?: boolean;
15
+ }
16
+ export interface UnkeyCreditsInput {
17
+ remaining?: number | null;
18
+ refill?: {
19
+ interval: "daily" | "monthly";
20
+ amount: number;
21
+ refillDay?: number;
22
+ } | null;
23
+ }
24
+ export interface UnkeyCreateKeyInput {
25
+ apiId?: string;
26
+ prefix?: string;
27
+ name?: string;
28
+ byteLength?: number;
29
+ externalId?: string;
30
+ meta?: Record<string, unknown>;
31
+ roles?: string[];
32
+ permissions?: string[];
33
+ expires?: number;
34
+ credits?: UnkeyCreditsInput;
35
+ ratelimits?: UnkeyRatelimitRequest[];
36
+ }
37
+ export interface UnkeyCreateKeyResult {
38
+ keyId: string;
39
+ key: string;
40
+ }
41
+ export interface UnkeyVerifyKeyInput {
42
+ key: string;
43
+ tags?: string[];
44
+ permissions?: string;
45
+ credits?: {
46
+ cost?: number;
47
+ };
48
+ ratelimits?: Array<{
49
+ name: string;
50
+ cost?: number;
51
+ limit?: number;
52
+ duration?: number;
53
+ }>;
54
+ migrationId?: string;
55
+ }
56
+ export interface UnkeyVerificationIdentity {
57
+ id?: string;
58
+ externalId?: string;
59
+ meta?: Record<string, unknown>;
60
+ ratelimits?: UnkeyRatelimitRequest[];
61
+ }
62
+ export interface UnkeyRatelimitState {
63
+ exceeded?: boolean;
64
+ id?: string;
65
+ name?: string;
66
+ limit?: number;
67
+ duration?: number;
68
+ reset?: number;
69
+ remaining?: number;
70
+ autoApply?: boolean;
71
+ }
72
+ export interface UnkeyVerifyKeyResult {
73
+ valid: boolean;
74
+ code?: string;
75
+ keyId?: string;
76
+ name?: string;
77
+ meta?: Record<string, unknown>;
78
+ expires?: number;
79
+ credits?: number;
80
+ enabled?: boolean;
81
+ permissions?: string[];
82
+ roles?: string[];
83
+ identity?: UnkeyVerificationIdentity;
84
+ ratelimits?: UnkeyRatelimitState[];
85
+ }
86
+ export interface UnkeyUpdateKeyInput {
87
+ keyId: string;
88
+ name?: string | null;
89
+ externalId?: string | null;
90
+ meta?: Record<string, unknown> | null;
91
+ expires?: number | null;
92
+ credits?: UnkeyCreditsInput | null;
93
+ ratelimits?: UnkeyRatelimitRequest[] | null;
94
+ enabled?: boolean;
95
+ roles?: string[];
96
+ permissions?: string[];
97
+ }
98
+ export interface UnkeyDeleteKeyInput {
99
+ keyId: string;
100
+ permanent?: boolean;
101
+ }
102
+ export interface UnkeyRevokeKeyInput {
103
+ keyId: string;
104
+ }
105
+ export interface UnkeyClient {
106
+ createKey(input: UnkeyCreateKeyInput): Promise<UnkeyCreateKeyResult>;
107
+ verifyKey(input: UnkeyVerifyKeyInput): Promise<UnkeyVerifyKeyResult>;
108
+ updateKey(input: UnkeyUpdateKeyInput): Promise<Record<string, never>>;
109
+ revokeKey(input: UnkeyRevokeKeyInput): Promise<Record<string, never>>;
110
+ deleteKey(input: UnkeyDeleteKeyInput): Promise<Record<string, never>>;
111
+ }
112
+ export interface UnkeyClientOptions {
113
+ rootKey?: string;
114
+ apiId?: string;
115
+ baseUrl?: string;
116
+ fetch?: typeof fetch;
117
+ }
118
+ export declare class UnkeyAPIError<TData = unknown> extends Error {
119
+ readonly status: number;
120
+ readonly requestId: string | undefined;
121
+ readonly data: TData | undefined;
122
+ constructor(message: string, options: {
123
+ status: number;
124
+ requestId?: string;
125
+ data?: TData;
126
+ });
127
+ }
128
+ export declare function createUnkeyClient(options?: UnkeyClientOptions): UnkeyClient;
129
+ export interface UnkeyIntegrationPaths {
130
+ basePath?: string;
131
+ create?: string;
132
+ verify?: string;
133
+ update?: string;
134
+ revoke?: string;
135
+ deleteKey?: string;
136
+ }
137
+ export interface UnkeyProtectionOptions {
138
+ matcher?: string | string[];
139
+ headers?: string | string[];
140
+ permissions?: string;
141
+ tags?: string[] | ((request: Request, context: FarmIntegrationHandlerContext) => string[]);
142
+ contextKey?: string;
143
+ exposeToPage?: boolean;
144
+ onVerified?: (request: Request, context: FarmIntegrationHandlerContext, result: UnkeyVerifyKeyResult) => Promise<Response | void> | Response | void;
145
+ onDenied?: (request: Request, context: FarmIntegrationHandlerContext, result: UnkeyVerifyKeyResult | {
146
+ valid: false;
147
+ code: "MISSING_KEY" | "VERIFY_ERROR";
148
+ }) => Promise<Response | void> | Response | void;
149
+ }
150
+ export interface UnkeyIntegrationInput extends UnkeyClientOptions {
151
+ client?: UnkeyClient;
152
+ paths?: UnkeyIntegrationPaths;
153
+ protectedRoutes?: string | string[];
154
+ protection?: UnkeyProtectionOptions;
155
+ log?: FarmIntegrationLogger;
156
+ }
157
+ interface ResolvedUnkeyConfig {
158
+ rootKey?: string;
159
+ apiId?: string;
160
+ baseUrl: string;
161
+ }
162
+ export declare function unkey(input?: UnkeyIntegrationInput): import("@farm.js/core").DefinedIntegration<{
163
+ category: "auth";
164
+ type: string;
165
+ instance: {
166
+ apiId: string | undefined;
167
+ baseUrl: string;
168
+ client: UnkeyClient;
169
+ };
170
+ api: {
171
+ [x: string]: {
172
+ post: {
173
+ readonly kind: "farm-integration-api-operation";
174
+ path: string;
175
+ method: "POST";
176
+ bodyFormat?: import("@farm.js/core/client").FarmIntegrationAPIBodyFormat | undefined;
177
+ responseFormat?: import("@farm.js/core/client").FarmIntegrationAPIResponseFormat | undefined;
178
+ headers?: {
179
+ [x: string]: string;
180
+ } | undefined;
181
+ credentials?: RequestCredentials | undefined;
182
+ isServer?: true | undefined;
183
+ __pathless?: boolean | undefined;
184
+ __types?: {
185
+ body: {
186
+ apiId?: string | undefined;
187
+ prefix?: string | undefined;
188
+ name?: string | undefined;
189
+ byteLength?: number | undefined;
190
+ externalId?: string | undefined;
191
+ meta?: {
192
+ [x: string]: unknown;
193
+ } | undefined;
194
+ roles?: string[] | undefined;
195
+ permissions?: {
196
+ [x: number]: string;
197
+ length: number;
198
+ toString: (() => string) & (() => string);
199
+ toLocaleString: {
200
+ (): string;
201
+ (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string;
202
+ };
203
+ pop: () => string | undefined;
204
+ push: (...items: string[]) => number;
205
+ concat: {
206
+ (...items: ConcatArray<string>[]): string[];
207
+ (...items: (string | ConcatArray<string>)[]): string[];
208
+ } & ((...strings: string[]) => string);
209
+ join: (separator?: string) => string;
210
+ reverse: () => string[];
211
+ shift: () => string | undefined;
212
+ slice: ((start?: number, end?: number) => string[]) & ((start?: number, end?: number) => string);
213
+ sort: (compareFn?: ((a: string, b: string) => number) | undefined) => string[] & string;
214
+ splice: {
215
+ (start: number, deleteCount?: number): string[];
216
+ (start: number, deleteCount: number, ...items: string[]): string[];
217
+ };
218
+ unshift: (...items: string[]) => number;
219
+ indexOf: ((searchElement: string, fromIndex?: number) => number) & ((searchString: string, position?: number) => number);
220
+ lastIndexOf: ((searchElement: string, fromIndex?: number) => number) & ((searchString: string, position?: number) => number);
221
+ every: {
222
+ <S extends string>(predicate: (value: string, index: number, array: string[]) => value is S, thisArg?: any): this is S[];
223
+ (predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): boolean;
224
+ };
225
+ some: (predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any) => boolean;
226
+ forEach: (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void;
227
+ map: <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[];
228
+ filter: {
229
+ <S extends string>(predicate: (value: string, index: number, array: string[]) => value is S, thisArg?: any): S[];
230
+ (predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): string[];
231
+ };
232
+ reduce: {
233
+ (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
234
+ (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
235
+ <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U;
236
+ };
237
+ reduceRight: {
238
+ (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
239
+ (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
240
+ <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U;
241
+ };
242
+ find: {
243
+ <S extends string>(predicate: (value: string, index: number, obj: string[]) => value is S, thisArg?: any): S | undefined;
244
+ (predicate: (value: string, index: number, obj: string[]) => unknown, thisArg?: any): string | undefined;
245
+ };
246
+ findIndex: (predicate: (value: string, index: number, obj: string[]) => unknown, thisArg?: any) => number;
247
+ fill: (value: string, start?: number, end?: number) => string[] & string;
248
+ copyWithin: (target: number, start: number, end?: number) => string[] & string;
249
+ entries: () => ArrayIterator<[number, string]>;
250
+ keys: () => ArrayIterator<number>;
251
+ values: () => ArrayIterator<string>;
252
+ includes: ((searchElement: string, fromIndex?: number) => boolean) & ((searchString: string, position?: number) => boolean);
253
+ flatMap: <U, This = undefined>(callback: (this: This, value: string, index: number, array: string[]) => U | readonly U[], thisArg?: This | undefined) => U[];
254
+ flat: <A, D extends number = 1>(this: A, depth?: D | undefined) => FlatArray<A, D>[];
255
+ at: ((index: number) => string | undefined) & ((index: number) => string | undefined);
256
+ [Symbol.iterator]: (() => ArrayIterator<string>) & (() => StringIterator<string>);
257
+ readonly [Symbol.unscopables]: {
258
+ [x: number]: boolean | undefined;
259
+ length?: boolean | undefined;
260
+ toString?: boolean | undefined;
261
+ toLocaleString?: boolean | undefined;
262
+ pop?: boolean | undefined;
263
+ push?: boolean | undefined;
264
+ concat?: boolean | undefined;
265
+ join?: boolean | undefined;
266
+ reverse?: boolean | undefined;
267
+ shift?: boolean | undefined;
268
+ slice?: boolean | undefined;
269
+ sort?: boolean | undefined;
270
+ splice?: boolean | undefined;
271
+ unshift?: boolean | undefined;
272
+ indexOf?: boolean | undefined;
273
+ lastIndexOf?: boolean | undefined;
274
+ every?: boolean | undefined;
275
+ some?: boolean | undefined;
276
+ forEach?: boolean | undefined;
277
+ map?: boolean | undefined;
278
+ filter?: boolean | undefined;
279
+ reduce?: boolean | undefined;
280
+ reduceRight?: boolean | undefined;
281
+ find?: boolean | undefined;
282
+ findIndex?: boolean | undefined;
283
+ fill?: boolean | undefined;
284
+ copyWithin?: boolean | undefined;
285
+ entries?: boolean | undefined;
286
+ keys?: boolean | undefined;
287
+ values?: boolean | undefined;
288
+ includes?: boolean | undefined;
289
+ flatMap?: boolean | undefined;
290
+ flat?: boolean | undefined;
291
+ at?: boolean | undefined;
292
+ [Symbol.iterator]?: boolean | undefined;
293
+ readonly [Symbol.unscopables]?: boolean | undefined;
294
+ };
295
+ charAt: (pos: number) => string;
296
+ charCodeAt: (index: number) => number;
297
+ localeCompare: {
298
+ (that: string): number;
299
+ (that: string, locales?: string | string[], options?: Intl.CollatorOptions): number;
300
+ (that: string, locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): number;
301
+ };
302
+ match: {
303
+ (regexp: string | RegExp): RegExpMatchArray | null;
304
+ (matcher: {
305
+ [Symbol.match](string: string): RegExpMatchArray | null;
306
+ }): RegExpMatchArray | null;
307
+ };
308
+ replace: {
309
+ (searchValue: string | RegExp, replaceValue: string): string;
310
+ (searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string;
311
+ (searchValue: {
312
+ [Symbol.replace](string: string, replaceValue: string): string;
313
+ }, replaceValue: string): string;
314
+ (searchValue: {
315
+ [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string;
316
+ }, replacer: (substring: string, ...args: any[]) => string): string;
317
+ };
318
+ search: {
319
+ (regexp: string | RegExp): number;
320
+ (searcher: {
321
+ [Symbol.search](string: string): number;
322
+ }): number;
323
+ };
324
+ split: {
325
+ (separator: string | RegExp, limit?: number): string[];
326
+ (splitter: {
327
+ [Symbol.split](string: string, limit?: number): string[];
328
+ }, limit?: number): string[];
329
+ };
330
+ substring: (start: number, end?: number) => string;
331
+ toLowerCase: () => string;
332
+ toLocaleLowerCase: {
333
+ (locales?: string | string[]): string;
334
+ (locales?: Intl.LocalesArgument): string;
335
+ };
336
+ toUpperCase: () => string;
337
+ toLocaleUpperCase: {
338
+ (locales?: string | string[]): string;
339
+ (locales?: Intl.LocalesArgument): string;
340
+ };
341
+ trim: () => string;
342
+ substr: (from: number, length?: number) => string;
343
+ valueOf: () => string;
344
+ codePointAt: (pos: number) => number | undefined;
345
+ endsWith: (searchString: string, endPosition?: number) => boolean;
346
+ normalize: {
347
+ (form: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
348
+ (form?: string): string;
349
+ };
350
+ repeat: (count: number) => string;
351
+ startsWith: (searchString: string, position?: number) => boolean;
352
+ anchor: (name: string) => string;
353
+ big: () => string;
354
+ blink: () => string;
355
+ bold: () => string;
356
+ fixed: () => string;
357
+ fontcolor: (color: string) => string;
358
+ fontsize: {
359
+ (size: number): string;
360
+ (size: string): string;
361
+ };
362
+ italics: () => string;
363
+ link: (url: string) => string;
364
+ small: () => string;
365
+ strike: () => string;
366
+ sub: () => string;
367
+ sup: () => string;
368
+ padStart: (maxLength: number, fillString?: string) => string;
369
+ padEnd: (maxLength: number, fillString?: string) => string;
370
+ trimEnd: () => string;
371
+ trimStart: () => string;
372
+ trimLeft: () => string;
373
+ trimRight: () => string;
374
+ matchAll: (regexp: RegExp) => RegExpStringIterator<RegExpExecArray>;
375
+ replaceAll: {
376
+ (searchValue: string | RegExp, replaceValue: string): string;
377
+ (searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string;
378
+ };
379
+ } | undefined;
380
+ expires?: number | undefined;
381
+ credits?: {
382
+ remaining?: number | null | undefined;
383
+ refill?: {
384
+ interval: "daily" | "monthly";
385
+ amount: number;
386
+ refillDay?: number | undefined;
387
+ } | null | undefined;
388
+ cost?: number | undefined;
389
+ } | undefined;
390
+ ratelimits?: ({
391
+ name: string;
392
+ limit?: number | undefined;
393
+ duration?: number | undefined;
394
+ cost?: number | undefined;
395
+ autoApply?: boolean | undefined;
396
+ }[] & {
397
+ name: string;
398
+ cost?: number | undefined;
399
+ limit?: number | undefined;
400
+ duration?: number | undefined;
401
+ }[]) | undefined;
402
+ key: string;
403
+ tags?: string[] | undefined;
404
+ migrationId?: string | undefined;
405
+ keyId: string;
406
+ enabled?: boolean | undefined;
407
+ permanent?: boolean | undefined;
408
+ };
409
+ query: never;
410
+ response: {
411
+ [x: string]: never;
412
+ keyId: string;
413
+ key: string;
414
+ valid: boolean;
415
+ code?: string | undefined;
416
+ name?: string | undefined;
417
+ meta?: {
418
+ [x: string]: unknown;
419
+ } | undefined;
420
+ expires?: number | undefined;
421
+ credits?: number | undefined;
422
+ enabled?: boolean | undefined;
423
+ permissions?: string[] | undefined;
424
+ roles?: string[] | undefined;
425
+ identity?: {
426
+ id?: string | undefined;
427
+ externalId?: string | undefined;
428
+ meta?: {
429
+ [x: string]: unknown;
430
+ } | undefined;
431
+ ratelimits?: {
432
+ name: string;
433
+ limit?: number | undefined;
434
+ duration?: number | undefined;
435
+ cost?: number | undefined;
436
+ autoApply?: boolean | undefined;
437
+ }[] | undefined;
438
+ } | undefined;
439
+ ratelimits?: {
440
+ exceeded?: boolean | undefined;
441
+ id?: string | undefined;
442
+ name?: string | undefined;
443
+ limit?: number | undefined;
444
+ duration?: number | undefined;
445
+ reset?: number | undefined;
446
+ remaining?: number | undefined;
447
+ autoApply?: boolean | undefined;
448
+ }[] | undefined;
449
+ };
450
+ } | undefined;
451
+ };
452
+ };
453
+ };
454
+ config: import("@farm.js/core").FarmIntegrationConfigDefinition<ResolvedUnkeyConfig, import("@farm.js/core").FarmIntegrationSchema | undefined>;
455
+ log: FarmIntegrationLogger | undefined;
456
+ middleware: {
457
+ matcher: string | string[];
458
+ handler(request: Request, context: FarmIntegrationHandlerContext<unknown, unknown, import("@farm.js/core").FarmIntegrationSchema | undefined>): Promise<void | Response>;
459
+ }[] | undefined;
460
+ routes: (import("@farm.js/core").FarmTypedIntegrationRoute<string, UnkeyCreateKeyInput, never, UnkeyCreateKeyResult, true, "POST", import("@farm.js/core").FarmIntegrationSchema | undefined> | import("@farm.js/core").FarmTypedIntegrationRoute<string, UnkeyVerifyKeyInput, never, UnkeyVerifyKeyResult, true, "POST", import("@farm.js/core").FarmIntegrationSchema | undefined> | import("@farm.js/core").FarmTypedIntegrationRoute<string, UnkeyRevokeKeyInput, never, Record<string, never>, true, "POST", import("@farm.js/core").FarmIntegrationSchema | undefined>)[];
461
+ }>;
462
+ export {};
463
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,380 @@
1
+ import { FARM_INTEGRATION_INTERNAL_DISPATCH_CONTEXT_KEY, defineIntegration, integrationRoute, } from "@farm.js/core";
2
+ import { api as clientApi } from "@farm.js/core/client";
3
+ import { createPathInferredClientApi, integrationConfig } from "@farm.js/integration-utils";
4
+ const DEFAULT_UNKEY_BASE_URL = "https://api.unkey.com";
5
+ export class UnkeyAPIError extends Error {
6
+ status;
7
+ requestId;
8
+ data;
9
+ constructor(message, options) {
10
+ super(message);
11
+ this.name = "UnkeyAPIError";
12
+ this.status = options.status;
13
+ this.requestId = options.requestId;
14
+ this.data = options.data;
15
+ }
16
+ }
17
+ export function createUnkeyClient(options = {}) {
18
+ return new UnkeyHttpClient(options);
19
+ }
20
+ class UnkeyHttpClient {
21
+ rootKey;
22
+ apiId;
23
+ baseUrl;
24
+ fetchImpl;
25
+ constructor(options) {
26
+ this.rootKey = options.rootKey ?? process.env.UNKEY_ROOT_KEY ?? undefined;
27
+ this.apiId = options.apiId ?? process.env.UNKEY_API_ID ?? undefined;
28
+ this.baseUrl = options.baseUrl ?? process.env.UNKEY_BASE_URL ?? DEFAULT_UNKEY_BASE_URL;
29
+ this.fetchImpl = options.fetch ?? fetch;
30
+ }
31
+ createKey(input) {
32
+ const apiId = input.apiId ?? this.apiId;
33
+ if (!apiId) {
34
+ throw new Error("Unkey createKey requires UNKEY_API_ID, options.apiId, or input.apiId.");
35
+ }
36
+ return this.request("keys.createKey", {
37
+ ...input,
38
+ apiId,
39
+ });
40
+ }
41
+ verifyKey(input) {
42
+ return this.request("keys.verifyKey", input);
43
+ }
44
+ updateKey(input) {
45
+ return this.request("keys.updateKey", input);
46
+ }
47
+ revokeKey(input) {
48
+ return this.updateKey({
49
+ keyId: input.keyId,
50
+ enabled: false,
51
+ });
52
+ }
53
+ deleteKey(input) {
54
+ return this.request("keys.deleteKey", input);
55
+ }
56
+ async request(operation, body) {
57
+ if (!this.rootKey) {
58
+ throw new Error("Unkey client requires UNKEY_ROOT_KEY or options.rootKey.");
59
+ }
60
+ const response = await this.fetchImpl(`${this.baseUrl.replace(/\/+$/, "")}/v2/${operation}`, {
61
+ method: "POST",
62
+ headers: {
63
+ authorization: `Bearer ${this.rootKey}`,
64
+ "content-type": "application/json",
65
+ accept: "application/json",
66
+ },
67
+ body: JSON.stringify(body),
68
+ });
69
+ const payload = await parseUnkeyResponse(response);
70
+ if (!response.ok) {
71
+ throw createUnkeyError(response, payload);
72
+ }
73
+ return (payload.data ?? {});
74
+ }
75
+ }
76
+ async function parseUnkeyResponse(response) {
77
+ const text = await response.text();
78
+ if (!text) {
79
+ return {};
80
+ }
81
+ try {
82
+ return JSON.parse(text);
83
+ }
84
+ catch {
85
+ return {
86
+ message: text,
87
+ };
88
+ }
89
+ }
90
+ function createUnkeyError(response, payload) {
91
+ const data = isRecord(payload) ? payload : undefined;
92
+ const error = isRecord(data?.error) ? data.error : undefined;
93
+ const message = getString(error?.message) ||
94
+ getString(data?.message) ||
95
+ response.statusText ||
96
+ "Unkey API request failed.";
97
+ const requestId = getString(data?.requestId) ||
98
+ (isRecord(data?.meta) ? getString(data.meta.requestId) : undefined);
99
+ return new UnkeyAPIError(message, {
100
+ status: response.status,
101
+ requestId,
102
+ data,
103
+ });
104
+ }
105
+ function createUnkeyApi(paths) {
106
+ return createPathInferredClientApi({
107
+ path: paths.create,
108
+ operation: clientApi.post(paths.create, {
109
+ responseFormat: "json",
110
+ isServer: true,
111
+ }),
112
+ }, {
113
+ path: paths.verify,
114
+ operation: clientApi.post(paths.verify, {
115
+ responseFormat: "json",
116
+ isServer: true,
117
+ }),
118
+ }, {
119
+ path: paths.update,
120
+ operation: clientApi.post(paths.update, {
121
+ responseFormat: "json",
122
+ isServer: true,
123
+ }),
124
+ }, {
125
+ path: paths.revoke,
126
+ operation: clientApi.post(paths.revoke, {
127
+ responseFormat: "json",
128
+ isServer: true,
129
+ }),
130
+ }, {
131
+ path: paths.deleteKey,
132
+ operation: clientApi.post(paths.deleteKey, {
133
+ responseFormat: "json",
134
+ isServer: true,
135
+ }),
136
+ });
137
+ }
138
+ export function unkey(input = {}) {
139
+ const config = resolveUnkeyConfig(input);
140
+ const paths = resolveUnkeyPaths(input.paths);
141
+ const hasInjectedClient = !!input.client;
142
+ const client = input.client ?? createUnkeyClient(config);
143
+ const protection = input.protection;
144
+ const protectedRoutes = input.protectedRoutes ?? protection?.matcher;
145
+ return defineIntegration({
146
+ category: "auth",
147
+ type: "unkey",
148
+ instance: {
149
+ apiId: config.apiId,
150
+ baseUrl: config.baseUrl,
151
+ client,
152
+ },
153
+ api: createUnkeyApi(paths),
154
+ config: integrationConfig({
155
+ label: "Unkey integration",
156
+ env: {
157
+ rootKey: "UNKEY_ROOT_KEY",
158
+ apiId: "UNKEY_API_ID",
159
+ baseUrl: "UNKEY_BASE_URL",
160
+ },
161
+ defaults: {
162
+ baseUrl: DEFAULT_UNKEY_BASE_URL,
163
+ },
164
+ input: config,
165
+ required: hasInjectedClient ? [] : ["rootKey"],
166
+ }),
167
+ log: input.log,
168
+ middleware: protectedRoutes
169
+ ? [
170
+ {
171
+ matcher: protectedRoutes,
172
+ handler(request, context) {
173
+ return verifyProtectedRequest(request, context, client, protection);
174
+ },
175
+ },
176
+ ]
177
+ : undefined,
178
+ routes: [
179
+ integrationRoute.post(paths.create, {
180
+ responseFormat: "json",
181
+ isServer: true,
182
+ async handler(request, context) {
183
+ const blocked = ensureInternalServerCall(context);
184
+ if (blocked) {
185
+ return blocked;
186
+ }
187
+ const body = await readJsonBody(request);
188
+ if (!hasInjectedClient && !body.apiId && !config.apiId) {
189
+ return Response.json({
190
+ error: "Unkey create key requires UNKEY_API_ID, options.apiId, or body.apiId.",
191
+ }, {
192
+ status: 400,
193
+ });
194
+ }
195
+ return Response.json(await client.createKey({
196
+ ...body,
197
+ apiId: body.apiId ?? config.apiId,
198
+ }));
199
+ },
200
+ }),
201
+ integrationRoute.post(paths.verify, {
202
+ responseFormat: "json",
203
+ isServer: true,
204
+ async handler(request, context) {
205
+ const blocked = ensureInternalServerCall(context);
206
+ if (blocked) {
207
+ return blocked;
208
+ }
209
+ return Response.json(await client.verifyKey(await readJsonBody(request)));
210
+ },
211
+ }),
212
+ integrationRoute.post(paths.update, {
213
+ responseFormat: "json",
214
+ isServer: true,
215
+ async handler(request, context) {
216
+ const blocked = ensureInternalServerCall(context);
217
+ if (blocked) {
218
+ return blocked;
219
+ }
220
+ return Response.json(await client.updateKey(await readJsonBody(request)));
221
+ },
222
+ }),
223
+ integrationRoute.post(paths.revoke, {
224
+ responseFormat: "json",
225
+ isServer: true,
226
+ async handler(request, context) {
227
+ const blocked = ensureInternalServerCall(context);
228
+ if (blocked) {
229
+ return blocked;
230
+ }
231
+ return Response.json(await client.revokeKey(await readJsonBody(request)));
232
+ },
233
+ }),
234
+ integrationRoute.post(paths.deleteKey, {
235
+ responseFormat: "json",
236
+ isServer: true,
237
+ async handler(request, context) {
238
+ const blocked = ensureInternalServerCall(context);
239
+ if (blocked) {
240
+ return blocked;
241
+ }
242
+ return Response.json(await client.deleteKey(await readJsonBody(request)));
243
+ },
244
+ }),
245
+ ],
246
+ });
247
+ }
248
+ function resolveUnkeyConfig(input) {
249
+ return {
250
+ rootKey: input.rootKey ?? process.env.UNKEY_ROOT_KEY ?? undefined,
251
+ apiId: input.apiId ?? process.env.UNKEY_API_ID ?? undefined,
252
+ baseUrl: input.baseUrl ?? process.env.UNKEY_BASE_URL ?? DEFAULT_UNKEY_BASE_URL,
253
+ };
254
+ }
255
+ function resolveUnkeyPaths(paths = {}) {
256
+ const basePath = normalizePath(paths.basePath ?? "/api/unkey");
257
+ return {
258
+ create: normalizePath(paths.create ?? `${basePath}/create`),
259
+ verify: normalizePath(paths.verify ?? `${basePath}/verify`),
260
+ update: normalizePath(paths.update ?? `${basePath}/update`),
261
+ revoke: normalizePath(paths.revoke ?? `${basePath}/revoke`),
262
+ deleteKey: normalizePath(paths.deleteKey ?? `${basePath}/delete-key`),
263
+ };
264
+ }
265
+ function normalizePath(path) {
266
+ return path.startsWith("/") ? path : `/${path}`;
267
+ }
268
+ async function readJsonBody(request) {
269
+ const text = await request.text();
270
+ if (!text) {
271
+ return {};
272
+ }
273
+ return JSON.parse(text);
274
+ }
275
+ function ensureInternalServerCall(context) {
276
+ if (context.req.get(FARM_INTEGRATION_INTERNAL_DISPATCH_CONTEXT_KEY) === true) {
277
+ return undefined;
278
+ }
279
+ return Response.json({
280
+ error: "Not found",
281
+ }, {
282
+ status: 404,
283
+ });
284
+ }
285
+ async function verifyProtectedRequest(request, context, client, options = {}) {
286
+ const key = getApiKeyFromRequest(request, options.headers);
287
+ if (!key) {
288
+ return ((await options.onDenied?.(request, context, {
289
+ valid: false,
290
+ code: "MISSING_KEY",
291
+ })) ||
292
+ Response.json({
293
+ error: "Missing API key",
294
+ code: "MISSING_KEY",
295
+ }, {
296
+ status: 401,
297
+ }));
298
+ }
299
+ try {
300
+ const result = await client.verifyKey({
301
+ key,
302
+ permissions: options.permissions,
303
+ tags: resolveProtectionTags(request, context, options.tags),
304
+ });
305
+ if (result.valid) {
306
+ const contextKey = options.contextKey ?? "unkey";
307
+ context.req.set(contextKey, result, {
308
+ exposeToPage: options.exposeToPage,
309
+ });
310
+ context.req.set("apiKey", result, {
311
+ exposeToPage: options.exposeToPage,
312
+ });
313
+ if (result.keyId) {
314
+ context.req.set("apiKeyId", result.keyId, {
315
+ exposeToPage: options.exposeToPage,
316
+ });
317
+ }
318
+ if (result.identity?.externalId) {
319
+ context.req.set("apiKeyOwnerId", result.identity.externalId, {
320
+ exposeToPage: options.exposeToPage,
321
+ });
322
+ }
323
+ return options.onVerified?.(request, context, result);
324
+ }
325
+ const override = await options.onDenied?.(request, context, result);
326
+ if (override) {
327
+ return override;
328
+ }
329
+ return Response.json({
330
+ error: "Invalid API key",
331
+ code: result.code ?? "INVALID",
332
+ }, {
333
+ status: result.code === "RATE_LIMITED" ? 429 : 401,
334
+ });
335
+ }
336
+ catch {
337
+ const failure = {
338
+ valid: false,
339
+ code: "VERIFY_ERROR",
340
+ };
341
+ const override = await options.onDenied?.(request, context, failure);
342
+ if (override) {
343
+ return override;
344
+ }
345
+ return Response.json({
346
+ error: "API key verification failed",
347
+ code: failure.code,
348
+ }, {
349
+ status: 401,
350
+ });
351
+ }
352
+ }
353
+ function getApiKeyFromRequest(request, headers) {
354
+ const names = Array.isArray(headers)
355
+ ? headers
356
+ : headers
357
+ ? [headers]
358
+ : ["authorization", "x-api-key"];
359
+ for (const name of names) {
360
+ const value = request.headers.get(name);
361
+ if (!value) {
362
+ continue;
363
+ }
364
+ if (name.toLowerCase() === "authorization") {
365
+ const match = value.match(/^Bearer\s+(.+)$/i);
366
+ return (match?.[1] || value).trim();
367
+ }
368
+ return value.trim();
369
+ }
370
+ return undefined;
371
+ }
372
+ function resolveProtectionTags(request, context, tags) {
373
+ return typeof tags === "function" ? tags(request, context) : tags;
374
+ }
375
+ function isRecord(value) {
376
+ return !!value && typeof value === "object" && !Array.isArray(value);
377
+ }
378
+ function getString(value) {
379
+ return typeof value === "string" && value.length > 0 ? value : undefined;
380
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@farm.js/unkey",
3
+ "version": "0.1.0-beta.0",
4
+ "description": "Unkey integration for Farm.js",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/farming-labs/farm.js",
9
+ "directory": "packages/farm-unkey"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "@farm.js/core": "0.1.0-beta.0",
29
+ "@farm.js/integration-utils": "0.1.0-beta.0"
30
+ },
31
+ "scripts": {
32
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
33
+ "dev": "tsc --watch",
34
+ "type-check": "tsc --noEmit",
35
+ "test": "echo 'No tests in this package'"
36
+ }
37
+ }