appstore-connect-sdk 1.2.0 → 1.3.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/dist/main.js CHANGED
@@ -47,6 +47,135 @@ var Configuration = class {
47
47
  }
48
48
  };
49
49
  var DefaultConfig = new Configuration();
50
+ var BaseAPI = class {
51
+ constructor(configuration = DefaultConfig) {
52
+ this.configuration = configuration;
53
+ this.fetchApi = async (url, init) => {
54
+ let fetchParams = { url, init };
55
+ for (const middleware of this.middleware) {
56
+ if (middleware.pre) {
57
+ fetchParams = await middleware.pre({
58
+ fetch: this.fetchApi,
59
+ ...fetchParams
60
+ }) || fetchParams;
61
+ }
62
+ }
63
+ let response = void 0;
64
+ try {
65
+ response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);
66
+ } catch (e) {
67
+ for (const middleware of this.middleware) {
68
+ if (middleware.onError) {
69
+ response = await middleware.onError({
70
+ fetch: this.fetchApi,
71
+ url: fetchParams.url,
72
+ init: fetchParams.init,
73
+ error: e,
74
+ response: response ? response.clone() : void 0
75
+ }) || response;
76
+ }
77
+ }
78
+ if (response === void 0) {
79
+ if (e instanceof Error) {
80
+ throw new FetchError(e, "The request failed and the interceptors did not return an alternative response");
81
+ } else {
82
+ throw e;
83
+ }
84
+ }
85
+ }
86
+ for (const middleware of this.middleware) {
87
+ if (middleware.post) {
88
+ response = await middleware.post({
89
+ fetch: this.fetchApi,
90
+ url: fetchParams.url,
91
+ init: fetchParams.init,
92
+ response: response.clone()
93
+ }) || response;
94
+ }
95
+ }
96
+ return response;
97
+ };
98
+ this.middleware = configuration.middleware;
99
+ }
100
+ withMiddleware(...middlewares) {
101
+ const next = this.clone();
102
+ next.middleware = next.middleware.concat(...middlewares);
103
+ return next;
104
+ }
105
+ withPreMiddleware(...preMiddlewares) {
106
+ const middlewares = preMiddlewares.map((pre) => ({ pre }));
107
+ return this.withMiddleware(...middlewares);
108
+ }
109
+ withPostMiddleware(...postMiddlewares) {
110
+ const middlewares = postMiddlewares.map((post) => ({ post }));
111
+ return this.withMiddleware(...middlewares);
112
+ }
113
+ async request(context, initOverrides) {
114
+ const { url, init } = await this.createFetchParams(context, initOverrides);
115
+ const response = await this.fetchApi(url, init);
116
+ if (response && (response.status >= 200 && response.status < 300)) {
117
+ return response;
118
+ }
119
+ throw new ResponseError(response, "Response returned an error code");
120
+ }
121
+ async createFetchParams(context, initOverrides) {
122
+ let url = this.configuration.basePath + context.path;
123
+ if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
124
+ url += "?" + this.configuration.queryParamsStringify(context.query);
125
+ }
126
+ const headers = Object.assign({}, this.configuration.headers, context.headers);
127
+ Object.keys(headers).forEach((key) => headers[key] === void 0 ? delete headers[key] : {});
128
+ const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
129
+ const initParams = {
130
+ method: context.method,
131
+ headers,
132
+ body: context.body,
133
+ credentials: this.configuration.credentials
134
+ };
135
+ const overriddenInit = {
136
+ ...initParams,
137
+ ...await initOverrideFn({
138
+ init: initParams,
139
+ context
140
+ })
141
+ };
142
+ const init = {
143
+ ...overriddenInit,
144
+ body: isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body) ? overriddenInit.body : JSON.stringify(overriddenInit.body)
145
+ };
146
+ return { url, init };
147
+ }
148
+ /**
149
+ * Create a shallow clone of `this` by constructing a new instance
150
+ * and then shallow cloning data members.
151
+ */
152
+ clone() {
153
+ const constructor = this.constructor;
154
+ const next = new constructor(this.configuration);
155
+ next.middleware = this.middleware.slice();
156
+ return next;
157
+ }
158
+ };
159
+ function isBlob(value) {
160
+ return typeof Blob !== "undefined" && value instanceof Blob;
161
+ }
162
+ function isFormData(value) {
163
+ return typeof FormData !== "undefined" && value instanceof FormData;
164
+ }
165
+ var ResponseError = class extends Error {
166
+ constructor(response, msg) {
167
+ super(msg);
168
+ this.response = response;
169
+ this.name = "ResponseError";
170
+ }
171
+ };
172
+ var FetchError = class extends Error {
173
+ constructor(cause, msg) {
174
+ super(msg);
175
+ this.cause = cause;
176
+ this.name = "FetchError";
177
+ }
178
+ };
50
179
  function querystring(params, prefix = "") {
51
180
  return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
52
181
  }
@@ -907,11 +1036,12 @@ async function generateAuthToken({ apiKeyId, issuerId, privateKey, expirationTim
907
1036
  kid: apiKeyId,
908
1037
  // The type of the token (JWT)
909
1038
  typ: "JWT"
910
- }).setIssuer(issuerId).setAudience("appstoreconnect-v1").setExpirationTime(expirationTime ?? (/* @__PURE__ */ new Date()).getTime() / 1e3).sign(key);
1039
+ }).setIssuer(issuerId).setAudience("appstoreconnect-v1").setExpirationTime(expirationTime).sign(key);
911
1040
  return token;
