@forge/realtime 0.4.2-next.0-experimental-4a332af → 0.5.0-experimental-04cc2b9
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 +28 -2
- package/out/productContext.d.ts +1 -1
- package/out/productContext.d.ts.map +1 -1
- package/out/productContext.js +3 -3
- package/out/publish.d.ts.map +1 -1
- package/out/publish.js +32 -3
- package/out/runtime.js +1 -2
- package/out/signRealtimeToken.d.ts +2 -1
- package/out/signRealtimeToken.d.ts.map +1 -1
- package/out/signRealtimeToken.js +6 -2
- package/out/utils.d.ts +7 -0
- package/out/utils.d.ts.map +1 -1
- package/out/utils.js +29 -1
- package/package.json +12 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
# @forge/realtime
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.5.0-experimental-04cc2b9
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- d9ef926: Adds support for TypeScript 5
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- f4a575a: Adds rate limit headers to signRealtimeToken
|
|
12
|
+
|
|
13
|
+
## 0.5.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 68e1229: Adds pre validation for the forge realtime token in publish methods
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
6
20
|
|
|
7
21
|
- 4c69f6e: Add headers for rate limits
|
|
8
|
-
-
|
|
22
|
+
- 64e72aa: Updates error return to be consistent
|
|
23
|
+
|
|
24
|
+
## 0.5.0-next.2
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- 64e72aa: Updates error return to be consistent
|
|
29
|
+
|
|
30
|
+
## 0.5.0-next.1
|
|
31
|
+
|
|
32
|
+
### Minor Changes
|
|
33
|
+
|
|
34
|
+
- 68e1229: Adds pre validation for the forge realtime token in publish methods
|
|
9
35
|
|
|
10
36
|
## 0.4.2-next.0
|
|
11
37
|
|
package/out/productContext.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export declare enum Bitbucket {
|
|
|
11
11
|
Repository = "repository",
|
|
12
12
|
PullRequest = "pullRequest"
|
|
13
13
|
}
|
|
14
|
-
export
|
|
14
|
+
export type ProductContext = Jira | Confluence | Bitbucket;
|
|
15
15
|
//# sourceMappingURL=productContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"productContext.d.ts","sourceRoot":"","sources":["../src/productContext.ts"],"names":[],"mappings":"AAGA,oBAAY,IAAI;IACd,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAED,oBAAY,UAAU;IACpB,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB;AAED,oBAAY,SAAS;IACnB,UAAU,eAAe;IACzB,WAAW,gBAAgB;CAC5B;AAED,
|
|
1
|
+
{"version":3,"file":"productContext.d.ts","sourceRoot":"","sources":["../src/productContext.ts"],"names":[],"mappings":"AAGA,oBAAY,IAAI;IACd,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAED,oBAAY,UAAU;IACpB,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB;AAED,oBAAY,SAAS;IACnB,UAAU,eAAe;IACzB,WAAW,gBAAgB;CAC5B;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC"}
|
package/out/productContext.js
CHANGED
|
@@ -6,14 +6,14 @@ var Jira;
|
|
|
6
6
|
Jira["Board"] = "board";
|
|
7
7
|
Jira["Issue"] = "issue";
|
|
8
8
|
Jira["Project"] = "project";
|
|
9
|
-
})(Jira
|
|
9
|
+
})(Jira || (exports.Jira = Jira = {}));
|
|
10
10
|
var Confluence;
|
|
11
11
|
(function (Confluence) {
|
|
12
12
|
Confluence["Content"] = "content";
|
|
13
13
|
Confluence["Space"] = "space";
|
|
14
|
-
})(Confluence
|
|
14
|
+
})(Confluence || (exports.Confluence = Confluence = {}));
|
|
15
15
|
var Bitbucket;
|
|
16
16
|
(function (Bitbucket) {
|
|
17
17
|
Bitbucket["Repository"] = "repository";
|
|
18
18
|
Bitbucket["PullRequest"] = "pullRequest";
|
|
19
|
-
})(Bitbucket
|
|
19
|
+
})(Bitbucket || (exports.Bitbucket = Bitbucket = {}));
|
package/out/publish.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA2BlD,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA2BlD,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,OAAO,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,aAAa,MAAM,EACnB,cAAc,MAAM,GAAG,CAAC,EACxB,UAAU,cAAc;;;;;;;;EA2FzB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,aAAa,MAAM,EACnB,cAAc,MAAM,GAAG,CAAC,EACxB,UAAU,cAAc;;;;;;;;EAiFzB,CAAC"}
|
package/out/publish.js
CHANGED
|
@@ -31,6 +31,20 @@ const publish = async (channelName, eventPayload, options) => {
|
|
|
31
31
|
if (contextOverrides && !Array.isArray(contextOverrides)) {
|
|
32
32
|
throw new Error('Invalid value for contextOverrides. Please provide an array of valid context properties.');
|
|
33
33
|
}
|
|
34
|
+
if (token) {
|
|
35
|
+
const { valid, error } = (0, utils_1.validateToken)(token, channelName);
|
|
36
|
+
if (!valid) {
|
|
37
|
+
return {
|
|
38
|
+
eventId: null,
|
|
39
|
+
eventTimestamp: null,
|
|
40
|
+
errors: [
|
|
41
|
+
{
|
|
42
|
+
message: `Realtime token validation failed: ${error}`
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
34
48
|
const channelContext = contextOverrides
|
|
35
49
|
? JSON.stringify({
|
|
36
50
|
contextOverrides
|
|
@@ -48,7 +62,7 @@ const publish = async (channelName, eventPayload, options) => {
|
|
|
48
62
|
context: channelContext,
|
|
49
63
|
payload: JSON.stringify(eventPayload),
|
|
50
64
|
isGlobal: false,
|
|
51
|
-
token
|
|
65
|
+
token
|
|
52
66
|
}
|
|
53
67
|
}),
|
|
54
68
|
errors: [],
|
|
@@ -89,6 +103,21 @@ const publish = async (channelName, eventPayload, options) => {
|
|
|
89
103
|
exports.publish = publish;
|
|
90
104
|
const publishGlobal = async (channelName, eventPayload, options) => {
|
|
91
105
|
const { appContext, realtime } = (0, runtime_1.__getRuntime)();
|
|
106
|
+
const { token } = options || {};
|
|
107
|
+
if (token) {
|
|
108
|
+
const { valid, error } = (0, utils_1.validateToken)(token, channelName);
|
|
109
|
+
if (!valid) {
|
|
110
|
+
return {
|
|
111
|
+
eventId: null,
|
|
112
|
+
eventTimestamp: null,
|
|
113
|
+
errors: [
|
|
114
|
+
{
|
|
115
|
+
message: `Realtime token validation failed: ${error}`
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
92
121
|
const response = await global.__forge_fetch__({
|
|
93
122
|
type: 'realtime'
|
|
94
123
|
}, '/', {
|
|
@@ -100,7 +129,7 @@ const publishGlobal = async (channelName, eventPayload, options) => {
|
|
|
100
129
|
name: channelName,
|
|
101
130
|
payload: JSON.stringify(eventPayload),
|
|
102
131
|
isGlobal: true,
|
|
103
|
-
token
|
|
132
|
+
token
|
|
104
133
|
}
|
|
105
134
|
}),
|
|
106
135
|
errors: [],
|
|
@@ -127,7 +156,7 @@ const publishGlobal = async (channelName, eventPayload, options) => {
|
|
|
127
156
|
eventTimestamp: null,
|
|
128
157
|
errors: [
|
|
129
158
|
{
|
|
130
|
-
message: 'Error publishing
|
|
159
|
+
message: 'Error publishing event to channel.'
|
|
131
160
|
}
|
|
132
161
|
]
|
|
133
162
|
};
|
package/out/runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.__getRuntime =
|
|
3
|
+
exports.__getRuntime = __getRuntime;
|
|
4
4
|
function __getRuntime() {
|
|
5
5
|
const runtime = global.__forge_runtime__;
|
|
6
6
|
if (!runtime) {
|
|
@@ -8,4 +8,3 @@ function __getRuntime() {
|
|
|
8
8
|
}
|
|
9
9
|
return runtime;
|
|
10
10
|
}
|
|
11
|
-
exports.__getRuntime = __getRuntime;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
type TokenPermissions = 'subscribe' | 'publish';
|
|
2
|
+
export type RealtimeTokenPermissions = [TokenPermissions, ...TokenPermissions[]];
|
|
2
3
|
export declare const signRealtimeToken: (channelName: string, claims: any, permissions?: RealtimeTokenPermissions) => Promise<{
|
|
3
4
|
token: null;
|
|
4
5
|
expiresAt: null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signRealtimeToken.d.ts","sourceRoot":"","sources":["../src/signRealtimeToken.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signRealtimeToken.d.ts","sourceRoot":"","sources":["../src/signRealtimeToken.ts"],"names":[],"mappings":"AA8BA,KAAK,gBAAgB,GAAG,WAAW,GAAG,SAAS,CAAC;AAChD,MAAM,MAAM,wBAAwB,GAAG,CAAC,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAAC,CAAC;AAEjF,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,EAEnB,QAAQ,GAAG,EACX,cAAc,wBAAwB;;;;;;;;EA6DvC,CAAC"}
|
package/out/signRealtimeToken.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.signRealtimeToken = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
|
+
const runtime_1 = require("./runtime");
|
|
5
6
|
const graphqlBody = `mutation signRealtimeToken(
|
|
6
7
|
$channelName: String!
|
|
7
8
|
$claims: JSON!
|
|
@@ -29,6 +30,7 @@ const graphqlBody = `mutation signRealtimeToken(
|
|
|
29
30
|
}
|
|
30
31
|
}`;
|
|
31
32
|
const signRealtimeToken = async (channelName, claims, permissions) => {
|
|
33
|
+
const { appContext } = (0, runtime_1.__getRuntime)();
|
|
32
34
|
const response = await global.__forge_fetch__({
|
|
33
35
|
type: 'realtime'
|
|
34
36
|
}, '/', {
|
|
@@ -43,7 +45,9 @@ const signRealtimeToken = async (channelName, claims, permissions) => {
|
|
|
43
45
|
}),
|
|
44
46
|
errors: [],
|
|
45
47
|
headers: {
|
|
46
|
-
'Content-Type': 'application/json'
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
'x-rate-limit-app-id': appContext.appId,
|
|
50
|
+
'x-rate-limit-installation-id': appContext.installationId
|
|
47
51
|
}
|
|
48
52
|
});
|
|
49
53
|
(0, utils_1.handleProxyResponseErrors)(response);
|
|
@@ -62,7 +66,7 @@ const signRealtimeToken = async (channelName, claims, permissions) => {
|
|
|
62
66
|
expiresAt: null,
|
|
63
67
|
errors: [
|
|
64
68
|
{
|
|
65
|
-
message: 'Error signing realtime token
|
|
69
|
+
message: 'Error signing realtime token'
|
|
66
70
|
}
|
|
67
71
|
]
|
|
68
72
|
};
|
package/out/utils.d.ts
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export declare const handleProxyResponseErrors: (response: Response) => void;
|
|
2
|
+
type RealtimeTokenValidationError = 'INVALID_TOKEN' | 'TOKEN_EXPIRED' | 'MISSING_PERMISSION' | 'CHANNEL_NAME_MISMATCH';
|
|
3
|
+
interface RealtimeTokenValidationResult {
|
|
4
|
+
error?: RealtimeTokenValidationError;
|
|
5
|
+
valid: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const validateToken: (token: string, channelName: string) => RealtimeTokenValidationResult;
|
|
8
|
+
export {};
|
|
2
9
|
//# sourceMappingURL=utils.d.ts.map
|
package/out/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,yBAAyB,GAAI,UAAU,QAAQ,KAAG,IAK9D,CAAC;AAeF,KAAK,4BAA4B,GAAG,eAAe,GAAG,eAAe,GAAG,oBAAoB,GAAG,uBAAuB,CAAC;AAEvH,UAAU,6BAA6B;IACrC,KAAK,CAAC,EAAE,4BAA4B,CAAC;IACrC,KAAK,EAAE,OAAO,CAAC;CAChB;AAuBD,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,aAAa,MAAM,KAAG,6BAqBlE,CAAC"}
|
package/out/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleProxyResponseErrors = void 0;
|
|
3
|
+
exports.validateToken = exports.handleProxyResponseErrors = void 0;
|
|
4
4
|
const api_1 = require("@forge/api");
|
|
5
5
|
const getForgeProxyError = (response) => response.headers.get('forge-proxy-error');
|
|
6
6
|
const handleProxyResponseErrors = (response) => {
|
|
@@ -10,3 +10,31 @@ const handleProxyResponseErrors = (response) => {
|
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
12
|
exports.handleProxyResponseErrors = handleProxyResponseErrors;
|
|
13
|
+
const decodeTokenPayload = (token) => {
|
|
14
|
+
const parts = token.split('.');
|
|
15
|
+
if (parts.length !== 3) {
|
|
16
|
+
throw new Error('Invalid token format.');
|
|
17
|
+
}
|
|
18
|
+
const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
19
|
+
return JSON.parse(Buffer.from(base64, 'base64').toString('utf-8'));
|
|
20
|
+
};
|
|
21
|
+
const validateToken = (token, channelName) => {
|
|
22
|
+
let decodedToken;
|
|
23
|
+
try {
|
|
24
|
+
decodedToken = decodeTokenPayload(token);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { valid: false, error: 'INVALID_TOKEN' };
|
|
28
|
+
}
|
|
29
|
+
if (typeof decodedToken.exp === 'number' && Date.now() / 1000 >= decodedToken.exp) {
|
|
30
|
+
return { valid: false, error: 'TOKEN_EXPIRED' };
|
|
31
|
+
}
|
|
32
|
+
if (decodedToken.channel.name !== channelName) {
|
|
33
|
+
return { valid: false, error: 'CHANNEL_NAME_MISMATCH' };
|
|
34
|
+
}
|
|
35
|
+
if (decodedToken.permissions && !decodedToken.permissions?.includes('publish')) {
|
|
36
|
+
return { valid: false, error: 'MISSING_PERMISSION' };
|
|
37
|
+
}
|
|
38
|
+
return { valid: true };
|
|
39
|
+
};
|
|
40
|
+
exports.validateToken = validateToken;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge/realtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-experimental-04cc2b9",
|
|
4
4
|
"description": "Forge realtime",
|
|
5
5
|
"main": "out/index.js",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -14,10 +14,19 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@atlassian/metrics-interface": "4.0.0",
|
|
17
|
-
"@forge/api": "^7.2.
|
|
18
|
-
"@types/node": "20.19.1"
|
|
17
|
+
"@forge/api": "^7.2.2-experimental-04cc2b9",
|
|
18
|
+
"@types/node": "20.19.1",
|
|
19
|
+
"typescript": "5.9.2"
|
|
19
20
|
},
|
|
20
21
|
"publishConfig": {
|
|
21
22
|
"registry": "https://packages.atlassian.com/api/npm/npm-public/"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"typescript": ">=5.0.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"typescript": {
|
|
29
|
+
"optional": true
|
|
30
|
+
}
|
|
22
31
|
}
|
|
23
32
|
}
|