feeef 0.8.4 → 0.8.5
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 +73 -0
- package/build/index.js +101 -1
- package/build/index.js.map +1 -1
- package/build/src/feeef/feeef.d.ts +5 -0
- package/build/src/feeef/repositories/apps.d.ts +14 -0
- package/build/src/feeef/repositories/oauth.d.ts +77 -0
- package/build/src/feeef/repositories/orders.d.ts +3 -0
- package/build/src/feeef/repositories/promos.d.ts +7 -0
- package/build/src/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,3 +213,76 @@ interface ProductOffer {
|
|
|
213
213
|
## Contributing
|
|
214
214
|
|
|
215
215
|
Feel free to fork this repository and contribute improvements, bug fixes, or additional features. Open a pull request for any major changes!
|
|
216
|
+
|
|
217
|
+
## Developer OAuth (Authorization Code)
|
|
218
|
+
|
|
219
|
+
Use this flow when a third-party app (created in `apps`) needs user authorization.
|
|
220
|
+
|
|
221
|
+
### Endpoints
|
|
222
|
+
|
|
223
|
+
- Authorize: `GET /v1/oauth/authorize`
|
|
224
|
+
- Token: `POST /v1/oauth/token`
|
|
225
|
+
- Revoke: `POST /v1/oauth/revoke`
|
|
226
|
+
- Introspect: `POST /v1/oauth/introspect`
|
|
227
|
+
|
|
228
|
+
### Step-by-step (Google-like)
|
|
229
|
+
|
|
230
|
+
1. Build authorize URL:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { FeeeF, OAuthRepository } from 'feeef'
|
|
234
|
+
|
|
235
|
+
const feeef = new FeeeF({
|
|
236
|
+
apiKey: '<your_api_key>',
|
|
237
|
+
baseURL: 'https://api.feeef.org/v1',
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const authorizeUrl = OAuthRepository.buildAuthorizeUrl({
|
|
241
|
+
baseUrl: 'https://api.feeef.org/v1',
|
|
242
|
+
clientId: '<client_id>',
|
|
243
|
+
redirectUri: 'https://your-app.com/oauth/callback',
|
|
244
|
+
scope: ['*'], // or explicit scopes
|
|
245
|
+
state: crypto.randomUUID(),
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
2. Open `authorizeUrl` in browser.
|
|
250
|
+
3. If user is not signed in, API may return `401` with:
|
|
251
|
+
- `error: "login_required"`
|
|
252
|
+
- `login_url` (accounts sign-in URL with `next`)
|
|
253
|
+
4. Redirect user to `login_url`.
|
|
254
|
+
5. After sign-in + authorization, user is redirected to your callback with `code` (and `state`).
|
|
255
|
+
6. Exchange `code` for token:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
const tokenResponse = await feeef.oauth.exchangeAuthorizationCode({
|
|
259
|
+
code: '<code_from_callback>',
|
|
260
|
+
redirectUri: 'https://your-app.com/oauth/callback',
|
|
261
|
+
clientId: '<client_id>',
|
|
262
|
+
clientSecret: '<client_secret>',
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
await feeef.oauth.revokeToken(tokenResponse.access_token)
|
|
266
|
+
|
|
267
|
+
const introspection = await feeef.oauth.introspectToken(tokenResponse.access_token)
|
|
268
|
+
console.log(introspection.active)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Alternative static helper:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { OAuthRepository } from 'feeef'
|
|
275
|
+
|
|
276
|
+
const authorizeUrl = OAuthRepository.buildAuthorizeUrl({
|
|
277
|
+
baseUrl: 'https://api.feeef.org/v1',
|
|
278
|
+
clientId: '<client_id>',
|
|
279
|
+
redirectUri: 'https://your-app.com/oauth/callback',
|
|
280
|
+
})
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Important
|
|
284
|
+
|
|
285
|
+
- `redirect_uri` must exactly match one of the app's registered redirect URIs.
|
|
286
|
+
- Keep `client_secret` server-side only.
|
|
287
|
+
- Always validate `state` on callback.
|
|
288
|
+
- Prefer PKCE (`code_challenge`, `code_verifier`) for public clients.
|
package/build/index.js
CHANGED
|
@@ -141,7 +141,12 @@ var OrderRepository = class extends ModelRepository {
|
|
|
141
141
|
if (options.page) params.page = options.page;
|
|
142
142
|
if (options.offset) params.offset = options.offset;
|
|
143
143
|
if (options.limit) params.limit = options.limit;
|
|
144
|
-
|
|
144
|
+
const useMultiStore = options.storeIds != null && options.storeIds.length > 0;
|
|
145
|
+
if (useMultiStore) {
|
|
146
|
+
params.store_ids = options.storeIds;
|
|
147
|
+
} else if (options.storeId) {
|
|
148
|
+
params.store_id = options.storeId;
|
|
149
|
+
}
|
|
145
150
|
if (options.status) {
|
|
146
151
|
params.status = Array.isArray(options.status) ? options.status : [options.status];
|
|
147
152
|
}
|
|
@@ -841,6 +846,14 @@ var AppRepository = class extends ModelRepository {
|
|
|
841
846
|
}
|
|
842
847
|
/**
|
|
843
848
|
* Builds the OAuth authorize URL to which the user should be redirected.
|
|
849
|
+
* This is the first step of the authorization-code flow (similar UX to Google OAuth).
|
|
850
|
+
*
|
|
851
|
+
* If the user is not logged in yet, API `GET /oauth/authorize` returns:
|
|
852
|
+
* - `401 login_required`
|
|
853
|
+
* - `login_url` (accounts sign-in URL with `next=...`)
|
|
854
|
+
*
|
|
855
|
+
* The client should navigate to `login_url`, let the user sign in, and then
|
|
856
|
+
* continue by opening the original authorize URL again (or rely on `next`).
|
|
844
857
|
*
|
|
845
858
|
* @param params - Parameters for the authorize URL.
|
|
846
859
|
* @param params.baseUrl - API base URL (e.g. https://api.feeef.org/api/v1).
|
|
@@ -869,6 +882,79 @@ var AppRepository = class extends ModelRepository {
|
|
|
869
882
|
}
|
|
870
883
|
};
|
|
871
884
|
|
|
885
|
+
// src/feeef/repositories/oauth.ts
|
|
886
|
+
var OAuthRepository = class {
|
|
887
|
+
client;
|
|
888
|
+
constructor(client) {
|
|
889
|
+
this.client = client;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Builds the authorize URL for browser redirect.
|
|
893
|
+
*/
|
|
894
|
+
static buildAuthorizeUrl(params) {
|
|
895
|
+
const base = params.baseUrl.endsWith("/") ? params.baseUrl : `${params.baseUrl}/`;
|
|
896
|
+
const url = new URL("oauth/authorize", base);
|
|
897
|
+
url.searchParams.set("client_id", params.clientId);
|
|
898
|
+
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
899
|
+
url.searchParams.set("response_type", "code");
|
|
900
|
+
if (params.scope?.length) url.searchParams.set("scope", params.scope.join(" "));
|
|
901
|
+
if (params.state) url.searchParams.set("state", params.state);
|
|
902
|
+
if (params.codeChallenge) url.searchParams.set("code_challenge", params.codeChallenge);
|
|
903
|
+
if (params.codeChallengeMethod) {
|
|
904
|
+
url.searchParams.set("code_challenge_method", params.codeChallengeMethod);
|
|
905
|
+
}
|
|
906
|
+
return url.toString();
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Exchanges an authorization code for an access token.
|
|
910
|
+
*/
|
|
911
|
+
async exchangeAuthorizationCode(params) {
|
|
912
|
+
const body = new URLSearchParams({
|
|
913
|
+
grant_type: "authorization_code",
|
|
914
|
+
code: params.code,
|
|
915
|
+
redirect_uri: params.redirectUri,
|
|
916
|
+
client_id: params.clientId,
|
|
917
|
+
client_secret: params.clientSecret
|
|
918
|
+
});
|
|
919
|
+
if (params.codeVerifier) {
|
|
920
|
+
body.set("code_verifier", params.codeVerifier);
|
|
921
|
+
}
|
|
922
|
+
const response = await this.client.post("/oauth/token", body.toString(), {
|
|
923
|
+
headers: {
|
|
924
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
return response.data;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Revokes an OAuth token.
|
|
931
|
+
*/
|
|
932
|
+
async revokeToken(token, tokenTypeHint) {
|
|
933
|
+
const body = new URLSearchParams({ token });
|
|
934
|
+
if (tokenTypeHint) {
|
|
935
|
+
body.set("token_type_hint", tokenTypeHint);
|
|
936
|
+
}
|
|
937
|
+
const response = await this.client.post("/oauth/revoke", body.toString(), {
|
|
938
|
+
headers: {
|
|
939
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
return response.data;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Introspects an OAuth token.
|
|
946
|
+
*/
|
|
947
|
+
async introspectToken(token) {
|
|
948
|
+
const body = new URLSearchParams({ token });
|
|
949
|
+
const response = await this.client.post("/oauth/introspect", body.toString(), {
|
|
950
|
+
headers: {
|
|
951
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
return response.data;
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
|
|
872
958
|
// src/feeef/repositories/deposits.ts
|
|
873
959
|
var DepositRepository = class extends ModelRepository {
|
|
874
960
|
/**
|
|
@@ -1017,9 +1103,17 @@ var PromoRepository = class {
|
|
|
1017
1103
|
if (params?.page != null) query.page = params.page;
|
|
1018
1104
|
if (params?.limit != null) query.limit = params.limit;
|
|
1019
1105
|
if (params?.validNow === true) query.validNow = "1";
|
|
1106
|
+
if (params?.filterator) query.filterator = params.filterator;
|
|
1020
1107
|
const res = await this.client.get("/promos", { params: query });
|
|
1021
1108
|
return res.data;
|
|
1022
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Fetches a single promo by id.
|
|
1112
|
+
*/
|
|
1113
|
+
async find(params) {
|
|
1114
|
+
const res = await this.client.get(`/promos/${params.id}`);
|
|
1115
|
+
return res.data;
|
|
1116
|
+
}
|
|
1023
1117
|
/**
|
|
1024
1118
|
* Validates a promo code. Returns validation result with discount info or reason.
|
|
1025
1119
|
*/
|
|
@@ -3513,6 +3607,10 @@ var FeeeF = class {
|
|
|
3513
3607
|
* The repository for managing developer-registered apps (OAuth clients).
|
|
3514
3608
|
*/
|
|
3515
3609
|
apps;
|
|
3610
|
+
/**
|
|
3611
|
+
* The repository for OAuth2 authorize/token/revoke/introspect operations.
|
|
3612
|
+
*/
|
|
3613
|
+
oauth;
|
|
3516
3614
|
/**
|
|
3517
3615
|
* The repository for managing orders.
|
|
3518
3616
|
*/
|
|
@@ -3604,6 +3702,7 @@ var FeeeF = class {
|
|
|
3604
3702
|
this.imageGenerations = new ImageGenerationsRepository(this.client);
|
|
3605
3703
|
this.users = new UserRepository(this.client);
|
|
3606
3704
|
this.apps = new AppRepository(this.client);
|
|
3705
|
+
this.oauth = new OAuthRepository(this.client);
|
|
3607
3706
|
this.orders = new OrderRepository(this.client);
|
|
3608
3707
|
this.deposits = new DepositRepository(this.client);
|
|
3609
3708
|
this.transfers = new TransferRepository(this.client);
|
|
@@ -4067,6 +4166,7 @@ export {
|
|
|
4067
4166
|
ModelRepository,
|
|
4068
4167
|
NoestDeliveryIntegrationApi,
|
|
4069
4168
|
NotificationsService,
|
|
4169
|
+
OAuthRepository,
|
|
4070
4170
|
OrderRepository,
|
|
4071
4171
|
OrderStatus,
|
|
4072
4172
|
PaymentStatus,
|