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 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
- if (options.storeId) params.store_id = options.storeId;
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,