@tigeropenapi/tigeropen 0.5.4 → 0.5.7

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.
Files changed (73) hide show
  1. package/README.md +80 -0
  2. package/dist/cjs/auth/authentication.js +74 -0
  3. package/dist/cjs/auth/index.js +24 -0
  4. package/dist/cjs/auth/oauth2/client-registration.js +44 -0
  5. package/dist/cjs/auth/oauth2/device-authorization.js +40 -0
  6. package/dist/cjs/auth/oauth2/errors.js +64 -0
  7. package/dist/cjs/auth/oauth2/http-utils.js +112 -0
  8. package/dist/cjs/auth/oauth2/index.js +42 -0
  9. package/dist/cjs/auth/oauth2/loopback-receiver.js +215 -0
  10. package/dist/cjs/auth/oauth2/metadata.js +34 -0
  11. package/dist/cjs/auth/oauth2/oauth2-authentication.js +74 -0
  12. package/dist/cjs/auth/oauth2/session-manager.js +762 -0
  13. package/dist/cjs/auth/oauth2/token-store.js +252 -0
  14. package/dist/cjs/auth/oauth2/token.js +76 -0
  15. package/dist/cjs/push/index.js +1 -0
  16. package/dist/cjs/push/pb/Request.js +12 -1
  17. package/dist/cjs/push/proto-message.js +5 -1
  18. package/dist/cjs/push/push-client.js +34 -16
  19. package/dist/cjs/push/tick-util.js +172 -0
  20. package/dist/cjs/quote/quote-client.js +59 -12
  21. package/dist/cjs/trade/trade-client.js +55 -6
  22. package/dist/cjs/version.js +1 -1
  23. package/dist/esm/auth/authentication.js +68 -0
  24. package/dist/esm/auth/index.js +3 -0
  25. package/dist/esm/auth/oauth2/client-registration.js +40 -0
  26. package/dist/esm/auth/oauth2/device-authorization.js +36 -0
  27. package/dist/esm/auth/oauth2/errors.js +59 -0
  28. package/dist/esm/auth/oauth2/http-utils.js +105 -0
  29. package/dist/esm/auth/oauth2/index.js +11 -0
  30. package/dist/esm/auth/oauth2/loopback-receiver.js +178 -0
  31. package/dist/esm/auth/oauth2/metadata.js +30 -0
  32. package/dist/esm/auth/oauth2/oauth2-authentication.js +70 -0
  33. package/dist/esm/auth/oauth2/session-manager.js +725 -0
  34. package/dist/esm/auth/oauth2/token-store.js +214 -0
  35. package/dist/esm/auth/oauth2/token.js +71 -0
  36. package/dist/esm/package.json +3 -0
  37. package/dist/esm/push/index.js +1 -0
  38. package/dist/esm/push/pb/Request.js +12 -1
  39. package/dist/esm/push/proto-message.js +5 -1
  40. package/dist/esm/push/push-client.js +34 -16
  41. package/dist/esm/push/tick-util.js +165 -0
  42. package/dist/esm/quote/quote-client.js +59 -12
  43. package/dist/esm/trade/trade-client.js +55 -6
  44. package/dist/esm/version.js +1 -1
  45. package/dist/types/auth/authentication.d.ts +98 -0
  46. package/dist/types/auth/index.d.ts +4 -0
  47. package/dist/types/auth/oauth2/client-registration.d.ts +32 -0
  48. package/dist/types/auth/oauth2/device-authorization.d.ts +40 -0
  49. package/dist/types/auth/oauth2/errors.d.ts +46 -0
  50. package/dist/types/auth/oauth2/http-utils.d.ts +21 -0
  51. package/dist/types/auth/oauth2/index.d.ts +16 -0
  52. package/dist/types/auth/oauth2/loopback-receiver.d.ts +29 -0
  53. package/dist/types/auth/oauth2/metadata.d.ts +32 -0
  54. package/dist/types/auth/oauth2/oauth2-authentication.d.ts +31 -0
  55. package/dist/types/auth/oauth2/session-manager.d.ts +241 -0
  56. package/dist/types/auth/oauth2/token-store.d.ts +49 -0
  57. package/dist/types/auth/oauth2/token.d.ts +56 -0
  58. package/dist/types/index.d.ts +2 -2
  59. package/dist/types/model/order.d.ts +62 -11
  60. package/dist/types/model/quote-requests.d.ts +21 -2
  61. package/dist/types/model/quote.d.ts +72 -14
  62. package/dist/types/model/trade-requests.d.ts +17 -4
  63. package/dist/types/model/trade.d.ts +11 -1
  64. package/dist/types/push/callbacks.d.ts +3 -7
  65. package/dist/types/push/index.d.ts +2 -1
  66. package/dist/types/push/pb/Request.d.ts +1 -0
  67. package/dist/types/push/proto-message.d.ts +4 -1
  68. package/dist/types/push/push-client.d.ts +33 -0
  69. package/dist/types/push/tick-util.d.ts +30 -0
  70. package/dist/types/quote/quote-client.d.ts +27 -6
  71. package/dist/types/trade/trade-client.d.ts +27 -3
  72. package/dist/types/version.d.ts +1 -1
  73. package/package.json +8 -4
