@allurereport/service 3.0.0-beta.16
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/README.md +13 -0
- package/dist/history.d.ts +8 -0
- package/dist/history.js +26 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/model.d.ts +4 -0
- package/dist/model.js +6 -0
- package/dist/service.d.ts +62 -0
- package/dist/service.js +173 -0
- package/dist/utils/http.d.ts +28 -0
- package/dist/utils/http.js +66 -0
- package/dist/utils/token.d.ts +12 -0
- package/dist/utils/token.js +56 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Allure Service API
|
|
2
|
+
|
|
3
|
+
[<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
|
|
4
|
+
|
|
5
|
+
- Learn more about Allure Report at https://allurereport.org
|
|
6
|
+
- 📚 [Documentation](https://allurereport.org/docs/) – discover official documentation for Allure Report
|
|
7
|
+
- ❓ [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) – get help from the team and community
|
|
8
|
+
- 📢 [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – be in touch with the latest updates
|
|
9
|
+
- 💬 [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – engage in casual conversations, share insights and ideas with the community
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
TODO:
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AllureHistory, HistoryDataPoint } from "@allurereport/core-api";
|
|
2
|
+
import type { AllureServiceClient } from "./service.js";
|
|
3
|
+
export declare class AllureRemoteHistory implements AllureHistory {
|
|
4
|
+
readonly allureServiceClient: AllureServiceClient;
|
|
5
|
+
constructor(allureServiceClient: AllureServiceClient);
|
|
6
|
+
readHistory(branch?: string): Promise<HistoryDataPoint[]>;
|
|
7
|
+
appendHistory(data: HistoryDataPoint, branch?: string): Promise<void>;
|
|
8
|
+
}
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { KnownError } from "./utils/http.js";
|
|
2
|
+
export class AllureRemoteHistory {
|
|
3
|
+
constructor(allureServiceClient) {
|
|
4
|
+
this.allureServiceClient = allureServiceClient;
|
|
5
|
+
}
|
|
6
|
+
async readHistory(branch) {
|
|
7
|
+
try {
|
|
8
|
+
const res = await this.allureServiceClient.downloadHistory({
|
|
9
|
+
branch,
|
|
10
|
+
});
|
|
11
|
+
return res;
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
if (err instanceof KnownError && err.status === 404) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async appendHistory(data, branch) {
|
|
21
|
+
await this.allureServiceClient.appendHistory({
|
|
22
|
+
history: data,
|
|
23
|
+
branch,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/model.d.ts
ADDED
package/dist/model.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
export const DEFAULT_HISTORY_SERVICE_URL = "https://history.allurereport.org";
|
|
4
|
+
export const ALLURE_FILES_DIRNAME = resolve(homedir(), ".allure");
|
|
5
|
+
export const ALLURE_LOGIN_EXCHANGE_TOKEN_PATH = join(ALLURE_FILES_DIRNAME, "exchange_token");
|
|
6
|
+
export const ALLURE_ACCESS_TOKEN_PATH = join(ALLURE_FILES_DIRNAME, "access_token");
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type HistoryDataPoint } from "@allurereport/core-api";
|
|
2
|
+
import { type Config } from "@allurereport/plugin-api";
|
|
3
|
+
export declare class AllureServiceClient {
|
|
4
|
+
#private;
|
|
5
|
+
readonly config: Config["allureService"] & {
|
|
6
|
+
pollingDelay?: number;
|
|
7
|
+
};
|
|
8
|
+
project: string | undefined;
|
|
9
|
+
constructor(config: Config["allureService"] & {
|
|
10
|
+
pollingDelay?: number;
|
|
11
|
+
});
|
|
12
|
+
setProject(project: string): void;
|
|
13
|
+
login(): Promise<string>;
|
|
14
|
+
logout(): Promise<void>;
|
|
15
|
+
profile(): Promise<{
|
|
16
|
+
email: string;
|
|
17
|
+
}>;
|
|
18
|
+
projects(): Promise<{
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
}[]>;
|
|
22
|
+
createProject(payload: {
|
|
23
|
+
name: string;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
}>;
|
|
28
|
+
deleteProject(payload: {
|
|
29
|
+
name: string;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
}>;
|
|
34
|
+
appendHistory(payload: {
|
|
35
|
+
history: HistoryDataPoint;
|
|
36
|
+
branch?: string;
|
|
37
|
+
}): Promise<unknown>;
|
|
38
|
+
downloadHistory(payload?: {
|
|
39
|
+
branch?: string;
|
|
40
|
+
}): Promise<HistoryDataPoint[]>;
|
|
41
|
+
createReport(payload: {
|
|
42
|
+
reportName: string;
|
|
43
|
+
reportUuid?: string;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
url: string;
|
|
46
|
+
}>;
|
|
47
|
+
completeReport(payload: {
|
|
48
|
+
reportUuid: string;
|
|
49
|
+
}): Promise<unknown>;
|
|
50
|
+
addReportAsset(payload: {
|
|
51
|
+
filename: string;
|
|
52
|
+
file?: Buffer;
|
|
53
|
+
filepath?: string;
|
|
54
|
+
}): Promise<unknown>;
|
|
55
|
+
addReportFile(payload: {
|
|
56
|
+
reportUuid: string;
|
|
57
|
+
pluginId: string;
|
|
58
|
+
filename: string;
|
|
59
|
+
file?: Buffer;
|
|
60
|
+
filepath?: string;
|
|
61
|
+
}): Promise<string>;
|
|
62
|
+
}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _AllureServiceClient_client, _AllureServiceClient_url, _AllureServiceClient_pollingDelay;
|
|
13
|
+
import { readFile } from "node:fs/promises";
|
|
14
|
+
import { join as joinPosix } from "node:path/posix";
|
|
15
|
+
import open from "open";
|
|
16
|
+
import { createServiceHttpClient } from "./utils/http.js";
|
|
17
|
+
import { decryptExchangeToken, deleteAccessToken, writeAccessToken, writeExchangeToken } from "./utils/token.js";
|
|
18
|
+
export class AllureServiceClient {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
_AllureServiceClient_client.set(this, void 0);
|
|
22
|
+
_AllureServiceClient_url.set(this, void 0);
|
|
23
|
+
_AllureServiceClient_pollingDelay.set(this, void 0);
|
|
24
|
+
if (!config.url) {
|
|
25
|
+
throw new Error("Allure service URL is required!");
|
|
26
|
+
}
|
|
27
|
+
__classPrivateFieldSet(this, _AllureServiceClient_url, config.url, "f");
|
|
28
|
+
__classPrivateFieldSet(this, _AllureServiceClient_client, createServiceHttpClient(__classPrivateFieldGet(this, _AllureServiceClient_url, "f"), config?.accessToken), "f");
|
|
29
|
+
__classPrivateFieldSet(this, _AllureServiceClient_pollingDelay, config?.pollingDelay ?? 2500, "f");
|
|
30
|
+
this.project = config?.project;
|
|
31
|
+
}
|
|
32
|
+
setProject(project) {
|
|
33
|
+
this.project = project;
|
|
34
|
+
}
|
|
35
|
+
async login() {
|
|
36
|
+
const exchangeToken = await writeExchangeToken();
|
|
37
|
+
const connectUrl = new URL("/connect", __classPrivateFieldGet(this, _AllureServiceClient_url, "f"));
|
|
38
|
+
connectUrl.searchParams.set("token", decryptExchangeToken(exchangeToken));
|
|
39
|
+
await open(connectUrl.toString());
|
|
40
|
+
let currentExchangeAttemptTimeout;
|
|
41
|
+
return await new Promise((res) => {
|
|
42
|
+
const makeExchangeAttempt = () => {
|
|
43
|
+
return globalThis.setTimeout(async () => {
|
|
44
|
+
const token = decryptExchangeToken(exchangeToken);
|
|
45
|
+
const { accessToken } = await __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/auth/tokens/exchange", {
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
body: {
|
|
50
|
+
token,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
if (!accessToken) {
|
|
54
|
+
globalThis.clearTimeout(currentExchangeAttemptTimeout);
|
|
55
|
+
currentExchangeAttemptTimeout = makeExchangeAttempt();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await writeAccessToken(accessToken);
|
|
59
|
+
return res(accessToken);
|
|
60
|
+
}, __classPrivateFieldGet(this, _AllureServiceClient_pollingDelay, "f"));
|
|
61
|
+
};
|
|
62
|
+
currentExchangeAttemptTimeout = makeExchangeAttempt();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async logout() {
|
|
66
|
+
await deleteAccessToken();
|
|
67
|
+
}
|
|
68
|
+
async profile() {
|
|
69
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").get("/api/user/profile");
|
|
70
|
+
}
|
|
71
|
+
async projects() {
|
|
72
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").get("/api/projects/list");
|
|
73
|
+
}
|
|
74
|
+
async createProject(payload) {
|
|
75
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/projects/create", {
|
|
76
|
+
body: payload,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async deleteProject(payload) {
|
|
80
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/projects/delete", {
|
|
81
|
+
body: payload,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async appendHistory(payload) {
|
|
85
|
+
if (!this.project) {
|
|
86
|
+
throw new Error("Project is not set");
|
|
87
|
+
}
|
|
88
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/history/append", {
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
},
|
|
92
|
+
body: {
|
|
93
|
+
...payload,
|
|
94
|
+
project: this.project,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async downloadHistory(payload) {
|
|
99
|
+
if (!this.project) {
|
|
100
|
+
throw new Error("Project is not set");
|
|
101
|
+
}
|
|
102
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").get("/api/history/download", {
|
|
103
|
+
params: {
|
|
104
|
+
project: this.project,
|
|
105
|
+
...payload,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async createReport(payload) {
|
|
110
|
+
const { reportName, reportUuid } = payload;
|
|
111
|
+
if (!this.project) {
|
|
112
|
+
throw new Error("Project is not set");
|
|
113
|
+
}
|
|
114
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/reports/create", {
|
|
115
|
+
body: {
|
|
116
|
+
project: this.project,
|
|
117
|
+
reportName,
|
|
118
|
+
reportUuid,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async completeReport(payload) {
|
|
123
|
+
const { reportUuid } = payload;
|
|
124
|
+
if (!this.project) {
|
|
125
|
+
throw new Error("Project is not set");
|
|
126
|
+
}
|
|
127
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/reports/complete", {
|
|
128
|
+
body: {
|
|
129
|
+
id: reportUuid,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async addReportAsset(payload) {
|
|
134
|
+
const { filename, file, filepath } = payload;
|
|
135
|
+
if (!file && !filepath) {
|
|
136
|
+
throw new Error("File or filepath is required");
|
|
137
|
+
}
|
|
138
|
+
let content = file;
|
|
139
|
+
if (!content) {
|
|
140
|
+
content = await readFile(filepath);
|
|
141
|
+
}
|
|
142
|
+
const form = new FormData();
|
|
143
|
+
form.set("filename", filename);
|
|
144
|
+
form.set("file", content);
|
|
145
|
+
return __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post("/api/assets/upload", {
|
|
146
|
+
body: form,
|
|
147
|
+
headers: {
|
|
148
|
+
"Content-Type": "multipart/form-data",
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async addReportFile(payload) {
|
|
153
|
+
const { reportUuid, filename, file, filepath, pluginId } = payload;
|
|
154
|
+
if (!file && !filepath) {
|
|
155
|
+
throw new Error("File or filepath is required");
|
|
156
|
+
}
|
|
157
|
+
let content = file;
|
|
158
|
+
if (!content) {
|
|
159
|
+
content = await readFile(filepath);
|
|
160
|
+
}
|
|
161
|
+
const form = new FormData();
|
|
162
|
+
form.set("filename", joinPosix(pluginId, filename));
|
|
163
|
+
form.set("file", content);
|
|
164
|
+
await __classPrivateFieldGet(this, _AllureServiceClient_client, "f").post(`/api/reports/upload/${reportUuid}`, {
|
|
165
|
+
body: form,
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "multipart/form-data",
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
return joinPosix(__classPrivateFieldGet(this, _AllureServiceClient_url, "f"), reportUuid, filename);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
_AllureServiceClient_client = new WeakMap(), _AllureServiceClient_url = new WeakMap(), _AllureServiceClient_pollingDelay = new WeakMap();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type AxiosRequestConfig } from "axios";
|
|
2
|
+
export declare class KnownError extends Error {
|
|
3
|
+
status?: number;
|
|
4
|
+
constructor(message: string, status?: number);
|
|
5
|
+
}
|
|
6
|
+
export declare class UnknownError extends Error {
|
|
7
|
+
stack?: string;
|
|
8
|
+
constructor(message: string, stack?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare const createServiceHttpClient: (historyServiceURL?: string, accessToken?: string) => {
|
|
11
|
+
get: <T>(endpoint: string, payload?: AxiosRequestConfig & {
|
|
12
|
+
params?: Record<string, any>;
|
|
13
|
+
body?: any;
|
|
14
|
+
}) => Promise<T>;
|
|
15
|
+
post: <T>(endpoint: string, payload?: AxiosRequestConfig & {
|
|
16
|
+
params?: Record<string, any>;
|
|
17
|
+
body?: any;
|
|
18
|
+
}) => Promise<T>;
|
|
19
|
+
put: <T>(endpoint: string, payload?: AxiosRequestConfig & {
|
|
20
|
+
params?: Record<string, any>;
|
|
21
|
+
body?: any;
|
|
22
|
+
}) => Promise<T>;
|
|
23
|
+
delete: <T>(endpoint: string, payload?: AxiosRequestConfig & {
|
|
24
|
+
params?: Record<string, any>;
|
|
25
|
+
body?: any;
|
|
26
|
+
}) => Promise<T>;
|
|
27
|
+
};
|
|
28
|
+
export type HttpClient = ReturnType<typeof createServiceHttpClient>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import axios, { AxiosError } from "axios";
|
|
2
|
+
import { DEFAULT_HISTORY_SERVICE_URL } from "../model.js";
|
|
3
|
+
import { readAccessToken } from "./token.js";
|
|
4
|
+
export class KnownError extends Error {
|
|
5
|
+
constructor(message, status) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "KnownError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class UnknownError extends Error {
|
|
12
|
+
constructor(message, stack) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "UnknownError";
|
|
15
|
+
this.stack = stack;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const createServiceHttpClient = (historyServiceURL = DEFAULT_HISTORY_SERVICE_URL, accessToken) => {
|
|
19
|
+
const client = axios.create({
|
|
20
|
+
baseURL: historyServiceURL,
|
|
21
|
+
withCredentials: true,
|
|
22
|
+
validateStatus: (status) => status < 400,
|
|
23
|
+
});
|
|
24
|
+
const sendRequest = (method) => async (endpoint, payload) => {
|
|
25
|
+
const actualAccessToken = accessToken || (await readAccessToken());
|
|
26
|
+
const headers = {
|
|
27
|
+
...(payload?.headers ?? {}),
|
|
28
|
+
};
|
|
29
|
+
if (actualAccessToken) {
|
|
30
|
+
headers.Authorization = `Bearer ${actualAccessToken}`;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
let res;
|
|
34
|
+
if (payload?.body) {
|
|
35
|
+
res = await client[method](endpoint, payload.body, {
|
|
36
|
+
...payload,
|
|
37
|
+
headers,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
res = await client[method](endpoint, {
|
|
42
|
+
...payload,
|
|
43
|
+
headers,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return res.data;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (!(err instanceof AxiosError)) {
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
const { status = 500 } = err.response ?? {};
|
|
53
|
+
if (status < 500) {
|
|
54
|
+
throw new KnownError(err.response?.data ?? err.message, status);
|
|
55
|
+
}
|
|
56
|
+
const { response, message, errors, stack } = err;
|
|
57
|
+
throw new UnknownError(response?.data ?? errors?.[0]?.message?.trim?.() ?? message, stack);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
get: sendRequest("get"),
|
|
62
|
+
post: sendRequest("post"),
|
|
63
|
+
put: sendRequest("put"),
|
|
64
|
+
delete: sendRequest("delete"),
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class InvalidTokenError extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
export declare class ExpiredTokenError extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare const generateExchangeToken: () => string;
|
|
8
|
+
export declare const decryptExchangeToken: (exchangeToken: string) => string;
|
|
9
|
+
export declare const writeExchangeToken: () => Promise<string>;
|
|
10
|
+
export declare const writeAccessToken: (token: string) => Promise<void>;
|
|
11
|
+
export declare const readAccessToken: () => Promise<string | undefined>;
|
|
12
|
+
export declare const deleteAccessToken: () => Promise<void>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { EOL } from "node:os";
|
|
4
|
+
import { ALLURE_ACCESS_TOKEN_PATH, ALLURE_FILES_DIRNAME, ALLURE_LOGIN_EXCHANGE_TOKEN_PATH } from "../model.js";
|
|
5
|
+
export class InvalidTokenError extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super("Invalid token");
|
|
8
|
+
this.name = "InvalidTokenError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class ExpiredTokenError extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super("Expired token");
|
|
14
|
+
this.name = "ExpiredTokenError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export const generateExchangeToken = () => {
|
|
18
|
+
const token = randomBytes(32).toString("hex");
|
|
19
|
+
const validTill = Date.now() + 10 * 60 * 1000;
|
|
20
|
+
return Buffer.from(`${token}:${validTill}`, "utf8").toString("base64");
|
|
21
|
+
};
|
|
22
|
+
export const decryptExchangeToken = (exchangeToken) => {
|
|
23
|
+
const [token, validTill] = Buffer.from(exchangeToken, "base64").toString("utf8").split(":");
|
|
24
|
+
if (!token) {
|
|
25
|
+
throw new InvalidTokenError();
|
|
26
|
+
}
|
|
27
|
+
if (validTill && parseInt(validTill, 10) < Date.now()) {
|
|
28
|
+
throw new ExpiredTokenError();
|
|
29
|
+
}
|
|
30
|
+
return token;
|
|
31
|
+
};
|
|
32
|
+
export const writeExchangeToken = async () => {
|
|
33
|
+
const tempToken = generateExchangeToken();
|
|
34
|
+
await mkdir(ALLURE_FILES_DIRNAME, { recursive: true });
|
|
35
|
+
await writeFile(ALLURE_LOGIN_EXCHANGE_TOKEN_PATH, tempToken);
|
|
36
|
+
return tempToken;
|
|
37
|
+
};
|
|
38
|
+
export const writeAccessToken = async (token) => {
|
|
39
|
+
await mkdir(ALLURE_FILES_DIRNAME, { recursive: true });
|
|
40
|
+
await writeFile(ALLURE_ACCESS_TOKEN_PATH, token);
|
|
41
|
+
};
|
|
42
|
+
export const readAccessToken = async () => {
|
|
43
|
+
try {
|
|
44
|
+
const accessToken = await readFile(ALLURE_ACCESS_TOKEN_PATH, "utf-8");
|
|
45
|
+
return accessToken.replaceAll(EOL, "").trim();
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
export const deleteAccessToken = async () => {
|
|
52
|
+
try {
|
|
53
|
+
await rm(ALLURE_ACCESS_TOKEN_PATH, { force: true });
|
|
54
|
+
}
|
|
55
|
+
catch (ignore) { }
|
|
56
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allurereport/service",
|
|
3
|
+
"version": "3.0.0-beta.16",
|
|
4
|
+
"description": "Allure Service API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"allure",
|
|
7
|
+
"testing",
|
|
8
|
+
"report",
|
|
9
|
+
"plugin",
|
|
10
|
+
"html"
|
|
11
|
+
],
|
|
12
|
+
"repository": "https://github.com/allure-framework/allure3",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"author": "Qameta Software",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"module": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"./dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "run clean && tsc --project ./tsconfig.json",
|
|
27
|
+
"clean": "rimraf ./dist",
|
|
28
|
+
"eslint": "eslint ./src/**/*.{js,jsx,ts,tsx}",
|
|
29
|
+
"eslint:format": "eslint --fix ./src/**/*.{js,jsx,ts,tsx}",
|
|
30
|
+
"test": "rimraf ./out && vitest run"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@allurereport/core-api": "3.0.0-beta.16",
|
|
34
|
+
"@allurereport/plugin-api": "3.0.0-beta.16",
|
|
35
|
+
"axios": "^1.8.4",
|
|
36
|
+
"open": "^10.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@stylistic/eslint-plugin": "^2.6.1",
|
|
40
|
+
"@types/eslint": "^8.56.11",
|
|
41
|
+
"@types/node": "^20.17.9",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
44
|
+
"@vitest/runner": "^2.1.8",
|
|
45
|
+
"@vitest/snapshot": "^2.1.8",
|
|
46
|
+
"allure-vitest": "^3.0.9",
|
|
47
|
+
"eslint": "^8.57.0",
|
|
48
|
+
"eslint-config-prettier": "^9.1.0",
|
|
49
|
+
"eslint-plugin-import": "^2.29.1",
|
|
50
|
+
"eslint-plugin-jsdoc": "^50.0.0",
|
|
51
|
+
"eslint-plugin-n": "^17.10.1",
|
|
52
|
+
"eslint-plugin-no-null": "^1.0.2",
|
|
53
|
+
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
54
|
+
"rimraf": "^6.0.1",
|
|
55
|
+
"typescript": "^5.6.3",
|
|
56
|
+
"vitest": "^2.1.8"
|
|
57
|
+
}
|
|
58
|
+
}
|