@forge/realtime 0.0.7-next.0 → 0.1.0-next.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @forge/realtime
2
2
 
3
+ ## 0.1.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 4242274: Adds new signRealtimeToken method to the forge realtime package
8
+
3
9
  ## 0.0.7-next.0
4
10
 
5
11
  ### Patch Changes
@@ -4,6 +4,29 @@ const tslib_1 = require("tslib");
4
4
  const runtime = tslib_1.__importStar(require("../runtime"));
5
5
  const publish_1 = require("../publish");
6
6
  const utils_1 = require("./utils");
7
+ const TEST_EVENT_ID = 'event-id';
8
+ const TEST_EVENT_TIMESTAMP = '1234567890';
9
+ const MOCK_FETCH_RESPONSE = {
10
+ errors: [],
11
+ data: {
12
+ ecosystem: {
13
+ publishRealtimeChannel: {
14
+ eventId: TEST_EVENT_ID,
15
+ eventTimestamp: TEST_EVENT_TIMESTAMP
16
+ },
17
+ success: true
18
+ }
19
+ }
20
+ };
21
+ const MOCK_ERRORS = [
22
+ {
23
+ message: 'Error message',
24
+ extensions: {
25
+ errorType: 'Error type',
26
+ statusCode: 500
27
+ }
28
+ }
29
+ ];
7
30
  describe('publish', () => {
8
31
  beforeEach(() => {
9
32
  jest.restoreAllMocks();
@@ -12,26 +35,26 @@ describe('publish', () => {
12
35
  it('should publish an event with FCT in header', async () => {
13
36
  jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
14
37
  const mockForgeFetch = jest.fn().mockResolvedValue({
15
- text: jest.fn().mockResolvedValue('Hello Magic'),
38
+ json: jest.fn().mockResolvedValue(MOCK_FETCH_RESPONSE),
16
39
  status: 200,
17
40
  headers: { get: jest.fn().mockReturnValue(undefined) }
18
41
  });
19
42
  global.__forge_fetch__ = mockForgeFetch;
20
43
  const response = await (0, publish_1.publish)('my-channel', 'this is an event payload');
21
- expect(response.status).toBe(200);
44
+ expect(response).toEqual({ eventId: TEST_EVENT_ID, eventTimestamp: TEST_EVENT_TIMESTAMP });
22
45
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
23
46
  });
24
47
  it('should publish an event when the payload is an object', async () => {
25
48
  jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
26
49
  const mockForgeFetch = jest.fn().mockResolvedValue({
27
- text: jest.fn().mockResolvedValue('Hello Magic'),
50
+ json: jest.fn().mockResolvedValue(MOCK_FETCH_RESPONSE),
28
51
  status: 200,
29
52
  headers: { get: jest.fn().mockReturnValue(undefined) }
30
53
  });
31
54
  global.__forge_fetch__ = mockForgeFetch;
32
55
  const payload = { value: 'this is a test payload', funLevel: 100 };
33
56
  const response = await (0, publish_1.publish)('my-channel', JSON.stringify(payload));
34
- expect(response.status).toBe(200);
57
+ expect(response).toEqual({ eventId: TEST_EVENT_ID, eventTimestamp: TEST_EVENT_TIMESTAMP });
35
58
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
36
59
  });
37
60
  it('should throw an error when Forge Outbound Proxy returns an error', async () => {
@@ -47,6 +70,26 @@ describe('publish', () => {
47
70
  await expect(response).rejects.toThrow('Forge platform failed to process runtime HTTP request - 502 - UPSTREAM_FAILURE');
48
71
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
49
72
  });
73
+ it('should return null eventId and eventTimestamp when the response has errors', async () => {
74
+ jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
75
+ const mockForgeFetch = jest.fn().mockResolvedValue({
76
+ json: jest.fn().mockResolvedValue({
77
+ errors: MOCK_ERRORS,
78
+ data: {
79
+ ecosystem: {
80
+ publishRealtimeChannel: null,
81
+ }
82
+ }
83
+ }),
84
+ status: 200,
85
+ headers: { get: jest.fn().mockReturnValue(undefined) }
86
+ });
87
+ global.__forge_fetch__ = mockForgeFetch;
88
+ const payload = { value: 'this is a test payload', funLevel: 100 };
89
+ const response = await (0, publish_1.publish)('my-channel', JSON.stringify(payload));
90
+ expect(response).toEqual({ eventId: null, eventTimestamp: null, errors: MOCK_ERRORS });
91
+ expect(mockForgeFetch.mock.calls).toMatchSnapshot();
92
+ });
50
93
  });
51
94
  describe('publishGlobal', () => {
52
95
  beforeEach(() => {
@@ -56,26 +99,26 @@ describe('publishGlobal', () => {
56
99
  it('should publish an event', async () => {
57
100
  jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
58
101
  const mockForgeFetch = jest.fn().mockResolvedValue({
59
- text: jest.fn().mockResolvedValue('Hello Magic'),
102
+ json: jest.fn().mockResolvedValue(MOCK_FETCH_RESPONSE),
60
103
  status: 200,
61
104
  headers: { get: jest.fn().mockReturnValue(undefined) }
62
105
  });
63
106
  global.__forge_fetch__ = mockForgeFetch;
64
107
  const response = await (0, publish_1.publishGlobal)('my-channel', 'this is an event payload');
65
- expect(response.status).toBe(200);
108
+ expect(response).toEqual({ eventId: TEST_EVENT_ID, eventTimestamp: TEST_EVENT_TIMESTAMP });
66
109
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
67
110
  });
68
111
  it('should publish an event when the payload is an object', async () => {
69
112
  jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
70
113
  const mockForgeFetch = jest.fn().mockResolvedValue({
71
- text: jest.fn().mockResolvedValue('Hello Magic'),
114
+ json: jest.fn().mockResolvedValue(MOCK_FETCH_RESPONSE),
72
115
  status: 200,
73
116
  headers: { get: jest.fn().mockReturnValue(undefined) }
74
117
  });
75
118
  global.__forge_fetch__ = mockForgeFetch;
76
119
  const payload = { value: 'this is a test payload', funLevel: 100 };
77
120
  const response = await (0, publish_1.publishGlobal)('my-channel', JSON.stringify(payload));
78
- expect(response.status).toBe(200);
121
+ expect(response).toEqual({ eventId: TEST_EVENT_ID, eventTimestamp: TEST_EVENT_TIMESTAMP });
79
122
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
80
123
  });
81
124
  it('should throw an error when Forge Outbound Proxy returns an error', async () => {
@@ -91,4 +134,24 @@ describe('publishGlobal', () => {
91
134
  await expect(response).rejects.toThrow('Forge platform failed to process runtime HTTP request - 502 - UPSTREAM_FAILURE');
92
135
  expect(mockForgeFetch.mock.calls).toMatchSnapshot();
93
136
  });
137
+ it('should return null eventId and eventTimestamp when the response has errors', async () => {
138
+ jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
139
+ const mockForgeFetch = jest.fn().mockResolvedValue({
140
+ json: jest.fn().mockResolvedValue({
141
+ errors: MOCK_ERRORS,
142
+ data: {
143
+ ecosystem: {
144
+ publishRealtimeChannel: null,
145
+ }
146
+ }
147
+ }),
148
+ status: 200,
149
+ headers: { get: jest.fn().mockReturnValue(undefined) }
150
+ });
151
+ global.__forge_fetch__ = mockForgeFetch;
152
+ const payload = { value: 'this is a test payload', funLevel: 100 };
153
+ const response = await (0, publish_1.publishGlobal)('my-channel', JSON.stringify(payload));
154
+ expect(response).toEqual({ eventId: null, eventTimestamp: null, errors: MOCK_ERRORS });
155
+ expect(mockForgeFetch.mock.calls).toMatchSnapshot();
156
+ });
94
157
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=signRealtimeToken.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signRealtimeToken.test.d.ts","sourceRoot":"","sources":["../../src/__test__/signRealtimeToken.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const runtime = tslib_1.__importStar(require("../runtime"));
5
+ const signRealtimeToken_1 = require("../signRealtimeToken");
6
+ const utils_1 = require("./utils");
7
+ const TEST_TOKEN = 'jwt-token';
8
+ const TEST_EXPIRES_AT = '1234567890';
9
+ const MOCK_ERRORS = [
10
+ {
11
+ message: 'Error message',
12
+ extensions: {
13
+ errorType: 'Error type',
14
+ statusCode: 500
15
+ }
16
+ }
17
+ ];
18
+ describe('signRealtimeToken', () => {
19
+ beforeEach(() => {
20
+ jest.restoreAllMocks();
21
+ jest.resetAllMocks();
22
+ });
23
+ it('should send a signRealtimeToken request and recieve a jwt and expiresAt', async () => {
24
+ jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
25
+ const mockForgeFetch = jest.fn().mockResolvedValue({
26
+ json: jest.fn().mockResolvedValue({
27
+ errors: [],
28
+ data: {
29
+ ecosystem: {
30
+ signRealtimeToken: {
31
+ errors: [],
32
+ forgeRealtimeToken: {
33
+ jwt: TEST_TOKEN,
34
+ expiresAt: TEST_EXPIRES_AT
35
+ },
36
+ success: true
37
+ }
38
+ }
39
+ }
40
+ }),
41
+ status: 200,
42
+ headers: { get: jest.fn().mockReturnValue(undefined) }
43
+ });
44
+ global.__forge_fetch__ = mockForgeFetch;
45
+ const response = await (0, signRealtimeToken_1.signRealtimeToken)('my-channel', { 'test-key': 'test-value' });
46
+ expect(response).toEqual({ jwt: TEST_TOKEN, expiresAt: TEST_EXPIRES_AT });
47
+ expect(mockForgeFetch.mock.calls).toMatchSnapshot();
48
+ });
49
+ it('should throw an error when Forge Outbound Proxy returns an error', async () => {
50
+ jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
51
+ const mockForgeFetch = jest.fn().mockResolvedValue({
52
+ text: jest.fn().mockResolvedValue('Error occurred'),
53
+ status: 502,
54
+ headers: { get: jest.fn().mockReturnValue('UPSTREAM_FAILURE') }
55
+ });
56
+ global.__forge_fetch__ = mockForgeFetch;
57
+ const response = (0, signRealtimeToken_1.signRealtimeToken)('my-channel', { 'test-key': 'test-value' });
58
+ await expect(response).rejects.toThrow('Forge platform failed to process runtime HTTP request - 502 - UPSTREAM_FAILURE');
59
+ expect(mockForgeFetch.mock.calls).toMatchSnapshot();
60
+ });
61
+ it('should send generic error when errors are returned', async () => {
62
+ jest.spyOn(runtime, '__getRuntime').mockReturnValue(utils_1.FORGE_RUNTIME);
63
+ const mockForgeFetch = jest.fn().mockResolvedValue({
64
+ json: jest.fn().mockResolvedValue({
65
+ errors: MOCK_ERRORS,
66
+ data: {
67
+ ecosystem: {
68
+ signRealtimeToken: null,
69
+ }
70
+ }
71
+ }),
72
+ status: 200,
73
+ headers: { get: jest.fn().mockReturnValue(undefined) }
74
+ });
75
+ global.__forge_fetch__ = mockForgeFetch;
76
+ const response = await (0, signRealtimeToken_1.signRealtimeToken)('my-channel', { 'test-key': 'test-value' });
77
+ expect(response).toEqual({ jwt: null, expiresAt: null, errors: MOCK_ERRORS });
78
+ expect(mockForgeFetch.mock.calls).toMatchSnapshot();
79
+ });
80
+ });
package/out/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { publish, publishGlobal } from './publish';
2
+ export { signRealtimeToken } from './signRealtimeToken';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
package/out/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.publishGlobal = exports.publish = void 0;
3
+ exports.signRealtimeToken = exports.publishGlobal = exports.publish = void 0;
4
4
  var publish_1 = require("./publish");
5
5
  Object.defineProperty(exports, "publish", { enumerable: true, get: function () { return publish_1.publish; } });
6
6
  Object.defineProperty(exports, "publishGlobal", { enumerable: true, get: function () { return publish_1.publishGlobal; } });
7
+ var signRealtimeToken_1 = require("./signRealtimeToken");
8
+ Object.defineProperty(exports, "signRealtimeToken", { enumerable: true, get: function () { return signRealtimeToken_1.signRealtimeToken; } });
package/out/publish.d.ts CHANGED
@@ -1,5 +1,19 @@
1
- export declare const getForgeProxyError: (response: Response) => string | null;
2
- export declare const handleProxyResponseErrors: (response: Response) => void;
3
- export declare const publish: (channelName: string, eventPayload: string) => Promise<any>;
4
- export declare const publishGlobal: (channelName: string, eventPayload: string) => Promise<any>;
1
+ export declare const publish: (channelName: string, eventPayload: string) => Promise<{
2
+ eventId: null;
3
+ eventTimestamp: null;
4
+ errors: any;
5
+ } | {
6
+ eventId: any;
7
+ eventTimestamp: any;
8
+ errors?: undefined;
9
+ }>;
10
+ export declare const publishGlobal: (channelName: string, eventPayload: string) => Promise<{
11
+ eventId: null;
12
+ eventTimestamp: null;
13
+ errors: any;
14
+ } | {
15
+ eventId: any;
16
+ eventTimestamp: any;
17
+ errors?: undefined;
18
+ }>;
5
19
  //# sourceMappingURL=publish.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,aAAc,QAAQ,kBAA8C,CAAC;AACpG,eAAO,MAAM,yBAAyB,aAAc,QAAQ,KAAG,IAK9D,CAAC;AAwBF,eAAO,MAAM,OAAO,gBAAuB,MAAM,gBAAgB,MAAM,iBAkCtE,CAAC;AAEF,eAAO,MAAM,aAAa,gBAAuB,MAAM,gBAAgB,MAAM,iBAiC5E,CAAC"}
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,OAAO,gBAAuB,MAAM,gBAAgB,MAAM;;;;;;;;EAgEtE,CAAC;AAEF,eAAO,MAAM,aAAa,gBAAuB,MAAM,gBAAgB,MAAM;;;;;;;;EA+D5E,CAAC"}
package/out/publish.js CHANGED
@@ -1,17 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.publishGlobal = exports.publish = exports.handleProxyResponseErrors = exports.getForgeProxyError = void 0;
4
- const api_1 = require("@forge/api");
3
+ exports.publishGlobal = exports.publish = void 0;
5
4
  const runtime_1 = require("./runtime");
6
- const getForgeProxyError = (response) => response.headers.get('forge-proxy-error');
7
- exports.getForgeProxyError = getForgeProxyError;
8
- const handleProxyResponseErrors = (response) => {
9
- const errorReason = (0, exports.getForgeProxyError)(response);
10
- if (errorReason) {
11
- throw new api_1.ProxyRequestError(response.status, errorReason);
12
- }
13
- };
14
- exports.handleProxyResponseErrors = handleProxyResponseErrors;
5
+ const utils_1 = require("./utils");
15
6
  const graphqlBody = `mutation publishRealtimeChannel(
16
7
  $installationId: ID!
17
8
  $name: String!
@@ -30,11 +21,10 @@ const graphqlBody = `mutation publishRealtimeChannel(
30
21
  }
31
22
  }
32
23
  }`;
33
- const prodEnvErrorMessage = 'Forge realtime usage is restricted to Forge apps in a non-production environment. Please see https://developer.atlassian.com/platform/forge/cli-reference/environments/ for reference on Forge app environments.';
34
24
  const publish = async (channelName, eventPayload) => {
35
25
  const { appContext, realtime } = (0, runtime_1.__getRuntime)();
36
26
  if (appContext?.environmentType === 'PRODUCTION') {
37
- throw new Error(prodEnvErrorMessage);
27
+ throw new Error(utils_1.prodEnvErrorMessage);
38
28
  }
39
29
  const response = await global.__forge_fetch__({
40
30
  type: 'realtime'
@@ -49,19 +39,44 @@ const publish = async (channelName, eventPayload) => {
49
39
  isGlobal: false
50
40
  }
51
41
  }),
42
+ errors: [],
52
43
  headers: {
53
44
  'Content-Type': 'application/json',
54
45
  'x-forge-context-token': realtime?.contextToken
55
46
  }
56
47
  });
57
- (0, exports.handleProxyResponseErrors)(response);
58
- return response;
48
+ (0, utils_1.handleProxyResponseErrors)(response);
49
+ const awaitedResponse = await response.json();
50
+ const { data, errors } = awaitedResponse;
51
+ if (errors && errors.length > 0) {
52
+ return {
53
+ eventId: null,
54
+ eventTimestamp: null,
55
+ errors
56
+ };
57
+ }
58
+ if (!data) {
59
+ return {
60
+ eventId: null,
61
+ eventTimestamp: null,
62
+ errors: [
63
+ {
64
+ message: 'Error publishing event to channel.'
65
+ }
66
+ ]
67
+ };
68
+ }
69
+ const { eventId, eventTimestamp } = awaitedResponse.data.ecosystem.publishRealtimeChannel;
70
+ return {
71
+ eventId,
72
+ eventTimestamp
73
+ };
59
74
  };
60
75
  exports.publish = publish;
61
76
  const publishGlobal = async (channelName, eventPayload) => {
62
77
  const { appContext } = (0, runtime_1.__getRuntime)();
63
78
  if (appContext?.environmentType === 'PRODUCTION') {
64
- throw new Error(prodEnvErrorMessage);
79
+ throw new Error(utils_1.prodEnvErrorMessage);
65
80
  }
66
81
  const response = await global.__forge_fetch__({
67
82
  type: 'realtime'
@@ -76,11 +91,36 @@ const publishGlobal = async (channelName, eventPayload) => {
76
91
  isGlobal: true
77
92
  }
78
93
  }),
94
+ errors: [],
79
95
  headers: {
80
96
  'Content-Type': 'application/json'
81
97
  }
82
98
  });
83
- (0, exports.handleProxyResponseErrors)(response);
84
- return response;
99
+ (0, utils_1.handleProxyResponseErrors)(response);
100
+ const awaitedResponse = await response.json();
101
+ const { data, errors } = awaitedResponse;
102
+ if (errors && errors.length > 0) {
103
+ return {
104
+ eventId: null,
105
+ eventTimestamp: null,
106
+ errors
107
+ };
108
+ }
109
+ if (!data) {
110
+ return {
111
+ eventId: null,
112
+ eventTimestamp: null,
113
+ errors: [
114
+ {
115
+ message: 'Error publishing global event to channel.'
116
+ }
117
+ ]
118
+ };
119
+ }
120
+ const { eventId, eventTimestamp } = data.ecosystem.publishRealtimeChannel;
121
+ return {
122
+ eventId,
123
+ eventTimestamp
124
+ };
85
125
  };
86
126
  exports.publishGlobal = publishGlobal;
@@ -0,0 +1,10 @@
1
+ export declare const signRealtimeToken: (channelName: string, claims: any) => Promise<{
2
+ jwt: null;
3
+ expiresAt: null;
4
+ errors: any;
5
+ } | {
6
+ jwt: any;
7
+ expiresAt: any;
8
+ errors?: undefined;
9
+ }>;
10
+ //# sourceMappingURL=signRealtimeToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signRealtimeToken.d.ts","sourceRoot":"","sources":["../src/signRealtimeToken.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,iBAAiB,gBAAuB,MAAM,UAAU,GAAG;;;;;;;;EA6DvE,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.signRealtimeToken = void 0;
4
+ const runtime_1 = require("./runtime");
5
+ const utils_1 = require("./utils");
6
+ const graphqlBody = `mutation signRealtimeToken(
7
+ $channelName: String!
8
+ $claims: JSON!
9
+ ){
10
+ ecosystem {
11
+ signRealtimeToken(
12
+ channelName: $channelName
13
+ claims: $claims
14
+ ) {
15
+ errors {
16
+ message
17
+ extensions {
18
+ errorType
19
+ statusCode
20
+ }
21
+ }
22
+ forgeRealtimeToken {
23
+ jwt
24
+ expiresAt
25
+ }
26
+ success
27
+ }
28
+ }
29
+ }`;
30
+ const signRealtimeToken = async (channelName, claims) => {
31
+ const { appContext } = (0, runtime_1.__getRuntime)();
32
+ if (appContext?.environmentType === 'PRODUCTION') {
33
+ throw new Error(utils_1.prodEnvErrorMessage);
34
+ }
35
+ const response = await global.__forge_fetch__({
36
+ type: 'realtime'
37
+ }, '/', {
38
+ method: 'POST',
39
+ body: JSON.stringify({
40
+ query: graphqlBody,
41
+ variables: {
42
+ channelName,
43
+ claims
44
+ }
45
+ }),
46
+ errors: [],
47
+ headers: {
48
+ 'Content-Type': 'application/json'
49
+ }
50
+ });
51
+ (0, utils_1.handleProxyResponseErrors)(response);
52
+ const awaitedResponse = await response.json();
53
+ const { data, errors } = awaitedResponse;
54
+ if (errors && errors.length > 0) {
55
+ return {
56
+ jwt: null,
57
+ expiresAt: null,
58
+ errors
59
+ };
60
+ }
61
+ if (!data) {
62
+ return {
63
+ jwt: null,
64
+ expiresAt: null,
65
+ errors: [
66
+ {
67
+ message: 'Error signing realtime token.'
68
+ }
69
+ ]
70
+ };
71
+ }
72
+ const { jwt, expiresAt } = data.ecosystem.signRealtimeToken.forgeRealtimeToken;
73
+ return {
74
+ jwt,
75
+ expiresAt
76
+ };
77
+ };
78
+ exports.signRealtimeToken = signRealtimeToken;
package/out/utils.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare const handleProxyResponseErrors: (response: Response) => void;
2
+ export declare const prodEnvErrorMessage = "Forge realtime usage is restricted to Forge apps in a non-production environment. Please see https://developer.atlassian.com/platform/forge/cli-reference/environments/ for reference on Forge app environments.";
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,aAAc,QAAQ,KAAG,IAK9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,qNACoL,CAAC"}
package/out/utils.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prodEnvErrorMessage = exports.handleProxyResponseErrors = void 0;
4
+ const api_1 = require("@forge/api");
5
+ const getForgeProxyError = (response) => response.headers.get('forge-proxy-error');
6
+ const handleProxyResponseErrors = (response) => {
7
+ const errorReason = getForgeProxyError(response);
8
+ if (errorReason) {
9
+ throw new api_1.ProxyRequestError(response.status, errorReason);
10
+ }
11
+ };
12
+ exports.handleProxyResponseErrors = handleProxyResponseErrors;
13
+ exports.prodEnvErrorMessage = 'Forge realtime usage is restricted to Forge apps in a non-production environment. Please see https://developer.atlassian.com/platform/forge/cli-reference/environments/ for reference on Forge app environments.';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/realtime",
3
- "version": "0.0.7-next.0",
3
+ "version": "0.1.0-next.1",
4
4
  "description": "Forge realtime",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "devDependencies": {
16
16
  "@atlassian/metrics-interface": "4.0.0",
17
- "@forge/api": "6.1.0",
17
+ "@forge/api": "6.1.1-next.0",
18
18
  "@types/node": "20.19.1"
19
19
  },
20
20
  "publishConfig": {
@@ -9,6 +9,7 @@ exports[`publish should publish an event when the payload is an object 1`] = `
9
9
  "/",
10
10
  {
11
11
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":false}}",
12
+ "errors": [],
12
13
  "headers": {
13
14
  "Content-Type": "application/json",
14
15
  "x-forge-context-token": "my.context.token",
@@ -28,6 +29,27 @@ exports[`publish should publish an event with FCT in header 1`] = `
28
29
  "/",
29
30
  {
30
31
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"this is an event payload","isGlobal":false}}",
32
+ "errors": [],
33
+ "headers": {
34
+ "Content-Type": "application/json",
35
+ "x-forge-context-token": "my.context.token",
36
+ },
37
+ "method": "POST",
38
+ },
39
+ ],
40
+ ]
41
+ `;
42
+
43
+ exports[`publish should return null eventId and eventTimestamp when the response has errors 1`] = `
44
+ [
45
+ [
46
+ {
47
+ "type": "realtime",
48
+ },
49
+ "/",
50
+ {
51
+ "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":false}}",
52
+ "errors": [],
31
53
  "headers": {
32
54
  "Content-Type": "application/json",
33
55
  "x-forge-context-token": "my.context.token",
@@ -47,6 +69,7 @@ exports[`publish should throw an error when Forge Outbound Proxy returns an erro
47
69
  "/",
48
70
  {
49
71
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":false}}",
72
+ "errors": [],
50
73
  "headers": {
51
74
  "Content-Type": "application/json",
52
75
  "x-forge-context-token": "my.context.token",
@@ -66,6 +89,7 @@ exports[`publishGlobal should publish an event 1`] = `
66
89
  "/",
67
90
  {
68
91
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"this is an event payload","isGlobal":true}}",
92
+ "errors": [],
69
93
  "headers": {
70
94
  "Content-Type": "application/json",
71
95
  },
@@ -84,6 +108,26 @@ exports[`publishGlobal should publish an event when the payload is an object 1`]
84
108
  "/",
85
109
  {
86
110
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":true}}",
111
+ "errors": [],
112
+ "headers": {
113
+ "Content-Type": "application/json",
114
+ },
115
+ "method": "POST",
116
+ },
117
+ ],
118
+ ]
119
+ `;
120
+
121
+ exports[`publishGlobal should return null eventId and eventTimestamp when the response has errors 1`] = `
122
+ [
123
+ [
124
+ {
125
+ "type": "realtime",
126
+ },
127
+ "/",
128
+ {
129
+ "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":true}}",
130
+ "errors": [],
87
131
  "headers": {
88
132
  "Content-Type": "application/json",
89
133
  },
@@ -102,6 +146,7 @@ exports[`publishGlobal should throw an error when Forge Outbound Proxy returns a
102
146
  "/",
103
147
  {
104
148
  "body": "{"query":"mutation publishRealtimeChannel(\\n $installationId: ID!\\n $name: String!\\n $payload: String!\\n $isGlobal: Boolean\\n){\\n ecosystem {\\n publishRealtimeChannel(\\n installationId: $installationId\\n name: $name\\n payload: $payload\\n isGlobal: $isGlobal\\n ) {\\n eventId,\\n eventTimestamp\\n }\\n }\\n}","variables":{"installationId":"iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii","name":"my-channel","payload":"{\\"value\\":\\"this is a test payload\\",\\"funLevel\\":100}","isGlobal":true}}",
149
+ "errors": [],
105
150
  "headers": {
106
151
  "Content-Type": "application/json",
107
152
  },