package/README.md CHANGED
@@ -276,10 +276,24 @@ pc.disconnect();
276
276
  | `subscribeFuture(symbols)` | Futures quotes | `onFuture(QuoteData)` |
277
277
  | `subscribeKline(symbols)` | K-line data | `onKline(KlineData)` |
278
278
  | `subscribeAsset(account?)` | Asset changes | `onAsset(AssetData)` |
279
+ | `subscribeAsset(options)` | Asset changes, `{ account?, assetQuoteType? }` | `onAsset(AssetData)` |
279
280
  | `subscribePosition(account?)` | Position changes | `onPosition(PositionData)` |
281
+ | `subscribePosition(options)` | Position changes, `{ account?, assetQuoteType? }` | `onPosition(PositionData)` |
280
282
  | `subscribeOrder(account?)` | Order status | `onOrder(OrderStatusData)` |
281
283
  | `subscribeTransaction(account?)` | Transactions | `onTransaction(OrderTransactionData)` |
282
284
 
285
+ `assetQuoteType` selects the quote basis of the pushed asset / position data —
286
+ `'ETH'`, `'RTH'` or `'OVERNIGHT'`. Omit it to keep the server default.
287
+
288
+ ```typescript
289
+ pc.subscribeAsset({ assetQuoteType: 'OVERNIGHT' });
290
+ pc.subscribePosition({ account: 'U1234567', assetQuoteType: 'RTH' });
291
+ ```
292
+
293
+ The same enum name is accepted as `assetQuoteType` on the HTTP side by
294
+ `getPositions` / `getAssets` / `getPrimeAssets` / `getAggregateAssets`
295
+ (wire name `asset_quote_type`).
296
+
283
297
  ## Project Structure
284
298
 
285
299
  ```
@@ -486,8 +500,61 @@ const chain = await qc.optionChain('AAPL', '2024-01-19');
486
500
 
487
501
  // 期货交易所
488
502
  const exchanges = await qc.futureExchange();
503
+
504
+ // 逐笔成交
505
+ const ticks = await qc.getTradeTick({ symbols: ['AAPL'] });
506
+ // ticks[0].items[i].partCode — 交易所短名,如 "NYSE"、"NSDQ"
507
+ // ticks[0].items[i].partName — 交易所全名,如 "New York Stock Exchange, LLC (NYSE)"
508
+ // ticks[0].items[i].cond — 已转换的成交条件,如 "US_REGULAR_SALE",参见下方说明
489
509
  ```
490
510
 
