@o2js/core 0.0.0-stage → 0.1.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gökhan Altun
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.
package/README.md CHANGED
@@ -1,3 +1,231 @@
1
- # Temporary Holding Version
1
+ # o2js
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **A lightweight and provider-agnostic OAuth2 library for Node.js.**
4
+
5
+ o2js provides the core OAuth2 authorization code and refresh token flows.
6
+
7
+ It does not manage users, sessions, token storage, or database operations. It only handles OAuth2 mechanics and leaves the rest to your application.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @o2js/core
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ First, define a provider:
18
+
19
+ ```typescript
20
+ import type { Provider } from "@o2js/core";
21
+
22
+ class MyProvider implements Provider {
23
+ authURL(): string {
24
+ return "https://example.com/oauth/authorize";
25
+ }
26
+
27
+ tokenURL(): string {
28
+ return "https://example.com/oauth/token";
29
+ }
30
+ }
31
+ ```
32
+
33
+ Create an OAuth2 client:
34
+
35
+ ```typescript
36
+ import { OAuth2 } from "@o2js/core";
37
+
38
+ const oauth = new OAuth2(
39
+ new MyProvider(),
40
+ {
41
+ clientID: "your-client-id",
42
+ clientSecret: "your-client-secret",
43
+ redirectURL: "https://yourapp.com/callback",
44
+ }
45
+ );
46
+ ```
47
+
48
+ Generate an authorization URL:
49
+
50
+ ```typescript
51
+ const state = "your-random-state";
52
+ const url = oauth.authCodeURL(state);
53
+ ```
54
+
55
+ After the user authorizes your application, exchange the authorization code:
56
+
57
+ ```typescript
58
+ const response = await oauth.exchangeAuthCode(code);
59
+
60
+ console.log(response.data);
61
+ ```
62
+
63
+ Refresh an access token:
64
+
65
+ ```typescript
66
+ const response = await oauth.exchangeRefreshToken(refreshToken);
67
+ ```
68
+
69
+ ## Configuration
70
+
71
+ ```typescript
72
+ type ClientAuthMethod =
73
+ | "client_secret_basic"
74
+ | "client_secret_post";
75
+
76
+ type Config = {
77
+ clientID: string;
78
+ clientSecret: string;
79
+ redirectURL: string;
80
+ clientAuthMethod?: ClientAuthMethod;
81
+ };
82
+ ```
83
+
84
+ - `clientID`: OAuth application client ID.
85
+ - `clientSecret`: OAuth application client secret.
86
+ - `redirectURL`: Registered callback URL.
87
+ - `clientAuthMethod`: Client authentication method used at the token endpoint.
88
+
89
+ Supported client authentication methods:
90
+
91
+ - `client_secret_basic`: Sends client credentials using HTTP Basic Authentication. This is the default.
92
+ - `client_secret_post`: Sends client credentials in the request body.
93
+
94
+ Example using `client_secret_post`:
95
+
96
+ ```typescript
97
+ const oauth = new OAuth2(provider, {
98
+ clientID: "your-client-id",
99
+ clientSecret: "your-client-secret",
100
+ redirectURL: "https://yourapp.com/callback",
101
+ clientAuthMethod: "client_secret_post",
102
+ });
103
+ ```
104
+
105
+ If `clientAuthMethod` is omitted, o2js uses `client_secret_basic`.
106
+
107
+
108
+ ## Custom Parameters
109
+
110
+ OAuth providers may require additional parameters for scopes, PKCE, or other features.
111
+
112
+ You can pass these parameters directly to the relevant methods.
113
+
114
+ Additional authorization URL parameters:
115
+
116
+ ```typescript
117
+ const url = oauth.authCodeURL(state, {
118
+ scope: "profile email",
119
+ prompt: "consent",
120
+ });
121
+ ```
122
+
123
+ Additional token request parameters:
124
+
125
+ ```typescript
126
+ const response = await oauth.exchangeAuthCode(code, {
127
+ code_verifier: "your-code-verifier",
128
+ });
129
+ ```
130
+
131
+ Refresh token requests also accept additional parameters:
132
+
133
+ ```typescript
134
+ const response = await oauth.exchangeRefreshToken(refreshToken, {
135
+ custom_parameter: "value",
136
+ });
137
+ ```
138
+
139
+ Check your provider's documentation for supported parameters and their expected values.
140
+
141
+ ## State and PKCE
142
+
143
+ o2js provides helpers for generating random state values and PKCE parameters.
144
+
145
+ Generate a random state:
146
+
147
+ ```typescript
148
+ import { generateRandomState } from "@o2js/core";
149
+
150
+ const state = generateRandomState();
151
+ ```
152
+
153
+ Generate PKCE parameters:
154
+
155
+ ```typescript
156
+ import { generateRandomPKCE } from "@o2js/core";
157
+
158
+ const pkce = generateRandomPKCE();
159
+ ```
160
+
161
+ Use the generated values in the authorization URL:
162
+
163
+ ```typescript
164
+ const url = oauth.authCodeURL(state, {
165
+ code_challenge: pkce.codeChallenge,
166
+ code_challenge_method: "S256",
167
+ });
168
+ ```
169
+
170
+ Send the code verifier when exchanging the authorization code:
171
+
172
+ ```typescript
173
+ const response = await oauth.exchangeAuthCode(code, {
174
+ code_verifier: pkce.codeVerifier,
175
+ });
176
+ ```
177
+
178
+ State and PKCE values must be stored and managed by your application. o2js does not handle their storage, verification, or lifecycle.
179
+
180
+ ## Response
181
+
182
+ Token exchange methods return an `ExchangeResponse`:
183
+
184
+ ```typescript
185
+ type ExchangeResponse = {
186
+ raw: string;
187
+ data: Record<string, unknown>;
188
+ };
189
+ ```
190
+
191
+ - `raw`: Raw response body.
192
+ - `data`: Parsed JSON response.
193
+
194
+ ## Error Handling
195
+
196
+ HTTP and response parsing errors are represented by `HTTPError`.
197
+
198
+ ```typescript
199
+ import { HTTPError } from "@o2js/core";
200
+
201
+ try {
202
+ const response = await oauth.exchangeAuthCode(code);
203
+ } catch (error) {
204
+ if (error instanceof HTTPError) {
205
+ console.log("Message:", error.message);
206
+ console.log("Status:", error.status);
207
+ console.log("Body:", error.body);
208
+ }
209
+ }
210
+ ```
211
+
212
+ `body` contains the raw response body when available.
213
+
214
+ ## Providers
215
+
216
+ o2js does not include provider implementations.
217
+
218
+ You can implement the `Provider` interface yourself or use separate provider packages when available.
219
+
220
+ A provider only needs to implement:
221
+
222
+ ```typescript
223
+ export interface Provider {
224
+ authURL(): string;
225
+ tokenURL(): string;
226
+ }
227
+ ```
228
+
229
+ ## License
230
+
231
+ MIT
@@ -0,0 +1,8 @@
1
+ export type ClientAuthMethod = "client_secret_basic" | "client_secret_post";
2
+ export type Config = {
3
+ clientID: string;
4
+ clientSecret: string;
5
+ redirectURL: string;
6
+ clientAuthMethod?: ClientAuthMethod;
7
+ };
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACtB,qBAAqB,GACrB,oBAAoB,CAAC;AAE3B,MAAM,MAAM,MAAM,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACvC,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export type PKCE = {
2
+ codeVerifier: string;
3
+ codeChallenge: string;
4
+ };
5
+ export declare function generateRandomState(): string;
6
+ export declare function generateRandomPKCE(): PKCE;
7
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,GAAG;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAWzC"}
package/dist/crypto.js ADDED
@@ -0,0 +1,15 @@
1
+ import { randomBytes, createHash } from "node:crypto";
2
+ export function generateRandomState() {
3
+ return randomBytes(32).toString("hex");
4
+ }
5
+ export function generateRandomPKCE() {
6
+ const codeVerifier = randomBytes(32).toString("base64url");
7
+ const codeChallenge = createHash("sha256")
8
+ .update(codeVerifier)
9
+ .digest("base64url");
10
+ return {
11
+ codeVerifier,
12
+ codeChallenge,
13
+ };
14
+ }
15
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOtD,MAAM,UAAU,mBAAmB;IAC/B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,kBAAkB;IAC9B,MAAM,YAAY,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAE3D,MAAM,aAAa,GAAG,UAAU,CAAC,QAAQ,CAAC;SACrC,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzB,OAAO;QACH,YAAY;QACZ,aAAa;KAChB,CAAC;AACN,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare class HTTPError extends Error {
2
+ readonly status?: number | undefined;
3
+ readonly body?: string | undefined;
4
+ constructor(message: string, status?: number | undefined, body?: string | undefined, options?: ErrorOptions);
5
+ }
6
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;aAGZ,MAAM,CAAC,EAAE,MAAM;aACf,IAAI,CAAC,EAAE,MAAM;IAHjC,YACI,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,IAAI,CAAC,EAAE,MAAM,YAAA,EAC7B,OAAO,CAAC,EAAE,YAAY,EAIzB;CACJ"}
package/dist/errors.js ADDED
@@ -0,0 +1,11 @@
1
+ export class HTTPError extends Error {
2
+ status;
3
+ body;
4
+ constructor(message, status, body, options) {
5
+ super(message, options);
6
+ this.status = status;
7
+ this.body = body;
8
+ this.name = "HTTPError";
9
+ }
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGZ,MAAM;IACN,IAAI;IAHxB,YACI,OAAe,EACC,MAAe,EACf,IAAa,EAC7B,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;sBAJR,MAAM;oBACN,IAAI;QAIpB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC5B,CAAC;CACJ"}
@@ -0,0 +1,7 @@
1
+ export { OAuth2 } from "./oauth2.js";
2
+ export { HTTPError } from "./errors.js";
3
+ export type { Provider } from "./provider.js";
4
+ export type { Config, ClientAuthMethod } from "./config.js";
5
+ export type { ExchangeResponse } from "./response.js";
6
+ export { generateRandomState, generateRandomPKCE, type PKCE } from "./crypto.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACH,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,IAAI,EACZ,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { OAuth2 } from "./oauth2.js";
2
+ export { HTTPError } from "./errors.js";
3
+ export { generateRandomState, generateRandomPKCE } from "./crypto.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,OAAO,EACH,mBAAmB,EACnB,kBAAkB,EAErB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Provider } from "./provider.js";
2
+ import type { Config } from "./config.js";
3
+ import type { ExchangeResponse } from "./response.js";
4
+ export declare class OAuth2 {
5
+ private provider;
6
+ private config;
7
+ constructor(provider: Provider, config: Config);
8
+ authCodeURL(state: string, urlParams?: Record<string, string>): string;
9
+ exchangeAuthCode(code: string, tokenParams?: Record<string, string>): Promise<ExchangeResponse>;
10
+ exchangeRefreshToken(refreshToken: string, tokenParams?: Record<string, string>): Promise<ExchangeResponse>;
11
+ private exchange;
12
+ private validate;
13
+ }
14
+ //# sourceMappingURL=oauth2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth2.d.ts","sourceRoot":"","sources":["../src/oauth2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AActD,qBAAa,MAAM;IAEX,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IAFlB,YACY,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EAGzB;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CA0BrE;IAEK,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAYpG;IAEK,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgBhH;YAEa,QAAQ;IAqGtB,OAAO,CAAC,QAAQ;CAoCnB"}
package/dist/oauth2.js ADDED
@@ -0,0 +1,135 @@
1
+ import { HTTPError } from "./errors.js";
2
+ import { parseParams, baseReservedParams, } from "./params.js";
3
+ function encodeFormValue(value) {
4
+ return new URLSearchParams([["value", value]])
5
+ .toString()
6
+ .slice("value=".length);
7
+ }
8
+ export class OAuth2 {
9
+ provider;
10
+ config;
11
+ constructor(provider, config) {
12
+ this.provider = provider;
13
+ this.config = config;
14
+ this.validate();
15
+ }
16
+ authCodeURL(state, urlParams) {
17
+ const params = new URLSearchParams();
18
+ params.set("client_id", this.config.clientID);
19
+ params.set("redirect_uri", this.config.redirectURL);
20
+ params.set("response_type", "code");
21
+ parseParams(baseReservedParams(), urlParams ?? {}, (key, value) => {
22
+ params.set(key, value);
23
+ });
24
+ if (state !== "") {
25
+ params.set("state", state);
26
+ }
27
+ const url = new URL(this.provider.authURL());
28
+ params.forEach((value, key) => {
29
+ url.searchParams.set(key, value);
30
+ });
31
+ return url.toString();
32
+ }
33
+ async exchangeAuthCode(code, tokenParams) {
34
+ if (!code.trim()) {
35
+ throw new Error("Code cannot be empty");
36
+ }
37
+ const params = new URLSearchParams();
38
+ params.set("code", code);
39
+ params.set("redirect_uri", this.config.redirectURL);
40
+ params.set("grant_type", "authorization_code");
41
+ return this.exchange(params, baseReservedParams(), tokenParams);
42
+ }
43
+ async exchangeRefreshToken(refreshToken, tokenParams) {
44
+ if (!refreshToken.trim()) {
45
+ throw new Error("Refresh token cannot be empty");
46
+ }
47
+ const params = new URLSearchParams();
48
+ params.set("refresh_token", refreshToken);
49
+ params.set("redirect_uri", this.config.redirectURL);
50
+ params.set("grant_type", "refresh_token");
51
+ return this.exchange(params, baseReservedParams(), tokenParams);
52
+ }
53
+ async exchange(params, reservedParams, tokenParams) {
54
+ parseParams(reservedParams, tokenParams ?? {}, (key, value) => {
55
+ params.set(key, value);
56
+ });
57
+ const authMethod = this.config.clientAuthMethod ?? "client_secret_basic";
58
+ const headers = {
59
+ "Content-Type": "application/x-www-form-urlencoded",
60
+ };
61
+ if (authMethod === "client_secret_basic") {
62
+ const credentials = Buffer.from(`${encodeFormValue(this.config.clientID)}:${encodeFormValue(this.config.clientSecret)}`, "utf8").toString("base64");
63
+ headers["Authorization"] = `Basic ${credentials}`;
64
+ }
65
+ else {
66
+ params.set("client_id", this.config.clientID);
67
+ params.set("client_secret", this.config.clientSecret);
68
+ }
69
+ let response;
70
+ try {
71
+ response = await fetch(this.provider.tokenURL(), {
72
+ method: "POST",
73
+ headers,
74
+ body: params.toString(),
75
+ });
76
+ }
77
+ catch (error) {
78
+ throw new HTTPError("Exchange: failed to post token request", undefined, undefined, { cause: error });
79
+ }
80
+ let raw;
81
+ try {
82
+ raw = await response.text();
83
+ }
84
+ catch (error) {
85
+ throw new HTTPError("Exchange: failed to read token response", response.status, undefined, { cause: error });
86
+ }
87
+ if (!response.ok) {
88
+ throw new HTTPError(`Exchange: token request failed with status ${response.status}`, response.status, raw);
89
+ }
90
+ let parsed;
91
+ try {
92
+ parsed = JSON.parse(raw);
93
+ }
94
+ catch (error) {
95
+ throw new HTTPError("Exchange: failed to parse token response", response.status, raw, { cause: error });
96
+ }
97
+ if (typeof parsed !== "object" ||
98
+ parsed === null ||
99
+ Array.isArray(parsed)) {
100
+ throw new HTTPError("Exchange: token response must be a JSON object", response.status, raw);
101
+ }
102
+ return {
103
+ raw,
104
+ data: parsed,
105
+ };
106
+ }
107
+ validate() {
108
+ if (!this.provider) {
109
+ throw new Error("Provider cannot be null or undefined");
110
+ }
111
+ if (!this.config) {
112
+ throw new Error("Config cannot be null or undefined");
113
+ }
114
+ if (!this.provider.authURL().trim()) {
115
+ throw new Error("Provider authorization URL cannot be empty");
116
+ }
117
+ if (!this.provider.tokenURL().trim()) {
118
+ throw new Error("Provider token URL cannot be empty");
119
+ }
120
+ if (!this.config.clientID.trim()) {
121
+ throw new Error("Client ID cannot be empty");
122
+ }
123
+ if (!this.config.clientSecret.trim()) {
124
+ throw new Error("Client secret cannot be empty");
125
+ }
126
+ if (!this.config.redirectURL.trim()) {
127
+ throw new Error("Redirect URL cannot be empty");
128
+ }
129
+ if (this.config.clientAuthMethod !== undefined &&
130
+ !["client_secret_basic", "client_secret_post"].includes(this.config.clientAuthMethod)) {
131
+ throw new Error("Unsupported client authentication method");
132
+ }
133
+ }
134
+ }
135
+ //# sourceMappingURL=oauth2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth2.js","sourceRoot":"","sources":["../src/oauth2.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACH,WAAW,EACX,kBAAkB,GACrB,MAAM,aAAa,CAAC;AAErB,SAAS,eAAe,CAAC,KAAa;IAClC,OAAO,IAAI,eAAe,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;SACzC,QAAQ,EAAE;SACV,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,OAAO,MAAM;IAEH,QAAQ;IACR,MAAM;IAFlB,YACY,QAAkB,EAClB,MAAc;wBADd,QAAQ;sBACR,MAAM;QAEd,IAAI,CAAC,QAAQ,EAAE,CAAC;IACpB,CAAC;IAED,WAAW,CAAC,KAAa,EAAE,SAAkC;QACzD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAErC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAEpC,WAAW,CACP,kBAAkB,EAAE,EACpB,SAAS,IAAI,EAAE,EACf,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACX,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC,CACJ,CAAC;QAEF,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACf,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAE7C,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC1B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,WAAoC;QACrE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAErC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;QAE/C,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,EAAE,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,YAAoB,EAAE,WAAoC;QACjF,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAErC,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QAE1C,OAAO,IAAI,CAAC,QAAQ,CAChB,MAAM,EACN,kBAAkB,EAAE,EACpB,WAAW,CACd,CAAC;IACN,CAAC;IAEO,KAAK,CAAC,QAAQ,CAClB,MAAuB,EACvB,cAA2B,EAC3B,WAAoC;QAGpC,WAAW,CACP,cAAc,EACd,WAAW,IAAI,EAAE,EACjB,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACX,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC,CACJ,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,qBAAqB,CAAC;QAEzE,MAAM,OAAO,GAA2B;YACpC,cAAc,EAAE,mCAAmC;SACtD,CAAC;QAEF,IAAI,UAAU,KAAK,qBAAqB,EAAE,CAAC;YACvC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAC3B,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,EACvF,MAAM,CACT,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAErB,OAAO,CAAC,eAAe,CAAC,GAAG,SAAS,WAAW,EAAE,CAAC;QACtD,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,QAAkB,CAAC;QAEvB,IAAI,CAAC;YACD,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE;gBAC7C,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;aAC1B,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CACf,wCAAwC,EACxC,SAAS,EACT,SAAS,EACT,EAAE,KAAK,EAAE,KAAK,EAAE,CACnB,CAAC;QACN,CAAC;QAED,IAAI,GAAW,CAAC;QAEhB,IAAI,CAAC;YACD,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CACf,yCAAyC,EACzC,QAAQ,CAAC,MAAM,EACf,SAAS,EACT,EAAE,KAAK,EAAE,KAAK,EAAE,CACnB,CAAC;QACN,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,SAAS,CACf,8CAA8C,QAAQ,CAAC,MAAM,EAAE,EAC/D,QAAQ,CAAC,MAAM,EACf,GAAG,CACN,CAAC;QACN,CAAC;QAED,IAAI,MAAe,CAAC;QAEpB,IAAI,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CACf,0CAA0C,EAC1C,QAAQ,CAAC,MAAM,EACf,GAAG,EACH,EAAE,KAAK,EAAE,KAAK,EAAE,CACnB,CAAC;QACN,CAAC;QAED,IACI,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EACvB,CAAC;YACC,MAAM,IAAI,SAAS,CACf,gDAAgD,EAChD,QAAQ,CAAC,MAAM,EACf,GAAG,CACN,CAAC;QACN,CAAC;QAED,OAAO;YACH,GAAG;YACH,IAAI,EAAE,MAAiC;SAC1C,CAAC;IACN,CAAC;IAEO,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACpD,CAAC;QAED,IACI,IAAI,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS;YAC1C,CAAC,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,EACvF,CAAC;YACC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAChE,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,6 @@
1
+ type ParseParamsCallback = (key: string, value: string) => void;
2
+ export declare function baseReservedParams(): Set<string>;
3
+ export declare function extendReservedParams(extraReservedParams?: string[]): Set<string>;
4
+ export declare function parseParams(reservedParams: Set<string>, paramsData: Record<string, string>, callback: ParseParamsCallback): void;
5
+ export {};
6
+ //# sourceMappingURL=params.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAAA,KAAK,mBAAmB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAEhE,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,CAAC,CAWhD;AAED,wBAAgB,oBAAoB,CAAC,mBAAmB,GAAE,MAAM,EAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAQpF;AAED,wBAAgB,WAAW,CACvB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,EAAE,mBAAmB,GAC9B,IAAI,CAQN"}
package/dist/params.js ADDED
@@ -0,0 +1,28 @@
1
+ export function baseReservedParams() {
2
+ return new Set([
3
+ "client_id",
4
+ "client_secret",
5
+ "redirect_uri",
6
+ "code",
7
+ "refresh_token",
8
+ "state",
9
+ "response_type",
10
+ "grant_type"
11
+ ]);
12
+ }
13
+ export function extendReservedParams(extraReservedParams = []) {
14
+ const params = baseReservedParams();
15
+ for (const param of extraReservedParams) {
16
+ params.add(param);
17
+ }
18
+ return params;
19
+ }
20
+ export function parseParams(reservedParams, paramsData, callback) {
21
+ for (const [key, value] of Object.entries(paramsData)) {
22
+ if (reservedParams.has(key)) {
23
+ continue;
24
+ }
25
+ callback(key, value);
26
+ }
27
+ }
28
+ //# sourceMappingURL=params.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"params.js","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB;IAC9B,OAAO,IAAI,GAAG,CAAC;QACX,WAAW;QACX,eAAe;QACf,cAAc;QACd,MAAM;QACN,eAAe;QACf,OAAO;QACP,eAAe;QACf,YAAY;KACf,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,mBAAmB,GAAa,EAAE;IACnE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IAEpC,KAAK,MAAM,KAAK,IAAI,mBAAmB,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,WAAW,CACvB,cAA2B,EAC3B,UAAkC,EAClC,QAA6B;IAE7B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACpD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,SAAS;QACb,CAAC;QAED,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface Provider {
2
+ authURL(): string;
3
+ tokenURL(): string;
4
+ }
5
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACrB,OAAO,IAAI,MAAM,CAAC;IAClB,QAAQ,IAAI,MAAM,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export type ExchangeResponse = {
2
+ raw: string;
3
+ data: Record<string, unknown>;
4
+ };
5
+ //# sourceMappingURL=response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@o2js/core",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "A minimal, provider-agnostic OAuth 2.0 client for Node.js.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "keywords": [
23
+ "oauth",
24
+ "oauth2",
25
+ "oauth-2.0",
26
+ "authentication",
27
+ "authorization",
28
+ "node",
29
+ "typescript"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.json",
33
+ "test": "npm run build && node --test"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^26.6.6",
37
+ "typescript": "^7.0.2"
38
+ }
39
+ }