@forge/os 1.1.3 → 1.2.0-next.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.
@@ -1,5 +1,6 @@
1
1
  export declare const errorCodes: {
2
2
  readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
3
3
  readonly APP_NOT_ENABLED: "APP_NOT_ENABLED";
4
+ readonly RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
4
5
  };
5
6
  //# sourceMappingURL=errorCodes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorCodes.d.ts","sourceRoot":"","sources":["../src/errorCodes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;CAGb,CAAC"}
1
+ {"version":3,"file":"errorCodes.d.ts","sourceRoot":"","sources":["../src/errorCodes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;CAIb,CAAC"}
package/out/errorCodes.js CHANGED
@@ -3,5 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.errorCodes = void 0;
4
4
  exports.errorCodes = {
5
5
  UNKNOWN_ERROR: 'UNKNOWN_ERROR',
6
- APP_NOT_ENABLED: 'APP_NOT_ENABLED'
6
+ APP_NOT_ENABLED: 'APP_NOT_ENABLED',
7
+ RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED'
7
8
  };
@@ -28,7 +28,7 @@ describe('error-handling', () => {
28
28
  });
29
29
  await expect((0, error_handling_1.checkResponseError)(mockResponse)).resolves.toBeUndefined();
30
30
  });
31
- describe('Forge errors - ForgeObjectStoreError', () => {
31
+ describe('Forge errors - ForgeObjectStoreAPIError', () => {
32
32
  const message = 'A test error has occurred';
33
33
  const code = 'ERROR_CODE';
34
34
  it('should return a ForgeObjectStoreError when response body is a Forge error', async () => {
@@ -37,22 +37,11 @@ describe('error-handling', () => {
37
37
  statusText: 'Bad Request',
38
38
  headers: { 'x-trace-id': traceId }
39
39
  });
40
- try {
41
- await (0, error_handling_1.checkResponseError)(mockResponse);
42
- throw new Error('Expected error to be thrown');
43
- }
44
- catch (error) {
45
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
46
- expect(error).toMatchObject({
47
- responseDetails: {
48
- status: 400,
49
- statusText: 'Bad Request',
50
- traceId
51
- },
52
- code,
53
- message
54
- });
55
- }
40
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
41
+ status: 400,
42
+ statusText: 'Bad Request',
43
+ traceId
44
+ }, { code, message }));
56
45
  });
57
46
  it('should include context if present in the Forge error', async () => {
58
47
  const context = { key: 'value' };
@@ -61,23 +50,11 @@ describe('error-handling', () => {
61
50
  statusText: 'Bad Request',
62
51
  headers: { 'x-trace-id': traceId }
63
52
  });
64
- try {
65
- await (0, error_handling_1.checkResponseError)(mockResponse);
66
- throw new Error('Expected error to be thrown');
67
- }
68
- catch (error) {
69
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
70
- expect(error).toMatchObject({
71
- code,
72
- message,
73
- context,
74
- responseDetails: {
75
- status: 400,
76
- statusText: 'Bad Request',
77
- traceId
78
- }
79
- });
80
- }
53
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
54
+ status: 400,
55
+ statusText: 'Bad Request',
56
+ traceId
57
+ }, { code, message, context }));
81
58
  });
82
59
  it('should include top level additional fields if present in the Forge error', async () => {
83
60
  const extraFields = { extraValue: 'value', debug: true };
@@ -86,23 +63,11 @@ describe('error-handling', () => {
86
63
  statusText: 'Bad Request',
87
64
  headers: { 'x-trace-id': traceId }
88
65
  });
89
- try {
90
- await (0, error_handling_1.checkResponseError)(mockResponse);
91
- throw new Error('Expected error to be thrown');
92
- }
93
- catch (error) {
94
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
95
- expect(error).toMatchObject({
96
- code,
97
- message,
98
- context: extraFields,
99
- responseDetails: {
100
- status: 400,
101
- statusText: 'Bad Request',
102
- traceId
103
- }
104
- });
105
- }
66
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
67
+ status: 400,
68
+ statusText: 'Bad Request',
69
+ traceId
70
+ }, { code, message, context: extraFields }));
106
71
  });
107
72
  it('should merge context and additional top level fields if both present in the Forge error', async () => {
108
73
  const context = { key: 'value' };
@@ -112,49 +77,28 @@ describe('error-handling', () => {
112
77
  statusText: 'Bad Request',
113
78
  headers: { 'x-trace-id': traceId }
114
79
  });
115
- try {
116
- await (0, error_handling_1.checkResponseError)(mockResponse);
117
- throw new Error('Expected error to be thrown');
118
- }
119
- catch (error) {
120
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
121
- expect(error).toMatchObject({
122
- code,
123
- message,
124
- context: { ...context, ...extraFields },
125
- responseDetails: {
126
- status: 400,
127
- statusText: 'Bad Request',
128
- traceId
129
- }
130
- });
131
- }
80
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toThrowError(new errors_1.ForgeObjectStoreAPIError({
81
+ status: 400,
82
+ statusText: 'Bad Request',
83
+ traceId
84
+ }, { code, message, context: { ...context, ...extraFields } }));
132
85
  });