511
+ ### 逐笔成交 `cond` 字段说明
512
+
513
+ `trade_tick` 接口和 push 层返回的 `cond` 字段已由 SDK 转换为可读字符串,含义如下:
514
+
515
+ **美股(US)**
516
+
517
+ | 字符 | 含义 |
518
+ |------|------|
519
+ | ` `(空格)| 常规交易(Regular Sale) |
520
+ | `B` | 批量交易(Bunched Trade) |
521
+ | `C` | 现金交易(Cash Trade) |
522
+ | `F` | 跨市场交易(Intermarket Sweep) |
523
+ | `G` | 批量卖出(Bunched Sold Trade) |
524
+ | `H` | 离价交易(Price Variation Trade) |
525
+ | `I` | 碎股交易(Odd Lot Trade) |
526
+ | `K` | 纽交所第 127/155 条交易 |
527
+ | `L` | 延迟交易(Sold Last) |
528
+ | `M` | 中央收市价(Market Center Close Price) |
529
+ | `N` | 隔日交易(Next Day Trade) |
530
+ | `O` | 中央开盘价交易(Market Center Opening Trade) |
531
+ | `P` | 前参考价(Prior Reference Price) |
532
+ | `Q` | 中央开盘价(Market Center Open Price) |
533
+ | `R` | 卖方(Seller) |
534
+ | `T` | 盘前盘后交易(Form T) |
535
+ | `U` | 延长交易时段(Extended Trading Hours) |
536
+ | `V` | 合单交易(Contingent Trade) |
537
+ | `W` | 均价交易(Average Price Trade) |
538
+ | `X` | 跨市场交易(Cross Trade) |
539
+ | `Z` | 场外售出(Sold Out of Sequence) |
540
+ | `4` | 衍生工具定价(Derivatively Priced) |
541
+ | `7` | 合单交易(Qualified Contingent Trade) |
542
+
543
+ **港股(HK)**
544
+
545
+ | 字符 | 含义 |
546
+ |------|------|
547
+ | ` `(空格)| 自动对盘(Automatch Normal) |
548
+ | `D` | 碎股交易(Odd Lot Trade) |
549
+ | `U` | 竞价交易(Auction Trade) |
550
+ | `*` | 场外交易(Overseas Trade) |
551
+ | `P` | 开市前成交(Late Trade Off Exchange) |
552
+ | `M` | 非自动对盘(Non-Direct Off Exchange Trade) |
553
+ | `X` | 同券商自动对盘(Direct Off Exchange Trade) |
554
+ | `Y` | 同券商非自动对盘(Automatic Internalized) |
555
+
556
+ 如上表所示,`cond` 值因市场(美股/港股)不同而有所区别。
557
+
491
558
  ## 交易
492
559
 
