@anmiles/google-api-wrapper 15.2.0 → 16.0.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.
- package/.eslintrc.js +0 -7
- package/CHANGELOG.md +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/api.d.ts +3 -3
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +16 -10
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth.d.ts +1 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +2 -2
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/paths.d.ts +1 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/profiles.d.ts +1 -0
- package/dist/lib/profiles.d.ts.map +1 -0
- package/dist/lib/profiles.js.map +1 -1
- package/dist/lib/renderer.d.ts +5 -2
- package/dist/lib/renderer.d.ts.map +1 -0
- package/dist/lib/renderer.js +6 -3
- package/dist/lib/renderer.js.map +1 -1
- package/dist/lib/secrets.d.ts +1 -0
- package/dist/lib/secrets.d.ts.map +1 -0
- package/dist/lib/secrets.js +5 -5
- package/dist/lib/secrets.js.map +1 -1
- package/dist/templates/auth.html +2 -1
- package/dist/templates/css.html +111 -0
- package/dist/templates/page.html +1 -110
- package/dist/types/common.d.ts +1 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/secrets.d.ts +1 -0
- package/dist/types/secrets.d.ts.map +1 -0
- package/jest.config.js +6 -4
- package/package.json +22 -25
- package/src/lib/__tests__/api.test.ts +7 -1
- package/src/lib/__tests__/renderer.test.ts +4 -3
- package/src/lib/__tests__/secrets.test.ts +3 -3
- package/src/lib/api.ts +15 -14
- package/src/lib/renderer.ts +6 -3
- package/src/lib/secrets.ts +2 -2
- package/src/templates/auth.html +2 -1
- package/src/templates/css.html +111 -0
- package/src/templates/page.html +1 -110
- package/src/types/out-url.d.ts +3 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +5 -19
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<style type="text/css">
|
|
2
|
+
* {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
html, body {
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 100%;
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
font-family: Arial, sans-serif;
|
|
15
|
+
font-size: 17px;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
padding: 30px 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.box {
|
|
23
|
+
width: 450px;
|
|
24
|
+
min-height: 500px;
|
|
25
|
+
max-height: 100%;
|
|
26
|
+
padding: 82px 40px 28px 40px;
|
|
27
|
+
margin: 1em;
|
|
28
|
+
border: 1px solid #dadce0;
|
|
29
|
+
border-radius: 8px;
|
|
30
|
+
position: relative;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
align-items: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.box:before {
|
|
37
|
+
width: 100%;
|
|
38
|
+
height: 34px;
|
|
39
|
+
border-bottom: 1px solid #dadce0;
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 0;
|
|
42
|
+
display: block;
|
|
43
|
+
content: '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
h1 {
|
|
47
|
+
font-size: 24px;
|
|
48
|
+
line-height: 40px;
|
|
49
|
+
font-weight: normal;
|
|
50
|
+
margin: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
p {
|
|
54
|
+
line-height: 32px;
|
|
55
|
+
margin: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ul {
|
|
59
|
+
width: 100%;
|
|
60
|
+
margin: 18px 0 30px 0;
|
|
61
|
+
padding-left: 0;
|
|
62
|
+
border-top: 1px solid #dadce0;
|
|
63
|
+
list-style-type: none;
|
|
64
|
+
overflow: auto;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
li {
|
|
68
|
+
line-height: 48px;
|
|
69
|
+
color: brown;
|
|
70
|
+
border-bottom: 1px solid #dadce0;
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
li:before {
|
|
76
|
+
content: 'W';
|
|
77
|
+
width: 28px;
|
|
78
|
+
height: 28px;
|
|
79
|
+
border-radius: 50%;
|
|
80
|
+
border: 2px solid currentColor;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: center;
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
margin-right: 10px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
li.readonly {
|
|
89
|
+
color: darkgreen;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
li.readonly:before {
|
|
93
|
+
content: 'R';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
a {
|
|
97
|
+
width: 50%;
|
|
98
|
+
padding: 0 24px;
|
|
99
|
+
line-height: 36px;
|
|
100
|
+
margin: auto;
|
|
101
|
+
color: #ffffff;
|
|
102
|
+
background: #1a73e8;
|
|
103
|
+
border-radius: 4px;
|
|
104
|
+
outline: none;
|
|
105
|
+
display: block;
|
|
106
|
+
text-align: center;
|
|
107
|
+
text-decoration: none;
|
|
108
|
+
font-weight: bold;
|
|
109
|
+
font-size: 15px;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
package/dist/templates/page.html
CHANGED
|
@@ -1,113 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* {
|
|
3
|
-
box-sizing: border-box;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
html, body {
|
|
7
|
-
width: 100%;
|
|
8
|
-
height: 100%;
|
|
9
|
-
margin: 0;
|
|
10
|
-
padding: 0;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
body {
|
|
14
|
-
font-family: Arial, sans-serif;
|
|
15
|
-
font-size: 17px;
|
|
16
|
-
display: flex;
|
|
17
|
-
align-items: center;
|
|
18
|
-
justify-content: center;
|
|
19
|
-
padding: 30px 0;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.box {
|
|
23
|
-
width: 450px;
|
|
24
|
-
min-height: 500px;
|
|
25
|
-
max-height: 100%;
|
|
26
|
-
padding: 82px 40px 28px 40px;
|
|
27
|
-
margin: 1em;
|
|
28
|
-
border: 1px solid #dadce0;
|
|
29
|
-
border-radius: 8px;
|
|
30
|
-
position: relative;
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: column;
|
|
33
|
-
align-items: center;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.box:before {
|
|
37
|
-
width: 100%;
|
|
38
|
-
height: 34px;
|
|
39
|
-
border-bottom: 1px solid #dadce0;
|
|
40
|
-
position: absolute;
|
|
41
|
-
top: 0;
|
|
42
|
-
display: block;
|
|
43
|
-
content: '';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
h1 {
|
|
47
|
-
font-size: 24px;
|
|
48
|
-
line-height: 40px;
|
|
49
|
-
font-weight: normal;
|
|
50
|
-
margin: 0;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
p {
|
|
54
|
-
line-height: 32px;
|
|
55
|
-
margin: 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
ul {
|
|
59
|
-
width: 100%;
|
|
60
|
-
margin: 18px 0 30px 0;
|
|
61
|
-
padding-left: 0;
|
|
62
|
-
border-top: 1px solid #dadce0;
|
|
63
|
-
list-style-type: none;
|
|
64
|
-
overflow: auto;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
li {
|
|
68
|
-
line-height: 48px;
|
|
69
|
-
color: brown;
|
|
70
|
-
border-bottom: 1px solid #dadce0;
|
|
71
|
-
display: flex;
|
|
72
|
-
align-items: center;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
li:before {
|
|
76
|
-
content: 'W';
|
|
77
|
-
width: 28px;
|
|
78
|
-
height: 28px;
|
|
79
|
-
border-radius: 50%;
|
|
80
|
-
border: 2px solid currentColor;
|
|
81
|
-
display: flex;
|
|
82
|
-
align-items: center;
|
|
83
|
-
justify-content: center;
|
|
84
|
-
font-size: 14px;
|
|
85
|
-
margin-right: 10px;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
li.readonly {
|
|
89
|
-
color: darkgreen;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
li.readonly:before {
|
|
93
|
-
content: 'R';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
a {
|
|
97
|
-
width: 50%;
|
|
98
|
-
padding: 0 24px;
|
|
99
|
-
line-height: 36px;
|
|
100
|
-
margin: auto;
|
|
101
|
-
color: #ffffff;
|
|
102
|
-
background: #1a73e8;
|
|
103
|
-
border-radius: 4px;
|
|
104
|
-
display: block;
|
|
105
|
-
text-align: center;
|
|
106
|
-
text-decoration: none;
|
|
107
|
-
font-weight: bold;
|
|
108
|
-
font-size: 15px;
|
|
109
|
-
}
|
|
110
|
-
</style>
|
|
1
|
+
${css}
|
|
111
2
|
<div class="box">
|
|
112
3
|
${content}
|
|
113
4
|
</div>
|
package/dist/types/common.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/types/common.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAA;CACtB"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
|
package/dist/types/secrets.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/types/secrets.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACvB,GAAG,EAAE;QACJ,SAAS,EAAE,GAAG,MAAM,6BAA6B,CAAC;QAClD,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,2CAA2C,CAAC;QACtD,SAAS,EAAE,qCAAqC,CAAC;QACjD,2BAA2B,EAAE,4CAA4C,CAAC;QAC1E,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB"}
|
package/jest.config.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
preset
|
|
2
|
+
preset : 'ts-jest',
|
|
3
|
+
transform : {
|
|
4
|
+
'^.+\\.tsx?$' : 'ts-jest',
|
|
5
|
+
},
|
|
6
|
+
|
|
3
7
|
clearMocks : true,
|
|
4
8
|
|
|
5
9
|
roots : [ '<rootDir>/src' ],
|
|
6
10
|
testMatch : [ '<rootDir>/src/**/__tests__/*.test.ts' ],
|
|
7
|
-
|
|
8
|
-
'^.+\\.ts$' : 'ts-jest',
|
|
9
|
-
},
|
|
11
|
+
|
|
10
12
|
collectCoverageFrom : [
|
|
11
13
|
'<rootDir>/src/**/*.ts',
|
|
12
14
|
'!<rootDir>/src/**/*.d.ts',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anmiles/google-api-wrapper",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"description": "Provides quick interface for getting google API data",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"google",
|
|
@@ -16,45 +16,42 @@
|
|
|
16
16
|
},
|
|
17
17
|
"main": "dist/index.js",
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "rimraf dist && tsc && copyfiles -u 1 src/templates/* dist/",
|
|
20
|
-
"lint": "eslint --ext .js,.ts .",
|
|
19
|
+
"build": "rimraf dist && tsc -p ./tsconfig.build.json && copyfiles -u 1 src/templates/* dist/",
|
|
20
|
+
"lint": "eslint --ext .js,.ts --ignore-path .gitignore .",
|
|
21
21
|
"lint:fix": "npm run lint -- --fix",
|
|
22
22
|
"test": "jest --verbose",
|
|
23
23
|
"test:coverage": "npm test -- --coverage",
|
|
24
24
|
"test:ci": "npm test -- --ci --coverage",
|
|
25
25
|
"test:watch": "npm test -- --watch",
|
|
26
26
|
"test:watch:coverage": "npm test -- --watch --coverage",
|
|
27
|
-
"test:report:coverage": "nyc report --nycrc-path ./coverage.config.js -t ./coverage --report-dir ./coverage"
|
|
28
|
-
"create": "node ./dist/create.js",
|
|
29
|
-
"login": "node ./dist/login.js"
|
|
27
|
+
"test:report:coverage": "nyc report --nycrc-path ./coverage.config.js -t ./coverage --report-dir ./coverage"
|
|
30
28
|
},
|
|
31
29
|
"dependencies": {
|
|
32
|
-
"@anmiles/
|
|
33
|
-
"@anmiles/
|
|
34
|
-
"@anmiles/
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"googleapis": "^126.0.1",
|
|
38
|
-
"open": "^8.4.2",
|
|
30
|
+
"@anmiles/logger": "^6.0.0",
|
|
31
|
+
"@anmiles/prototypes": "^7.0.0",
|
|
32
|
+
"@anmiles/sleep": "^3.0.0",
|
|
33
|
+
"googleapis": "^130.0.0",
|
|
34
|
+
"out-url": "^1.1.3",
|
|
39
35
|
"server-destroy": "^1.0.1"
|
|
40
36
|
},
|
|
41
37
|
"devDependencies": {
|
|
42
|
-
"@anmiles/eslint-config": "^
|
|
43
|
-
"@
|
|
44
|
-
"@types/
|
|
45
|
-
"@types/
|
|
46
|
-
"@
|
|
47
|
-
"@typescript-eslint/
|
|
38
|
+
"@anmiles/eslint-config": "^5.0.0",
|
|
39
|
+
"@anmiles/tsconfig": "^2.0.0",
|
|
40
|
+
"@types/event-emitter": "^0.3.5",
|
|
41
|
+
"@types/jest": "^29.5.11",
|
|
42
|
+
"@types/server-destroy": "^1.0.3",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
44
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
48
45
|
"copyfiles": "^2.4.1",
|
|
49
|
-
"eslint": "^8.
|
|
46
|
+
"eslint": "^8.56.0",
|
|
50
47
|
"eslint-plugin-align-assignments": "^1.1.2",
|
|
51
|
-
"eslint-plugin-import": "^2.
|
|
52
|
-
"eslint-plugin-jest": "^27.
|
|
48
|
+
"eslint-plugin-import": "^2.29.1",
|
|
49
|
+
"eslint-plugin-jest": "^27.6.3",
|
|
53
50
|
"event-emitter": "^0.3.5",
|
|
54
|
-
"jest": "^29.
|
|
51
|
+
"jest": "^29.7.0",
|
|
55
52
|
"nyc": "^15.1.0",
|
|
56
|
-
"rimraf": "^5.0.
|
|
53
|
+
"rimraf": "^5.0.5",
|
|
57
54
|
"ts-jest": "^29.1.1",
|
|
58
|
-
"typescript": "^5.
|
|
55
|
+
"typescript": "^5.3.3"
|
|
59
56
|
}
|
|
60
57
|
}
|
|
@@ -108,7 +108,7 @@ describe('src/lib/api', () => {
|
|
|
108
108
|
it('should return instance wrapper for google api', async () => {
|
|
109
109
|
const instance = await api.getAPI('calendar', profile, { scopes, temporary : true });
|
|
110
110
|
|
|
111
|
-
expect(instance).toEqual({ apiName : 'calendar', profile, authOptions : { scopes, temporary : true }, api : calendarAPI
|
|
111
|
+
expect(instance).toEqual({ apiName : 'calendar', profile, authOptions : { scopes, temporary : true }, api : calendarAPI });
|
|
112
112
|
});
|
|
113
113
|
|
|
114
114
|
it('should warn when creating permanent credentials using non-readonly scopes', async () => {
|
|
@@ -228,6 +228,12 @@ describe('src/lib/api', () => {
|
|
|
228
228
|
|
|
229
229
|
expect(items).toEqual(items);
|
|
230
230
|
});
|
|
231
|
+
|
|
232
|
+
it('should throw if api was not initialized before getting items', async () => {
|
|
233
|
+
instance = new api.API('calendar', profile);
|
|
234
|
+
|
|
235
|
+
await expect(() => instance.getItems((api) => api.calendarList, args)).rejects.toEqual('API is not initialized. Call `init` before getting items.');
|
|
236
|
+
});
|
|
231
237
|
});
|
|
232
238
|
});
|
|
233
239
|
});
|
|
@@ -36,7 +36,8 @@ jest.mock<Partial<typeof paths>>('../paths', () => ({
|
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
38
|
const mockTemplates: Record<TemplateName, string> = {
|
|
39
|
-
page : 'page content = (${content})',
|
|
39
|
+
page : 'page css = (${css}) content = (${content})',
|
|
40
|
+
css : 'css',
|
|
40
41
|
auth : 'auth profile = (${profile}) authUrl = (${authUrl}) scopesList = (${scopesList})',
|
|
41
42
|
scope : 'scope type = (${type}) title = (${title}) name = (${name})',
|
|
42
43
|
done : 'done profile = (${profile})',
|
|
@@ -50,14 +51,14 @@ describe('src/lib/renderer', () => {
|
|
|
50
51
|
describe('renderAuth', () => {
|
|
51
52
|
it('should return auth page', () => {
|
|
52
53
|
const result = original.renderAuth({ authUrl, profile, scope });
|
|
53
|
-
expect(result).toEqual('page content = (auth profile = (username) authUrl = (https://authUrl) scopesList = (scope type = (readonly) title = (Readonly (cannot change or delete your data)) name = (scope1.readonly)\nscope type = () title = (Writable (can change or delete your data)) name = (scope2)))');
|
|
54
|
+
expect(result).toEqual('page css = (css) content = (auth profile = (username) authUrl = (https://authUrl) scopesList = (scope type = (readonly) title = (Readonly (cannot change or delete your data)) name = (scope1.readonly)\nscope type = () title = (Writable (can change or delete your data)) name = (scope2)))');
|
|
54
55
|
});
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
describe('renderDone', () => {
|
|
58
59
|
it('should return done page', () => {
|
|
59
60
|
const result = original.renderDone({ profile });
|
|
60
|
-
expect(result).toEqual('page content = (done profile = (username))');
|
|
61
|
+
expect(result).toEqual('page css = (css) content = (done profile = (username))');
|
|
61
62
|
});
|
|
62
63
|
});
|
|
63
64
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import http from 'http';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import open from '
|
|
4
|
+
import { open } from 'out-url';
|
|
5
5
|
import type GoogleApis from 'googleapis';
|
|
6
6
|
import logger from '@anmiles/logger';
|
|
7
7
|
import emitter from 'event-emitter';
|
|
@@ -54,8 +54,8 @@ jest.mock<Partial<typeof path>>('path', () => ({
|
|
|
54
54
|
join : jest.fn().mockImplementation((...args) => args.join('/')),
|
|
55
55
|
}));
|
|
56
56
|
|
|
57
|
-
jest.mock('
|
|
58
|
-
makeRequest(url.replace('http://localhost:6006', ''))
|
|
57
|
+
jest.mock<{ open: typeof open }>('out-url', () => ({
|
|
58
|
+
open : jest.fn().mockImplementation(async (url) => makeRequest(url.replace('http://localhost:6006', ''))),
|
|
59
59
|
}));
|
|
60
60
|
|
|
61
61
|
jest.mock<Partial<typeof logger>>('@anmiles/logger', () => ({
|
package/src/lib/api.ts
CHANGED
|
@@ -24,22 +24,17 @@ type CommonResponse<TItem> = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
class API<TKey extends keyof typeof allAPIs> {
|
|
27
|
-
api: ReturnType<typeof allAPIs[TKey]
|
|
28
|
-
private auth: GoogleApis.Common.OAuth2Client;
|
|
27
|
+
api: ReturnType<typeof allAPIs[TKey]> | undefined;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.apiName = apiName;
|
|
36
|
-
this.profile = profile;
|
|
37
|
-
this.authOptions = authOptions;
|
|
38
|
-
}
|
|
29
|
+
constructor(
|
|
30
|
+
private apiName: TKey,
|
|
31
|
+
private profile: string,
|
|
32
|
+
private authOptions?: AuthOptions,
|
|
33
|
+
) { }
|
|
39
34
|
|
|
40
35
|
async init() {
|
|
41
|
-
|
|
42
|
-
this.api
|
|
36
|
+
const auth = await getAuth(this.profile, this.authOptions);
|
|
37
|
+
this.api = allAPIs[this.apiName](auth) as ReturnType<typeof allAPIs[TKey]>;
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
async getItems<TItem>(selectAPI: (api: ReturnType<typeof allAPIs[TKey]>) => CommonAPI<TItem>, params: any, options?: CommonOptions): Promise<TItem[]> {
|
|
@@ -51,9 +46,15 @@ class API<TKey extends keyof typeof allAPIs> {
|
|
|
51
46
|
let response: GoogleApis.Common.GaxiosResponse<CommonResponse<TItem>>;
|
|
52
47
|
|
|
53
48
|
try {
|
|
49
|
+
if (!this.api) {
|
|
50
|
+
throw 'API is not initialized. Call `init` before getting items.';
|
|
51
|
+
}
|
|
52
|
+
|
|
54
53
|
response = await selectAPI(this.api).list({ ...params, pageToken });
|
|
55
54
|
} catch (ex) {
|
|
56
|
-
|
|
55
|
+
const message = ex instanceof Error ? ex.message : ex as string;
|
|
56
|
+
|
|
57
|
+
if ((message === 'invalid_grant' || message === 'Invalid credentials') && !this.authOptions?.temporary) {
|
|
57
58
|
warn('Access token stored is invalid, re-creating...');
|
|
58
59
|
deleteCredentials(this.profile);
|
|
59
60
|
await this.init();
|
package/src/lib/renderer.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { getTemplateFile } from './paths';
|
|
|
5
5
|
export { templates, renderAuth, renderDone };
|
|
6
6
|
|
|
7
7
|
const templates = {
|
|
8
|
-
page : [ 'content' ] as const,
|
|
8
|
+
page : [ 'css', 'content' ] as const,
|
|
9
|
+
css : [ ] as const,
|
|
9
10
|
auth : [ 'profile', 'authUrl', 'scopesList' ],
|
|
10
11
|
scope : [ 'type', 'title', 'name' ] as const,
|
|
11
12
|
done : [ 'profile' ] as const,
|
|
@@ -22,13 +23,15 @@ function renderAuth({ profile, authUrl, scope }: { profile: string, authUrl: str
|
|
|
22
23
|
type : s.endsWith('.readonly') ? 'readonly' : '',
|
|
23
24
|
})).join('\n');
|
|
24
25
|
|
|
26
|
+
const css = render('css', {});
|
|
25
27
|
const content = render('auth', { profile, authUrl, scopesList });
|
|
26
|
-
return render('page', { content });
|
|
28
|
+
return render('page', { css, content });
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
function renderDone({ profile }: { profile: string }): string {
|
|
32
|
+
const css = render('css', {});
|
|
30
33
|
const content = render('done', { profile });
|
|
31
|
-
return render('page', { content });
|
|
34
|
+
return render('page', { css, content });
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
// TODO: Use react
|
package/src/lib/secrets.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import http from 'http';
|
|
3
|
+
import { open } from 'out-url';
|
|
3
4
|
import enableDestroy from 'server-destroy';
|
|
4
|
-
import open from 'open';
|
|
5
5
|
import type GoogleApis from 'googleapis';
|
|
6
6
|
import { warn } from '@anmiles/logger';
|
|
7
7
|
import type { Secrets, AuthOptions } from '../types';
|
|
@@ -115,7 +115,7 @@ async function createCredentials(profile: string, auth: GoogleApis.Auth.OAuth2Cl
|
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
server.once('listening', () => {
|
|
118
|
+
server.once('listening', async () => {
|
|
119
119
|
warn('Please check your browser for further actions');
|
|
120
120
|
open(startURI);
|
|
121
121
|
});
|
package/src/templates/auth.html
CHANGED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<style type="text/css">
|
|
2
|
+
* {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
html, body {
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 100%;
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
font-family: Arial, sans-serif;
|
|
15
|
+
font-size: 17px;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
padding: 30px 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.box {
|
|
23
|
+
width: 450px;
|
|
24
|
+
min-height: 500px;
|
|
25
|
+
max-height: 100%;
|
|
26
|
+
padding: 82px 40px 28px 40px;
|
|
27
|
+
margin: 1em;
|
|
28
|
+
border: 1px solid #dadce0;
|
|
29
|
+
border-radius: 8px;
|
|
30
|
+
position: relative;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
align-items: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.box:before {
|
|
37
|
+
width: 100%;
|
|
38
|
+
height: 34px;
|
|
39
|
+
border-bottom: 1px solid #dadce0;
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 0;
|
|
42
|
+
display: block;
|
|
43
|
+
content: '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
h1 {
|
|
47
|
+
font-size: 24px;
|
|
48
|
+
line-height: 40px;
|
|
49
|
+
font-weight: normal;
|
|
50
|
+
margin: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
p {
|
|
54
|
+
line-height: 32px;
|
|
55
|
+
margin: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ul {
|
|
59
|
+
width: 100%;
|
|
60
|
+
margin: 18px 0 30px 0;
|
|
61
|
+
padding-left: 0;
|
|
62
|
+
border-top: 1px solid #dadce0;
|
|
63
|
+
list-style-type: none;
|
|
64
|
+
overflow: auto;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
li {
|
|
68
|
+
line-height: 48px;
|
|
69
|
+
color: brown;
|
|
70
|
+
border-bottom: 1px solid #dadce0;
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
li:before {
|
|
76
|
+
content: 'W';
|
|
77
|
+
width: 28px;
|
|
78
|
+
height: 28px;
|
|
79
|
+
border-radius: 50%;
|
|
80
|
+
border: 2px solid currentColor;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: center;
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
margin-right: 10px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
li.readonly {
|
|
89
|
+
color: darkgreen;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
li.readonly:before {
|
|
93
|
+
content: 'R';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
a {
|
|
97
|
+
width: 50%;
|
|
98
|
+
padding: 0 24px;
|
|
99
|
+
line-height: 36px;
|
|
100
|
+
margin: auto;
|
|
101
|
+
color: #ffffff;
|
|
102
|
+
background: #1a73e8;
|
|
103
|
+
border-radius: 4px;
|
|
104
|
+
outline: none;
|
|
105
|
+
display: block;
|
|
106
|
+
text-align: center;
|
|
107
|
+
text-decoration: none;
|
|
108
|
+
font-weight: bold;
|
|
109
|
+
font-size: 15px;
|
|
110
|
+
}
|
|
111
|
+
</style>
|