133
- describe('Handle non forge errors - UNKNOWN_ERROR', () => {
134
- it('returns an when no response body', async () => {
86
+ describe('Handle non forge errors', () => {
87
+ it('returns an UNKNOWN_ERROR when no response body', async () => {
135
88
  const mockResponse = new node_fetch_1.Response(undefined, {
136
89
  status: 404,
137
90
  statusText: 'Not Found',
138
91
  headers: { 'x-trace-id': traceId }
139
92
  });
140
- try {
141
- await (0, error_handling_1.checkResponseError)(mockResponse);
142
- throw new Error('Expected error to be thrown');
143
- }
144
- catch (error) {
145
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
146
- expect(error).toMatchObject({
147
- code: errorCodes_1.errorCodes.UNKNOWN_ERROR,
148
- context: {
149
- responseText: ''
150
- },
151
- responseDetails: {
152
- traceId,
153
- status: 404,
154
- statusText: 'Not Found'
155
- }
156
- });
157
- }
93
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
94
+ status: 404,
95
+ statusText: 'Not Found',
96
+ traceId
97
+ }, {
98
+ code: errorCodes_1.errorCodes.UNKNOWN_ERROR,
99
+ context: { responseText: '' },
100
+ message: 'Unexpected error in Forge SQL API request'
101
+ }));
158
102
  });
159
103
  it("returns UNKNOWN_ERROR if there is a JSON body that isn't a forge error", async () => {
160
104
  const body = JSON.stringify({ not: 'a forge error' });
@@ -163,24 +107,30 @@ describe('error-handling', () => {
163
107
  statusText: 'Internal Server Error',
164
108
  headers: { 'x-trace-id': traceId }
165
109
  });
166
- try {
167
- await (0, error_handling_1.checkResponseError)(mockResponse);
168
- throw new Error('Expected error to be thrown');
169
- }
170
- catch (error) {
171
- expect(error).toBeInstanceOf(errors_1.ForgeObjectStoreError);
172
- expect(error).toMatchObject({
173
- code: errorCodes_1.errorCodes.UNKNOWN_ERROR,
174
- context: {
175
- responseText: body
176
- },
177
- responseDetails: {
178
- traceId,
179
- status: 500,
180
- statusText: 'Internal Server Error'
181
- }
182
- });
183
- }
110
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
111
+ status: 500,
112
+ statusText: 'Internal Server Error',
113
+ traceId
114
+ }, {
115
+ code: errorCodes_1.errorCodes.UNKNOWN_ERROR,
116
+ context: { responseText: body },
117
+ message: 'Unexpected error in Forge SQL API request'
118
+ }));
119
+ });
120
+ it('returns RATE_LIMIT_EXCEEDED when status is 429', async () => {
121
+ const mockResponse = new node_fetch_1.Response(undefined, {
122
+ status: 429,
123
+ statusText: 'Rate Limit Exceeded',
124
+ headers: { 'x-trace-id': traceId }
125
+ });
126
+ await expect(async () => await (0, error_handling_1.checkResponseError)(mockResponse)).rejects.toMatchError(new errors_1.ForgeObjectStoreAPIError({
127
+ status: 429,
128
+ statusText: 'Rate Limit Exceeded',
129
+ traceId
130
+ }, {
131
+ code: errorCodes_1.errorCodes.RATE_LIMIT_EXCEEDED,
132
+ message: 'You have exceeded the rate limits for OS. Please wait and try again later.'
133
+ }));
184
134
  });
185
135
  });
186
136
  });
@@ -1 +1 @@
1
- {"version":3,"file":"error-handling.d.ts","sourceRoot":"","sources":["../../src/utils/error-handling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAA2B,UAAU,EAA4B,MAAM,WAAW,CAAC;AAG1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAE9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAMnE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/F"}
1
+ {"version":3,"file":"error-handling.d.ts","sourceRoot":"","sources":["../../src/utils/error-handling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAA2B,UAAU,EAA4B,MAAM,WAAW,CAAC;AAG1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAE9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAMnE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
@@ -30,6 +30,12 @@ async function checkResponseError(response, message) {
30
30
  statusText: response.statusText,
31
31
  traceId: extractTraceId(response)
32
32
  };
33
+ if (details.status === 429) {
34
+ throw new errors_1.ForgeObjectStoreAPIError(details, {
35
+ code: errorCodes_1.errorCodes.RATE_LIMIT_EXCEEDED,
36
+ message: 'You have exceeded the rate limits for OS. Please wait and try again later.'
37
+ });
38
+ }
33
39
  const parsedBody = safeGetParsedBody(responseText);
34
40
  if (parsedBody && isForgeError(parsedBody)) {
35
41
  throw new errors_1.ForgeObjectStoreAPIError(details, parsedBody);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/os",
3
- "version": "1.1.3",
3
+ "version": "1.2.0-next.0",
4
4
  "description": "Forge Object Store SDK",
5
5
  "author": "Atlassian",
6
6
  "license": "UNLICENSED",