@lightsparkdev/core 0.3.8 → 0.3.9
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 +6 -0
- package/dist/index.cjs +10 -8
- package/dist/index.d.ts +17 -13
- package/dist/index.js +10 -8
- package/package.json +14 -7
- package/src/LightsparkException.ts +6 -2
- package/src/auth/AuthProvider.ts +7 -2
- package/src/auth/LightsparkAuthException.ts +1 -1
- package/src/auth/StubAuthProvider.ts +6 -3
- package/src/crypto/LightsparkSigningException.ts +1 -1
- package/src/crypto/crypto.ts +2 -3
- package/src/requester/Query.ts +2 -2
- package/src/requester/Requester.ts +15 -10
- package/src/utils/base64.ts +2 -2
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -89,7 +89,7 @@ var StubAuthProvider = class {
|
|
|
89
89
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
90
90
|
var Base64 = {
|
|
91
91
|
btoa: (input = "") => {
|
|
92
|
-
|
|
92
|
+
const str = input;
|
|
93
93
|
let output = "";
|
|
94
94
|
for (let block = 0, charCode, i = 0, map = chars; str.charAt(i | 0) || (map = "=", i % 1); output += map.charAt(63 & block >> 8 - i % 1 * 8)) {
|
|
95
95
|
charCode = str.charCodeAt(i += 3 / 4);
|
|
@@ -103,7 +103,7 @@ var Base64 = {
|
|
|
103
103
|
return output;
|
|
104
104
|
},
|
|
105
105
|
atob: (input = "") => {
|
|
106
|
-
|
|
106
|
+
const str = input.replace(/=+$/, "");
|
|
107
107
|
let output = "";
|
|
108
108
|
if (str.length % 4 == 1) {
|
|
109
109
|
throw new Error(
|
|
@@ -205,8 +205,8 @@ var deriveKey = async (password, salt, iterations, algorithm, bit_len) => {
|
|
|
205
205
|
return [key, iv];
|
|
206
206
|
};
|
|
207
207
|
var decrypt = async (header_json, ciphertext, password) => {
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
let decoded = b64decode(ciphertext);
|
|
209
|
+
let header;
|
|
210
210
|
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
211
211
|
header = {
|
|
212
212
|
v: 0,
|
|
@@ -294,7 +294,6 @@ var serializeSigningKey = async (key, format) => {
|
|
|
294
294
|
);
|
|
295
295
|
};
|
|
296
296
|
var getNonce = async () => {
|
|
297
|
-
const cryptoImpl = await getCrypto();
|
|
298
297
|
const nonceSt = await getRandomValues32(new Uint32Array(1));
|
|
299
298
|
return Number(nonceSt);
|
|
300
299
|
};
|
|
@@ -452,7 +451,7 @@ var Requester = class {
|
|
|
452
451
|
}
|
|
453
452
|
}
|
|
454
453
|
const operation = operationMatch[2];
|
|
455
|
-
|
|
454
|
+
const bodyData = {
|
|
456
455
|
query: queryPayload,
|
|
457
456
|
variables,
|
|
458
457
|
operationName: operation
|
|
@@ -558,10 +557,13 @@ var Requester = class {
|
|
|
558
557
|
"Missing node of encrypted_signing_private_key"
|
|
559
558
|
);
|
|
560
559
|
}
|
|
560
|
+
let TextEncoderImpl = TextEncoder;
|
|
561
561
|
if (typeof TextEncoder === "undefined") {
|
|
562
|
-
|
|
562
|
+
TextEncoderImpl = (await import("text-encoding")).TextEncoder;
|
|
563
563
|
}
|
|
564
|
-
const encodedPayload = new
|
|
564
|
+
const encodedPayload = new TextEncoderImpl().encode(
|
|
565
|
+
JSON.stringify(payload)
|
|
566
|
+
);
|
|
565
567
|
const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
|
|
566
568
|
const encodedSignedPayload = b64encode(signedPayload);
|
|
567
569
|
headers["X-Lightspark-Signing"] = JSON.stringify({
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import { Observable } from 'zen-observable-ts';
|
|
2
2
|
|
|
3
|
+
type Headers = Record<string, string>;
|
|
4
|
+
type WsConnectionParams = Record<string, unknown>;
|
|
3
5
|
interface AuthProvider {
|
|
4
|
-
addAuthHeaders(headers:
|
|
6
|
+
addAuthHeaders(headers: Headers): Promise<Headers>;
|
|
5
7
|
isAuthorized(): Promise<boolean>;
|
|
6
|
-
addWsConnectionParams(params:
|
|
8
|
+
addWsConnectionParams(params: WsConnectionParams): Promise<WsConnectionParams>;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
declare class LightsparkException extends Error {
|
|
10
12
|
code: string;
|
|
11
13
|
message: string;
|
|
12
|
-
extraInfo:
|
|
13
|
-
constructor(code: string, message: string, extraInfo?:
|
|
14
|
+
extraInfo: Record<string, unknown> | undefined;
|
|
15
|
+
constructor(code: string, message: string, extraInfo?: Record<string, unknown>);
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
declare class LightsparkAuthException extends LightsparkException {
|
|
17
|
-
constructor(message: string, extraInfo?:
|
|
19
|
+
constructor(message: string, extraInfo?: Record<string, unknown>);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
declare class StubAuthProvider implements AuthProvider {
|
|
21
|
-
addAuthHeaders(headers:
|
|
23
|
+
addAuthHeaders(headers: Headers): Promise<Headers>;
|
|
22
24
|
isAuthorized(): Promise<boolean>;
|
|
23
|
-
addWsConnectionParams(params:
|
|
25
|
+
addWsConnectionParams(params: WsConnectionParams): Promise<WsConnectionParams>;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
declare class LightsparkSigningException extends LightsparkException {
|
|
27
|
-
constructor(message: string, extraInfo?:
|
|
29
|
+
constructor(message: string, extraInfo?: Record<string, unknown>);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
type GeneratedKeyPair = {
|
|
@@ -79,7 +81,7 @@ type Query<T> = {
|
|
|
79
81
|
queryPayload: string;
|
|
80
82
|
/** The variables that will be passed to the query. **/
|
|
81
83
|
variables?: {
|
|
82
|
-
[key: string]:
|
|
84
|
+
[key: string]: unknown;
|
|
83
85
|
};
|
|
84
86
|
/** The function that will be called to construct the object from the response. **/
|
|
85
87
|
constructObject: (rawData: any) => T;
|
|
@@ -99,11 +101,13 @@ declare class Requester {
|
|
|
99
101
|
private readonly wsClient;
|
|
100
102
|
constructor(nodeKeyCache: NodeKeyCache, schemaEndpoint: string, sdkUserAgent: string, authProvider?: AuthProvider, baseUrl?: string, cryptoImpl?: CryptoInterface);
|
|
101
103
|
executeQuery<T>(query: Query<T>): Promise<T | null>;
|
|
102
|
-
subscribe(queryPayload: string, variables?: {
|
|
103
|
-
[key: string]:
|
|
104
|
-
}): Observable<
|
|
104
|
+
subscribe<T>(queryPayload: string, variables?: {
|
|
105
|
+
[key: string]: unknown;
|
|
106
|
+
}): Observable<{
|
|
107
|
+
data: T;
|
|
108
|
+
}>;
|
|
105
109
|
makeRawRequest(queryPayload: string, variables?: {
|
|
106
|
-
[key: string]:
|
|
110
|
+
[key: string]: unknown;
|
|
107
111
|
}, signingNodeId?: string | undefined, skipAuth?: boolean): Promise<any | null>;
|
|
108
112
|
private getSdkUserAgent;
|
|
109
113
|
private stripProtocol;
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ var StubAuthProvider = class {
|
|
|
37
37
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
38
38
|
var Base64 = {
|
|
39
39
|
btoa: (input = "") => {
|
|
40
|
-
|
|
40
|
+
const str = input;
|
|
41
41
|
let output = "";
|
|
42
42
|
for (let block = 0, charCode, i = 0, map = chars; str.charAt(i | 0) || (map = "=", i % 1); output += map.charAt(63 & block >> 8 - i % 1 * 8)) {
|
|
43
43
|
charCode = str.charCodeAt(i += 3 / 4);
|
|
@@ -51,7 +51,7 @@ var Base64 = {
|
|
|
51
51
|
return output;
|
|
52
52
|
},
|
|
53
53
|
atob: (input = "") => {
|
|
54
|
-
|
|
54
|
+
const str = input.replace(/=+$/, "");
|
|
55
55
|
let output = "";
|
|
56
56
|
if (str.length % 4 == 1) {
|
|
57
57
|
throw new Error(
|
|
@@ -153,8 +153,8 @@ var deriveKey = async (password, salt, iterations, algorithm, bit_len) => {
|
|
|
153
153
|
return [key, iv];
|
|
154
154
|
};
|
|
155
155
|
var decrypt = async (header_json, ciphertext, password) => {
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
let decoded = b64decode(ciphertext);
|
|
157
|
+
let header;
|
|
158
158
|
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
159
159
|
header = {
|
|
160
160
|
v: 0,
|
|
@@ -242,7 +242,6 @@ var serializeSigningKey = async (key, format) => {
|
|
|
242
242
|
);
|
|
243
243
|
};
|
|
244
244
|
var getNonce = async () => {
|
|
245
|
-
const cryptoImpl = await getCrypto();
|
|
246
245
|
const nonceSt = await getRandomValues32(new Uint32Array(1));
|
|
247
246
|
return Number(nonceSt);
|
|
248
247
|
};
|
|
@@ -400,7 +399,7 @@ var Requester = class {
|
|
|
400
399
|
}
|
|
401
400
|
}
|
|
402
401
|
const operation = operationMatch[2];
|
|
403
|
-
|
|
402
|
+
const bodyData = {
|
|
404
403
|
query: queryPayload,
|
|
405
404
|
variables,
|
|
406
405
|
operationName: operation
|
|
@@ -506,10 +505,13 @@ var Requester = class {
|
|
|
506
505
|
"Missing node of encrypted_signing_private_key"
|
|
507
506
|
);
|
|
508
507
|
}
|
|
508
|
+
let TextEncoderImpl = TextEncoder;
|
|
509
509
|
if (typeof TextEncoder === "undefined") {
|
|
510
|
-
|
|
510
|
+
TextEncoderImpl = (await import("text-encoding")).TextEncoder;
|
|
511
511
|
}
|
|
512
|
-
const encodedPayload = new
|
|
512
|
+
const encodedPayload = new TextEncoderImpl().encode(
|
|
513
|
+
JSON.stringify(payload)
|
|
514
|
+
);
|
|
513
515
|
const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
|
|
514
516
|
const encodedSignedPayload = b64encode(signedPayload);
|
|
515
517
|
headers["X-Lightspark-Signing"] = JSON.stringify({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightsparkdev/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Lightspark JS SDK",
|
|
5
5
|
"author": "Lightspark Inc.",
|
|
6
6
|
"keywords": [
|
|
@@ -48,14 +48,17 @@
|
|
|
48
48
|
],
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
51
|
-
"dev": "yarn build -- --watch",
|
|
52
51
|
"clean": "rm -rf .turbo && rm -rf dist",
|
|
53
|
-
"
|
|
54
|
-
"format": "prettier src --check",
|
|
52
|
+
"dev": "yarn build -- --watch",
|
|
55
53
|
"format:fix": "prettier src --write",
|
|
54
|
+
"format": "prettier src --check",
|
|
55
|
+
"lint:fix": "eslint --fix .",
|
|
56
|
+
"lint:watch": "esw ./src -w --ext .ts,.tsx,.js --color",
|
|
57
|
+
"lint": "eslint .",
|
|
58
|
+
"postversion": "yarn build",
|
|
56
59
|
"test": "echo \"TODO\"",
|
|
57
|
-
"types": "tsc",
|
|
58
|
-
"
|
|
60
|
+
"types:watch": "tsc-absolute --watch",
|
|
61
|
+
"types": "tsc"
|
|
59
62
|
},
|
|
60
63
|
"license": "Apache-2.0",
|
|
61
64
|
"dependencies": {
|
|
@@ -70,13 +73,17 @@
|
|
|
70
73
|
"zen-observable-ts": "^1.1.0"
|
|
71
74
|
},
|
|
72
75
|
"devDependencies": {
|
|
76
|
+
"@lightsparkdev/eslint-config": "*",
|
|
77
|
+
"@lightsparkdev/tsconfig": "0.0.0",
|
|
73
78
|
"@types/crypto-js": "^4.1.1",
|
|
74
79
|
"@types/ws": "^8.5.4",
|
|
80
|
+
"eslint": "^8.3.0",
|
|
81
|
+
"eslint-watch": "^8.0.0",
|
|
75
82
|
"jest": "^29.4.1",
|
|
76
83
|
"prettier": "2.8.7",
|
|
77
84
|
"prettier-plugin-organize-imports": "^3.2.2",
|
|
78
85
|
"ts-jest": "^29.0.5",
|
|
79
|
-
"
|
|
86
|
+
"tsc-absolute": "^1.0.1",
|
|
80
87
|
"tsup": "^6.7.0",
|
|
81
88
|
"typescript": "^4.9.5"
|
|
82
89
|
}
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
class LightsparkException extends Error {
|
|
4
4
|
code: string;
|
|
5
5
|
message: string;
|
|
6
|
-
extraInfo:
|
|
6
|
+
extraInfo: Record<string, unknown> | undefined;
|
|
7
7
|
|
|
8
|
-
constructor(
|
|
8
|
+
constructor(
|
|
9
|
+
code: string,
|
|
10
|
+
message: string,
|
|
11
|
+
extraInfo?: Record<string, unknown>
|
|
12
|
+
) {
|
|
9
13
|
super(message);
|
|
10
14
|
this.code = code;
|
|
11
15
|
this.message = message;
|
package/src/auth/AuthProvider.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
|
+
export type Headers = Record<string, string>;
|
|
4
|
+
export type WsConnectionParams = Record<string, unknown>;
|
|
5
|
+
|
|
3
6
|
export default interface AuthProvider {
|
|
4
|
-
addAuthHeaders(headers:
|
|
7
|
+
addAuthHeaders(headers: Headers): Promise<Headers>;
|
|
5
8
|
isAuthorized(): Promise<boolean>;
|
|
6
|
-
addWsConnectionParams(
|
|
9
|
+
addWsConnectionParams(
|
|
10
|
+
params: WsConnectionParams
|
|
11
|
+
): Promise<WsConnectionParams>;
|
|
7
12
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import LightsparkException from "../LightsparkException.js";
|
|
4
4
|
|
|
5
5
|
class LightsparkAuthException extends LightsparkException {
|
|
6
|
-
constructor(message: string, extraInfo?:
|
|
6
|
+
constructor(message: string, extraInfo?: Record<string, unknown>) {
|
|
7
7
|
super("AuthException", message, extraInfo);
|
|
8
8
|
}
|
|
9
9
|
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
|
-
import AuthProvider
|
|
3
|
+
import AuthProvider, {
|
|
4
|
+
type Headers,
|
|
5
|
+
type WsConnectionParams,
|
|
6
|
+
} from "./AuthProvider.js";
|
|
4
7
|
|
|
5
8
|
export default class StubAuthProvider implements AuthProvider {
|
|
6
|
-
async addAuthHeaders(headers:
|
|
9
|
+
async addAuthHeaders(headers: Headers) {
|
|
7
10
|
return headers;
|
|
8
11
|
}
|
|
9
12
|
async isAuthorized(): Promise<boolean> {
|
|
10
13
|
return false;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
async addWsConnectionParams(params:
|
|
16
|
+
async addWsConnectionParams(params: WsConnectionParams) {
|
|
14
17
|
return params;
|
|
15
18
|
}
|
|
16
19
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import LightsparkException from "../LightsparkException.js";
|
|
4
4
|
|
|
5
5
|
class LightsparkSigningException extends LightsparkException {
|
|
6
|
-
constructor(message: string, extraInfo?:
|
|
6
|
+
constructor(message: string, extraInfo?: Record<string, unknown>) {
|
|
7
7
|
super("SigningException", message, extraInfo);
|
|
8
8
|
}
|
|
9
9
|
}
|
package/src/crypto/crypto.ts
CHANGED
|
@@ -122,9 +122,9 @@ const decrypt = async (
|
|
|
122
122
|
ciphertext: string,
|
|
123
123
|
password: string
|
|
124
124
|
): Promise<ArrayBuffer> => {
|
|
125
|
-
|
|
125
|
+
let decoded = b64decode(ciphertext);
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
let header;
|
|
128
128
|
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
129
129
|
header = {
|
|
130
130
|
v: 0,
|
|
@@ -225,7 +225,6 @@ const serializeSigningKey = async (
|
|
|
225
225
|
};
|
|
226
226
|
|
|
227
227
|
const getNonce = async () => {
|
|
228
|
-
const cryptoImpl = await getCrypto();
|
|
229
228
|
const nonceSt = await getRandomValues32(new Uint32Array(1));
|
|
230
229
|
return Number(nonceSt);
|
|
231
230
|
};
|
package/src/requester/Query.ts
CHANGED
|
@@ -5,10 +5,10 @@ type Query<T> = {
|
|
|
5
5
|
queryPayload: string;
|
|
6
6
|
|
|
7
7
|
/** The variables that will be passed to the query. **/
|
|
8
|
-
variables?: { [key: string]:
|
|
8
|
+
variables?: { [key: string]: unknown };
|
|
9
9
|
|
|
10
10
|
/** The function that will be called to construct the object from the response. **/
|
|
11
|
-
constructObject: (rawData: any) => T;
|
|
11
|
+
constructObject: (rawData: any) => T; // eslint-disable-line @typescript-eslint/no-explicit-any -- LIG-3400
|
|
12
12
|
|
|
13
13
|
/** The id of the node that will be used to sign the query. **/
|
|
14
14
|
signingNodeId?: string;
|
|
@@ -65,10 +65,10 @@ class Requester {
|
|
|
65
65
|
return query.constructObject(data);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
public subscribe(
|
|
68
|
+
public subscribe<T>(
|
|
69
69
|
queryPayload: string,
|
|
70
|
-
variables: { [key: string]:
|
|
71
|
-
)
|
|
70
|
+
variables: { [key: string]: unknown } = {}
|
|
71
|
+
) {
|
|
72
72
|
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
73
73
|
const operationMatch = queryPayload.match(operationNameRegex);
|
|
74
74
|
if (!operationMatch || operationMatch.length < 3) {
|
|
@@ -88,15 +88,15 @@ class Requester {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
const operation = operationMatch[2];
|
|
91
|
-
|
|
91
|
+
const bodyData = {
|
|
92
92
|
query: queryPayload,
|
|
93
93
|
variables,
|
|
94
94
|
operationName: operation,
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
return new Observable((observer) =>
|
|
97
|
+
return new Observable<{ data: T }>((observer) =>
|
|
98
98
|
this.wsClient.subscribe(bodyData, {
|
|
99
|
-
next: (data) => observer.next(data),
|
|
99
|
+
next: (data) => observer.next(data as { data: T }),
|
|
100
100
|
error: (err) => observer.error(err),
|
|
101
101
|
complete: () => observer.complete(),
|
|
102
102
|
})
|
|
@@ -105,9 +105,10 @@ class Requester {
|
|
|
105
105
|
|
|
106
106
|
public async makeRawRequest(
|
|
107
107
|
queryPayload: string,
|
|
108
|
-
variables: { [key: string]:
|
|
108
|
+
variables: { [key: string]: unknown } = {},
|
|
109
109
|
signingNodeId: string | undefined = undefined,
|
|
110
110
|
skipAuth: boolean = false
|
|
111
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- LIG-3400 */
|
|
111
112
|
): Promise<any | null> {
|
|
112
113
|
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
113
114
|
const operationMatch = queryPayload.match(operationNameRegex);
|
|
@@ -191,9 +192,10 @@ class Requester {
|
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
private async addSigningDataIfNeeded(
|
|
194
|
-
queryPayload: { query: string; variables:
|
|
195
|
+
queryPayload: { query: string; variables: unknown; operationName: string },
|
|
195
196
|
headers: { [key: string]: string },
|
|
196
197
|
signingNodeId: string | undefined
|
|
198
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- LIG-3400 */
|
|
197
199
|
): Promise<any> {
|
|
198
200
|
if (!signingNodeId) {
|
|
199
201
|
return queryPayload;
|
|
@@ -221,10 +223,13 @@ class Requester {
|
|
|
221
223
|
);
|
|
222
224
|
}
|
|
223
225
|
|
|
226
|
+
let TextEncoderImpl = TextEncoder;
|
|
224
227
|
if (typeof TextEncoder === "undefined") {
|
|
225
|
-
|
|
228
|
+
TextEncoderImpl = (await import("text-encoding")).TextEncoder;
|
|
226
229
|
}
|
|
227
|
-
const encodedPayload = new
|
|
230
|
+
const encodedPayload = new TextEncoderImpl().encode(
|
|
231
|
+
JSON.stringify(payload)
|
|
232
|
+
);
|
|
228
233
|
const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
|
|
229
234
|
const encodedSignedPayload = b64encode(signedPayload);
|
|
230
235
|
|
package/src/utils/base64.ts
CHANGED
|
@@ -4,7 +4,7 @@ const chars =
|
|
|
4
4
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
5
5
|
const Base64 = {
|
|
6
6
|
btoa: (input: string = "") => {
|
|
7
|
-
|
|
7
|
+
const str = input;
|
|
8
8
|
let output = "";
|
|
9
9
|
|
|
10
10
|
for (
|
|
@@ -27,7 +27,7 @@ const Base64 = {
|
|
|
27
27
|
},
|
|
28
28
|
|
|
29
29
|
atob: (input: string = "") => {
|
|
30
|
-
|
|
30
|
+
const str = input.replace(/=+$/, "");
|
|
31
31
|
let output = "";
|
|
32
32
|
|
|
33
33
|
if (str.length % 4 == 1) {
|