912
1041
  }
913
1042
 
914
1043
  // src/main.ts
1044
+ var DEFAULT_EXPIRATION_DURATION_SECONDS = 60 * 20;
915
1045
  var AppStoreConnectAPI = class {
916
1046
  /**
917
1047
  * Creates an instance of the AppStoreConnectAPI.
@@ -921,13 +1051,15 @@ var AppStoreConnectAPI = class {
921
1051
  * @param options.privateKey - The content of the private key used for generating JWT token.
922
1052
  * @param options.fetchApi - (Optional) The FetchAPI implementation to use for API requests.
923
1053
  * @param options.bearerToken - (Optional) A pre-generated bearer token to use for authentication.
924
- * @param options.expirationTime - (Optional) The time (in seconds) until the token expires (default 10 minutes)
1054
+ * @param options.expirationDuration - (Optional) The expiration duration for the bearer token in seconds (default 20 minutes).
925
1055
  * @param options.basePath - (Optional) The base path for the API (without trailing slash, default https://api.appstoreconnect.apple.com).
926
1056
  * @throws {string} Will throw an error if no bearerToken or private key is provided
927
1057
  */
928
1058
  constructor(options) {
1059
+ /**
1060
+ * The time (in milliseconds) when the current bearer token was generated.
1061
+ */
929
1062
  this.bearerTokenGeneratedAt = 0;
930
- if (options.expirationTime) options.expirationTime = options.expirationTime;
931
1063
  this.options = options;
932
1064
  }
933
1065
  /**
@@ -936,16 +1068,16 @@ var AppStoreConnectAPI = class {
936
1068
  async genToken() {
937
1069
  if (this.options.bearerToken) {
938
1070
  return this.options.bearerToken;
939
- } else if (this.options.privateKeyId && this.options.issuerId && this.options.privateKey) {
1071
+ }
1072
+ if (this.options.privateKeyId && this.options.issuerId && this.options.privateKey) {
940
1073
  return await generateAuthToken({
941
1074
  apiKeyId: this.options.privateKeyId,
942
1075
  issuerId: this.options.issuerId,
943
1076
  privateKey: this.options.privateKey,
944
- expirationTime: this.options.expirationTime
1077
+ expirationTime: Math.floor(Date.now() / 1e3) + (this.options.expirationDuration ?? DEFAULT_EXPIRATION_DURATION_SECONDS)
945
1078
  });
946
- } else {
947
- throw "No bearerToken!!!";
948
1079
  }
1080
+ throw "No bearerToken or private key provided";
949
1081
  }
950
1082
  /**
951
1083
  * Create a Configuration object with the authentication token and any provided FetchAPI implementation.
@@ -964,7 +1096,9 @@ var AppStoreConnectAPI = class {
964
1096
  * Returns the current bearer token, generating a new one if necessary.
965
1097
  */
966
1098
  async getConfiguration() {
967
- const hasExpired = this.bearerTokenGeneratedAt && Date.now() - this.bearerTokenGeneratedAt > 1e3 * this.options.expirationTime;
1099
+ const latestBearerTokenDuration = this.bearerTokenGeneratedAt ? Date.now() - this.bearerTokenGeneratedAt : 0;
1100
+ const expirationDurationMs = 1e3 * (this.options.expirationDuration ?? DEFAULT_EXPIRATION_DURATION_SECONDS);
1101
+ const hasExpired = latestBearerTokenDuration > expirationDurationMs;
968
1102
  if (!this.configuration || hasExpired) {
969
1103
  await this.genConfiguration();
970
1104
  }
@@ -978,6 +1112,39 @@ var AppStoreConnectAPI = class {
978
1112
  async create(apiClass) {
979
1113
  return new apiClass(await this.getConfiguration());
980
1114
  }
1115
+ /**
1116
+ * Makes an API request.
1117
+ * @param context - The request context for the API request.
1118
+ * @param initOverrides - (Optional) The request options to use for the API request.
1119
+ * @returns The response from the API request.
1120
+ */
1121
+ async request(context, initOverrides) {
1122
+ if (!context.url && !context.path) {
1123
+ throw new Error("No url or path provided");
1124
+ }
1125
+ const _context = { ...context };
1126
+ if (!_context.path && _context.url) {
1127
+ if (_context.url.startsWith(BASE_PATH)) {
1128
+ _context.path = _context.url.replace(BASE_PATH, "");
1129
+ } else {
1130
+ throw new Error("url must start with " + BASE_PATH);
1131
+ }
1132
+ }
1133
+ if (!_context.method) {
1134
+ _context.method = "GET";
1135
+ }
1136
+ delete _context.url;
1137
+ const globalApi = new GlobalAPI(await this.getConfiguration());
1138
+ return await globalApi.request(_context, initOverrides);
1139
+ }
1140
+ };
1141
+ var GlobalAPI = class extends BaseAPI {
1142
+ constructor(configuration) {
1143
+ super(configuration);
1144
+ }
1145
+ request(context, initOverrides) {
1146
+ return super.request(context, initOverrides);
1147
+ }
981
1148
  };
982
1149
  export {
983
1150
  AppStoreConnectAPI