493
560
  ```typescript
@@ -599,10 +666,23 @@ pc.disconnect();
599
666
  | `subscribeFuture(symbols)` | 期货行情 | `onFuture(QuoteData)` |
600
667
  | `subscribeKline(symbols)` | K 线数据 | `onKline(KlineData)` |
601
668
  | `subscribeAsset(account?)` | 资产变动 | `onAsset(AssetData)` |
669
+ | `subscribeAsset(options)` | 资产变动,`{ account?, assetQuoteType? }` | `onAsset(AssetData)` |
602
670
  | `subscribePosition(account?)` | 持仓变动 | `onPosition(PositionData)` |
671
+ | `subscribePosition(options)` | 持仓变动,`{ account?, assetQuoteType? }` | `onPosition(PositionData)` |
603
672
  | `subscribeOrder(account?)` | 订单状态 | `onOrder(OrderStatusData)` |
604
673
  | `subscribeTransaction(account?)` | 成交明细 | `onTransaction(OrderTransactionData)` |
605
674
 
675
+ `assetQuoteType` 用于选择推送的资产/持仓行情口径,取值为枚举名
676
+ `'ETH'` / `'RTH'` / `'OVERNIGHT'`,不传则用服务端默认值。
677
+
678
+ ```typescript
679
+ pc.subscribeAsset({ assetQuoteType: 'OVERNIGHT' });
680
+ pc.subscribePosition({ account: 'U1234567', assetQuoteType: 'RTH' });
681
+ ```
682
+
683
+ 拉取侧 `getPositions` / `getAssets` / `getPrimeAssets` / `getAggregateAssets`
684
+ 同样接受 `assetQuoteType` 字段(wire 名 `asset_quote_type`)。
685
+
606
686
  ## 项目结构
607
687
 
608
688
  ```
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Request authentication interfaces.
4
+ *
5
+ * Implementations attach credentials, handle authentication retries, and release
6
+ * resources. OAuth 2.0 authorization flows live in `OAuth2SessionManager`; this module
7
+ * is the data plane and knows nothing about login.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.RetryDecision = exports.AuthenticationAttempt = exports.RequestAuthContext = exports.AuthenticationType = void 0;
11
+ /** Which kind of authentication. */
12
+ var AuthenticationType;
13
+ (function (AuthenticationType) {
14
+ /** tigerId + RSA private key signature */
15
+ AuthenticationType["Signature"] = "SIGNATURE";
16
+ /** `Authorization: Bearer <access_token>` */
17
+ AuthenticationType["OAuth2"] = "OAUTH2";
18
+ })(AuthenticationType || (exports.AuthenticationType = AuthenticationType = {}));
19
+ /**
20
+ * Per-request authentication context.
21
+ *
22
+ * Business parameters (`method`, `version`, `biz_content`, `timestamp`) are filled in by
23
+ * the client and must not be modified by an authentication implementation.
24
+ */
25
+ class RequestAuthContext {
26
+ constructor(params, retryable = true) {
27
+ this.params = params;
28
+ this.retryable = retryable;
29
+ }
30
+ }
31
+ exports.RequestAuthContext = RequestAuthContext;
32
+ /**
33
+ * Credential snapshot used to coordinate authentication retries.
34
+ *
35
+ * Comparing the failed credential with current state detects rotation completed
36
+ * elsewhere and avoids duplicate refresh requests.
37
+ */
38
+ class AuthenticationAttempt {
39
+ constructor(authType, credential) {
40
+ this.authType = authType;
41
+ this.credential = credential;
42
+ }
43
+ /** Never prints the credential value. */
44
+ toString() {
45
+ return `AuthenticationAttempt{type=${this.authType}, credential=${this.credential === undefined ? '<none>' : '***'}}`;
46
+ }
47
+ }
48
+ exports.AuthenticationAttempt = AuthenticationAttempt;
49
+ /**
50
+ * Authentication retry decision.
51
+ *
52
+ * A retry always supplies a new full `Authorization` header value, including the
53
+ * `Bearer ` prefix. There is deliberately no "retry with the same credential" option:
54
+ * that only collects the same 401 twice.
55
+ */
56
+ class RetryDecision {
57
+ constructor(shouldRetry, authorizationHeader) {
58
+ this.shouldRetry = shouldRetry;
59
+ this.authorizationHeader = authorizationHeader;
60
+ }
61
+ static noRetry() {
62
+ return RetryDecision.NO_RETRY;
63
+ }
64
+ /** @param authorizationHeader full new header value, including `Bearer ` */
65
+ static retry(authorizationHeader) {
66
+ return new RetryDecision(true, authorizationHeader);
67
+ }
68
+ /** Never prints the header value. */
69
+ toString() {
70
+ return `RetryDecision{shouldRetry=${this.shouldRetry}}`;
71
+ }
72
+ }
73
+ exports.RetryDecision = RetryDecision;
74
+ RetryDecision.NO_RETRY = new RetryDecision(false, undefined);
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.RetryDecision = exports.RequestAuthContext = exports.AuthenticationType = exports.AuthenticationAttempt = void 0;
18
+ /** Authentication layer: the request-level data plane plus the OAuth 2.0 control plane. */
19
+ var authentication_1 = require("./authentication");
20
+ Object.defineProperty(exports, "AuthenticationAttempt", { enumerable: true, get: function () { return authentication_1.AuthenticationAttempt; } });
21
+ Object.defineProperty(exports, "AuthenticationType", { enumerable: true, get: function () { return authentication_1.AuthenticationType; } });
22
+ Object.defineProperty(exports, "RequestAuthContext", { enumerable: true, get: function () { return authentication_1.RequestAuthContext; } });
23
+ Object.defineProperty(exports, "RetryDecision", { enumerable: true, get: function () { return authentication_1.RetryDecision; } });
24
+ __exportStar(require("./oauth2"), exports);
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * OAuth 2.0 dynamic client registration state (RFC 7591).
4
+ *
5
+ * Registration state is stored separately from tokens and retained across logout.
6
+ * `registeredScopes` records the granted scope set; scope expansion requires a new
7
+ * registration to avoid `invalid_scope`.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.OAuth2ClientRegistration = void 0;
11
+ class OAuth2ClientRegistration {
12
+ constructor(init = {}) {
13
+ this.issuer = init.issuer;
14
+ this.clientId = init.clientId;
15
+ this.clientName = init.clientName;
16
+ this.registeredScopes = init.registeredScopes;
17
+ this.clientIdIssuedAt = init.clientIdIssuedAt ?? 0;
18
+ }
19
+ toJSON() {
20
+ return {
21
+ issuer: this.issuer,
22
+ client_id: this.clientId,
23
+ client_name: this.clientName,
24
+ registered_scopes: this.registeredScopes,
25
+ client_id_issued_at: this.clientIdIssuedAt,
26
+ };
27
+ }
28
+ static fromJSON(data) {
29
+ if (!data)
30
+ return null;
31
+ return new OAuth2ClientRegistration({
32
+ issuer: data.issuer,
33
+ clientId: data.client_id,
34
+ clientName: data.client_name,
35
+ registeredScopes: data.registered_scopes,
36
+ clientIdIssuedAt: data.client_id_issued_at ?? 0,
37
+ });
38
+ }
39
+ toString() {
40
+ return `OAuth2ClientRegistration{issuer=${this.issuer}, clientId=${this.clientId}, `
41
+ + `clientName=${this.clientName}, registeredScopes=${this.registeredScopes}}`;
42
+ }
43
+ }
44
+ exports.OAuth2ClientRegistration = OAuth2ClientRegistration;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /** Device authorization response (RFC 8628). */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.OAuth2DeviceAuthorization = exports.DEFAULT_DEVICE_INTERVAL_SECONDS = void 0;
5
+ /**
6
+ * Default polling interval per RFC 8628 §3.5. Tiger's authorization server does not
7
+ * return `interval`, so this default applies in practice.
8
+ */
9
+ exports.DEFAULT_DEVICE_INTERVAL_SECONDS = 5;
10
+ class OAuth2DeviceAuthorization {
11
+ constructor(init = {}) {
12
+ this.deviceCode = init.deviceCode;
13
+ this.userCode = init.userCode;
14
+ this.verificationUri = init.verificationUri;
15
+ this.verificationUriComplete = init.verificationUriComplete;
16
+ this.expiresIn = init.expiresIn ?? 0;
17
+ this.interval = init.interval ?? 0;
18
+ }
19
+ effectiveIntervalSeconds() {
20
+ return this.interval > 0 ? this.interval : exports.DEFAULT_DEVICE_INTERVAL_SECONDS;
21
+ }
22
+ static fromJSON(data) {
23
+ if (!data)
24
+ return null;
25
+ return new OAuth2DeviceAuthorization({
26
+ deviceCode: data.device_code,
27
+ userCode: data.user_code,
28
+ verificationUri: data.verification_uri,
29
+ verificationUriComplete: data.verification_uri_complete,
30
+ expiresIn: data.expires_in ?? 0,
31
+ interval: data.interval ?? 0,
32
+ });
33
+ }
34
+ /** Prints no deviceCode. */
35
+ toString() {
36
+ return `OAuth2DeviceAuthorization{userCode=${this.userCode}, verificationUri=${this.verificationUri}, `
37
+ + `expiresIn=${this.expiresIn}, interval=${this.interval}}`;
38
+ }
39
+ }
40
+ exports.OAuth2DeviceAuthorization = OAuth2DeviceAuthorization;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Categorized errors from OAuth 2.0 authorization flows.
4
+ *
5
+ * Authorization server error details are retained in the error message.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.RejectedGrantError = exports.OAuth2Error = exports.OAuth2Category = void 0;
9
+ /** Error category. Each one implies a different action. */
10
+ var OAuth2Category;
11
+ (function (OAuth2Category) {
12
+ /** Cannot fetch authorization server metadata: wrong address, service down, no network */
13
+ OAuth2Category["MetadataUnavailable"] = "METADATA_UNAVAILABLE";
14
+ /** No usable client_id, and automatic registration is not possible */
15
+ OAuth2Category["ClientRegistrationRequired"] = "CLIENT_REGISTRATION_REQUIRED";
16
+ /** Callback stage failed: timeout, user denial, or state mismatch */
17
+ OAuth2Category["CallbackFailed"] = "CALLBACK_FAILED";
18
+ /**
19
+ * Device flow not approved in time, or explicitly denied. Kept separate from
20
+ * ReauthorizationRequired because only a new device authorization is needed -- the
21
+ * stored token was not touched.
22
+ */
23
+ OAuth2Category["DeviceAuthorizationFailed"] = "DEVICE_AUTHORIZATION_FAILED";
24
+ /** refresh_token expired, revoked, or never obtained. Retrying is pointless */
25
+ OAuth2Category["ReauthorizationRequired"] = "REAUTHORIZATION_REQUIRED";
26
+ /** Token endpoint call failed, and not in the terminal way above */
27
+ OAuth2Category["TokenRequestFailed"] = "TOKEN_REQUEST_FAILED";
28
+ /** Reading or writing the local token file failed */
29
+ OAuth2Category["StorageFailed"] = "STORAGE_FAILED";
30
+ })(OAuth2Category || (exports.OAuth2Category = OAuth2Category = {}));
31
+ /** Thrown by any stage of the OAuth2 flow. */
32
+ class OAuth2Error extends Error {
33
+ constructor(category, message, cause) {
34
+ super(message);
35
+ this.name = 'OAuth2Error';
36
+ this.category = category;
37
+ this.cause = cause;
38
+ }
39
+ get reauthorizationRequired() {
40
+ return this.category === OAuth2Category.ReauthorizationRequired;
41
+ }
42
+ toString() {
43
+ return `OAuth2Error{${this.category}: ${this.message}}`;
44
+ }
45
+ }
46
+ exports.OAuth2Error = OAuth2Error;
47
+ /**
48
+ * A grant the authorization server refused.
49
+ *
50
+ * Carries the error code so a caller can tell a rejected credential from a rejected
51
+ * client registration. Its category is `ReauthorizationRequired`, so callers that only
52
+ * know the public type behave as they would for any terminal authorization failure.
53
+ */
54
+ class RejectedGrantError extends OAuth2Error {
55
+ constructor(error, description) {
56
+ super(OAuth2Category.ReauthorizationRequired, `token request rejected: ${error} ${description}`);
57
+ this.name = 'RejectedGrantError';
58
+ this.error = error;
59
+ }
60
+ get isClientRejected() {
61
+ return this.error === 'invalid_client';
62
+ }
63
+ }
64
+ exports.RejectedGrantError = RejectedGrantError;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.READ_TIMEOUT_SECONDS = exports.CONNECT_TIMEOUT_SECONDS = void 0;
4
+ exports.getJson = getJson;
5
+ exports.postJson = postJson;
6
+ exports.postForm = postForm;
7
+ exports.postFormForStatus = postFormForStatus;
8
+ /**
9
+ * HTTP helpers for OAuth 2.0 JSON and form-encoded requests.
10
+ *
11
+ * OAuth error responses retain 4xx response bodies for protocol-level error handling.
12
+ */
13
+ const errors_1 = require("./errors");
14
+ /**
15
+ * Every call here is a small JSON exchange with the authorization server, so a request
16
+ * that has not answered in this long is not going to. Same values as the Java and
17
+ * Python SDKs.
18
+ */
19
+ exports.CONNECT_TIMEOUT_SECONDS = 5;
20
+ exports.READ_TIMEOUT_SECONDS = 10;
21
+ /** Combined budget handed to `AbortSignal.timeout`; fetch does not split the two. */
22
+ const REQUEST_TIMEOUT_MS = (exports.CONNECT_TIMEOUT_SECONDS + exports.READ_TIMEOUT_SECONDS) * 1000;
23
+ const JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
24
+ const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8';
25
+ function encodeForm(form) {
26
+ const params = new URLSearchParams();
27
+ for (const [key, value] of Object.entries(form)) {
28
+ if (value !== undefined && value !== null) {
29
+ params.append(key, value);
30
+ }
31
+ }
32
+ return params.toString();
33
+ }
34
+ async function getJson(url) {
35
+ return execute('GET', url, undefined, undefined);
36
+ }
37
+ async function postJson(url, payload) {
38
+ return execute('POST', url, JSON.stringify(payload), JSON_CONTENT_TYPE);
39
+ }
40
+ async function postForm(url, form) {
41
+ return execute('POST', url, encodeForm(form), FORM_CONTENT_TYPE);
42
+ }
43
+ /**
44
+ * Post a form and return the HTTP status without requiring a response body.
45
+ *
46
+ * RFC 7009 revocation returns an empty success body, so no parsing is performed.
47
+ *
48
+ * @returns the HTTP status code
49
+ * @throws OAuth2Error on connection failure
50
+ */
51
+ async function postFormForStatus(url, form) {
52
+ let response;
53
+ try {
54
+ response = await fetch(url, {
55
+ method: 'POST',
56
+ headers: { Accept: 'application/json', 'Content-Type': FORM_CONTENT_TYPE },
57
+ body: encodeForm(form),
58
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
59
+ });
60
+ }
61
+ catch (e) {
62
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.TokenRequestFailed, `request fail: ${url}`, e);
63
+ }
64
+ return response.status;
65
+ }
66
+ /**
67
+ * Send the request and parse the response body as an object.
68
+ *
69
+ * A 4xx returns its body instead of throwing: OAuth2 errors (`invalid_grant`,
70
+ * `authorization_pending` and friends) live in the 4xx body, and the caller needs the
71
+ * `error` field to tell "wait and retry" from "re-authorize". Only a connection failure
72
+ * or a non-JSON response throws.
73
+ */
74
+ async function execute(method, url, body, contentType) {
75
+ const headers = { Accept: 'application/json' };
76
+ if (contentType) {
77
+ headers['Content-Type'] = contentType;
78
+ }
79
+ let response;
80
+ try {
81
+ response = await fetch(url, {
82
+ method,
83
+ headers,
84
+ body,
85
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
86
+ });
87
+ }
88
+ catch (e) {
89
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.MetadataUnavailable, `request fail: ${url}`, e);
90
+ }
91
+ let text;
92
+ try {
93
+ text = await response.text();
94
+ }
95
+ catch (e) {
96
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.TokenRequestFailed, `cannot decode response from ${url}, http status ${response.status}`, e);
97
+ }
98
+ if (!text) {
99
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.TokenRequestFailed, `empty response from ${url}, http status ${response.status}`);
100
+ }
101
+ let parsed;
102
+ try {
103
+ parsed = JSON.parse(text);
104
+ }
105
+ catch (e) {
106
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.TokenRequestFailed, `non-JSON response from ${url}, http status ${response.status}`, e);
107
+ }
108
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
109
+ throw new errors_1.OAuth2Error(errors_1.OAuth2Category.TokenRequestFailed, `unexpected response from ${url}, http status ${response.status}`);
110
+ }
111
+ return parsed;
112
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.READ_TIMEOUT_SECONDS = exports.CONNECT_TIMEOUT_SECONDS = exports.hashIssuer = exports.ENV_HOME = exports.DEFAULT_SURFACE = exports.OAuth2TokenStore = exports.currentMillis = exports.TOKEN_SCHEMA_VERSION = exports.OAuth2Token = exports.MIN_USABLE_REMAINING_MILLIS = exports.ENV_ISSUER = exports.DEFAULT_REFRESH_AHEAD_MILLIS = exports.DEFAULT_MANUAL_CALLBACK_PORT = exports.DEFAULT_AUTHORIZE_TIMEOUT_SECONDS = exports.CLIENT_NAME = exports.BUILTIN_ISSUER = exports.OAuth2SessionManager = exports.BEARER_PREFIX = exports.OAuth2Authentication = exports.OAuth2Metadata = exports.CALLBACK_PATH = exports.LoopbackReceiver = exports.RejectedGrantError = exports.OAuth2Error = exports.OAuth2Category = exports.DEFAULT_DEVICE_INTERVAL_SECONDS = exports.OAuth2DeviceAuthorization = exports.OAuth2ClientRegistration = void 0;
4
+ /** OAuth 2.0 authentication, authorization flows, and token persistence. */
5
+ var client_registration_1 = require("./client-registration");
6
+ Object.defineProperty(exports, "OAuth2ClientRegistration", { enumerable: true, get: function () { return client_registration_1.OAuth2ClientRegistration; } });
7
+ var device_authorization_1 = require("./device-authorization");
8
+ Object.defineProperty(exports, "OAuth2DeviceAuthorization", { enumerable: true, get: function () { return device_authorization_1.OAuth2DeviceAuthorization; } });
9
+ Object.defineProperty(exports, "DEFAULT_DEVICE_INTERVAL_SECONDS", { enumerable: true, get: function () { return device_authorization_1.DEFAULT_DEVICE_INTERVAL_SECONDS; } });
10
+ var errors_1 = require("./errors");
11
+ Object.defineProperty(exports, "OAuth2Category", { enumerable: true, get: function () { return errors_1.OAuth2Category; } });
12
+ Object.defineProperty(exports, "OAuth2Error", { enumerable: true, get: function () { return errors_1.OAuth2Error; } });
13
+ Object.defineProperty(exports, "RejectedGrantError", { enumerable: true, get: function () { return errors_1.RejectedGrantError; } });
14
+ var loopback_receiver_1 = require("./loopback-receiver");
15
+ Object.defineProperty(exports, "LoopbackReceiver", { enumerable: true, get: function () { return loopback_receiver_1.LoopbackReceiver; } });
16
+ Object.defineProperty(exports, "CALLBACK_PATH", { enumerable: true, get: function () { return loopback_receiver_1.CALLBACK_PATH; } });
17
+ var metadata_1 = require("./metadata");
18
+ Object.defineProperty(exports, "OAuth2Metadata", { enumerable: true, get: function () { return metadata_1.OAuth2Metadata; } });
19
+ var oauth2_authentication_1 = require("./oauth2-authentication");
20
+ Object.defineProperty(exports, "OAuth2Authentication", { enumerable: true, get: function () { return oauth2_authentication_1.OAuth2Authentication; } });
21
+ Object.defineProperty(exports, "BEARER_PREFIX", { enumerable: true, get: function () { return oauth2_authentication_1.BEARER_PREFIX; } });
22
+ var session_manager_1 = require("./session-manager");
23
+ Object.defineProperty(exports, "OAuth2SessionManager", { enumerable: true, get: function () { return session_manager_1.OAuth2SessionManager; } });
24
+ Object.defineProperty(exports, "BUILTIN_ISSUER", { enumerable: true, get: function () { return session_manager_1.BUILTIN_ISSUER; } });
25
+ Object.defineProperty(exports, "CLIENT_NAME", { enumerable: true, get: function () { return session_manager_1.CLIENT_NAME; } });
26
+ Object.defineProperty(exports, "DEFAULT_AUTHORIZE_TIMEOUT_SECONDS", { enumerable: true, get: function () { return session_manager_1.DEFAULT_AUTHORIZE_TIMEOUT_SECONDS; } });
27
+ Object.defineProperty(exports, "DEFAULT_MANUAL_CALLBACK_PORT", { enumerable: true, get: function () { return session_manager_1.DEFAULT_MANUAL_CALLBACK_PORT; } });
28
+ Object.defineProperty(exports, "DEFAULT_REFRESH_AHEAD_MILLIS", { enumerable: true, get: function () { return session_manager_1.DEFAULT_REFRESH_AHEAD_MILLIS; } });
29
+ Object.defineProperty(exports, "ENV_ISSUER", { enumerable: true, get: function () { return session_manager_1.ENV_ISSUER; } });
30
+ Object.defineProperty(exports, "MIN_USABLE_REMAINING_MILLIS", { enumerable: true, get: function () { return session_manager_1.MIN_USABLE_REMAINING_MILLIS; } });
31
+ var token_1 = require("./token");
32
+ Object.defineProperty(exports, "OAuth2Token", { enumerable: true, get: function () { return token_1.OAuth2Token; } });
33
+ Object.defineProperty(exports, "TOKEN_SCHEMA_VERSION", { enumerable: true, get: function () { return token_1.TOKEN_SCHEMA_VERSION; } });
34
+ Object.defineProperty(exports, "currentMillis", { enumerable: true, get: function () { return token_1.currentMillis; } });
35
+ var token_store_1 = require("./token-store");
36
+ Object.defineProperty(exports, "OAuth2TokenStore", { enumerable: true, get: function () { return token_store_1.OAuth2TokenStore; } });
37
+ Object.defineProperty(exports, "DEFAULT_SURFACE", { enumerable: true, get: function () { return token_store_1.DEFAULT_SURFACE; } });
38
+ Object.defineProperty(exports, "ENV_HOME", { enumerable: true, get: function () { return token_store_1.ENV_HOME; } });
39
+ Object.defineProperty(exports, "hashIssuer", { enumerable: true, get: function () { return token_store_1.hashIssuer; } });
40
+ var http_utils_1 = require("./http-utils");
41
+ Object.defineProperty(exports, "CONNECT_TIMEOUT_SECONDS", { enumerable: true, get: function () { return http_utils_1.CONNECT_TIMEOUT_SECONDS; } });
42
+ Object.defineProperty(exports, "READ_TIMEOUT_SECONDS", { enumerable: true, get: function () { return http_utils_1.READ_TIMEOUT_SECONDS; } });