Skip to content
This repository was archived by the owner on Aug 23, 2024. It is now read-only.

Commit 2527af5

Browse files
authored
Merge pull request Shopify#311 from Shopify/paulo/add_base_rest_resource
Add base rest resource
2 parents e650d67 + d27ea46 commit 2527af5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1483
-726
lines changed

.eslintrc.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,30 @@ module.exports = {
33
browser: false,
44
es2021: true,
55
},
6-
plugins: ['@shopify'],
7-
extends: ['plugin:@shopify/typescript'],
6+
extends: ['plugin:@shopify/typescript', 'plugin:@shopify/prettier'],
87
ignorePatterns: ['dist/'],
98
rules: {
109
'import/no-named-as-default': 0,
1110
'no-mixed-operators': 0,
1211
'no-console': 0,
1312
},
13+
overrides: [
14+
{
15+
files: [
16+
'src/rest_resources/__tests__/*.ts',
17+
'src/rest_resources/base.ts',
18+
'src/rest_resources/admin*/*.ts',
19+
],
20+
rules: {
21+
'@typescript-eslint/naming-convention': [
22+
'error',
23+
{
24+
selector: 'default',
25+
// Allow snake_case so we can have properties that follow the API's naming conventions
26+
format: ['camelCase', 'PascalCase', 'snake_case', 'UPPER_CASE'],
27+
},
28+
],
29+
},
30+
},
31+
],
1432
};

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
1414

1515
### Fixed
1616

17+
- ⚠️ [Breaking] Stop responding to the request in the GraphQL Proxy function, returning Shopify's response instead [#312](https://github.com/Shopify/shopify-node-api/pull/312)
18+
1719
## [2.1.0] - 2022-02-03
1820

1921
### Added

jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ module.exports = {
66
testRegex: '.*\\.test\\.tsx?$',
77
coverageDirectory: './coverage/',
88
collectCoverage: true,
9+
setupFilesAfterEnv: ['<rootDir>/src/utils/setup-jest.ts'],
910
};

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,18 @@
5050
"uuid": "^8.3.1"
5151
},
5252
"devDependencies": {
53-
"@shopify/eslint-plugin": "^41.0.1",
53+
"@shopify/eslint-plugin": "^41.1.0",
5454
"@shopify/prettier-config": "^1.1.2",
5555
"@types/cookies": "^0.7.5",
5656
"@types/jest": "^26.0.15",
5757
"@types/node": "^14.14.1",
5858
"@types/uuid": "^8.3.0",
5959
"eslint": "^7.30.0",
60-
"eslint-plugin-tsdoc": "^0.2.7",
60+
"eslint-plugin-prettier": "^4.0.0",
6161
"express": "^4.17.1",
6262
"jest": "^27.4.3",
6363
"jest-fetch-mock": "^3.0.3",
64-
"prettier": "^2.3.2",
64+
"prettier": "^2.5.1",
6565
"rimraf": "^3.0.2",
6666
"supertest": "^6.1.3",
6767
"ts-jest": "^27.1.1",

src/test/context.test.ts src/__tests__/context.test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import './test_helper';
2-
31
import Cookies from 'cookies';
42

53
import * as ShopifyErrors from '../error';

src/auth/oauth/test/oauth.test.ts src/auth/oauth/__tests__/oauth.test.ts

+44-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import '../../../test/test_helper';
2-
31
import querystring from 'querystring';
42
import http from 'http';
53

@@ -94,7 +92,13 @@ describe('beginAuth', () => {
9492
});
9593

9694
test('returns the correct auth url for given info', async () => {
97-
const authRoute = await ShopifyOAuth.beginAuth(req, res, shop, '/some-callback', false);
95+
const authRoute = await ShopifyOAuth.beginAuth(
96+
req,
97+
res,
98+
shop,
99+
'/some-callback',
100+
false,
101+
);
98102
const session = await Context.SESSION_STORAGE.loadSession(cookies.id);
99103
/* eslint-disable @typescript-eslint/naming-convention */
100104
const query = {
@@ -170,7 +174,7 @@ describe('validateAuthCallback', () => {
170174
res = {} as http.ServerResponse;
171175

172176
Cookies.prototype.set.mockImplementation(
173-
(cookieName: string, cookieValue: string, options: {expires: Date;}) => {
177+
(cookieName: string, cookieValue: string, options: {expires: Date}) => {
174178
expect(cookieName).toBe('shopify_app_session');
175179
cookies.id = cookieValue;
176180
cookies.expires = options.expires;
@@ -383,7 +387,11 @@ describe('validateAuthCallback', () => {
383387
testCallbackQuery.hmac = expectedHmac;
384388

385389
fetchMock.mockResponse(JSON.stringify(successResponse));
386-
const returnedSession = await ShopifyOAuth.validateAuthCallback(req, res, testCallbackQuery);
390+
const returnedSession = await ShopifyOAuth.validateAuthCallback(
391+
req,
392+
res,
393+
testCallbackQuery,
394+
);
387395

388396
const jwtPayload: JwtPayload = {
389397
iss: `https://${shop}/admin`,
@@ -425,7 +433,10 @@ describe('validateAuthCallback', () => {
425433
const currentSession = await loadCurrentSession(jwtReq, jwtRes);
426434
expect(currentSession).not.toBe(null);
427435
expect(currentSession?.id).toEqual(jwtSessionId);
428-
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(new Date().getTime(), 1);
436+
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(
437+
new Date().getTime(),
438+
1,
439+
);
429440
});
430441

431442
test('properly updates the Oauth cookie for online, non-embedded apps', async () => {
@@ -463,11 +474,21 @@ describe('validateAuthCallback', () => {
463474
testCallbackQuery.hmac = expectedHmac;
464475

465476
fetchMock.mockResponse(JSON.stringify(successResponse));
466-
const returnedSession = await ShopifyOAuth.validateAuthCallback(req, res, testCallbackQuery);
477+
const returnedSession = await ShopifyOAuth.validateAuthCallback(
478+
req,
479+
res,
480+
testCallbackQuery,
481+
);
467482
expect(returnedSession.id).toEqual(cookies.id);
468483

469-
expect(returnedSession?.expires?.getTime() as number).toBeWithinSecondsOf(new Date(Date.now() + successResponse.expires_in * 1000).getTime(), 1);
470-
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(returnedSession?.expires?.getTime() as number, 1);
484+
expect(returnedSession?.expires?.getTime() as number).toBeWithinSecondsOf(
485+
new Date(Date.now() + successResponse.expires_in * 1000).getTime(),
486+
1,
487+
);
488+
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(
489+
returnedSession?.expires?.getTime() as number,
490+
1,
491+
);
471492

472493
const cookieSession = await Context.SESSION_STORAGE.loadSession(cookies.id);
473494
expect(cookieSession).not.toBeUndefined();
@@ -508,13 +529,20 @@ describe('validateAuthCallback', () => {
508529
testCallbackQuery.hmac = expectedHmac;
509530

510531
fetchMock.mockResponse(JSON.stringify(successResponse));
511-
const returnedSession = await ShopifyOAuth.validateAuthCallback(req, res, testCallbackQuery);
532+
const returnedSession = await ShopifyOAuth.validateAuthCallback(
533+
req,
534+
res,
535+
testCallbackQuery,
536+
);
512537
expect(returnedSession.id).toEqual(cookies.id);
513538
expect(returnedSession.id).toEqual(ShopifyOAuth.getOfflineSessionId(shop));
514539

515540
const cookieSession = await Context.SESSION_STORAGE.loadSession(cookies.id);
516541
expect(cookieSession).not.toBeUndefined();
517-
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(new Date().getTime(), 1);
542+
expect(cookies?.expires?.getTime() as number).toBeWithinSecondsOf(
543+
new Date().getTime(),
544+
1,
545+
);
518546
expect(returnedSession?.expires?.getTime()).toBeUndefined();
519547
});
520548

@@ -553,7 +581,11 @@ describe('validateAuthCallback', () => {
553581
testCallbackQuery.hmac = expectedHmac;
554582

555583
fetchMock.mockResponse(JSON.stringify(successResponse));
556-
const returnedSession = await ShopifyOAuth.validateAuthCallback(req, res, testCallbackQuery);
584+
const returnedSession = await ShopifyOAuth.validateAuthCallback(
585+
req,
586+
res,
587+
testCallbackQuery,
588+
);
557589
expect(returnedSession.id).toEqual(cookies.id);
558590
expect(returnedSession.id).toEqual(ShopifyOAuth.getOfflineSessionId(shop));
559591
expect(cookies?.expires?.getTime()).toBeUndefined();

src/auth/oauth/oauth.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ const ShopifyOAuth = {
173173
);
174174
const jwtSession = Session.cloneSession(currentSession, jwtSessionId);
175175

176-
const sessionDeleted = await Context.SESSION_STORAGE.deleteSession(currentSession.id);
176+
const sessionDeleted = await Context.SESSION_STORAGE.deleteSession(
177+
currentSession.id,
178+
);
177179
if (!sessionDeleted) {
178180
throw new ShopifyErrors.SessionStorageError(
179181
'OAuth Session could not be deleted. Please check your session storage functionality.',
@@ -195,7 +197,9 @@ const ShopifyOAuth = {
195197
secure: true,
196198
});
197199

198-
const sessionStored = await Context.SESSION_STORAGE.storeSession(currentSession);
200+
const sessionStored = await Context.SESSION_STORAGE.storeSession(
201+
currentSession,
202+
);
199203
if (!sessionStored) {
200204
throw new ShopifyErrors.SessionStorageError(
201205
'OAuth Session could not be saved. Please check your session storage functionality.',

src/auth/scopes/test/scopes.test.ts src/auth/scopes/__tests__/scopes.test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import '../../../test/test_helper';
2-
31
import {AuthScopes} from '../index';
42

53
describe('AuthScopes', () => {

src/auth/scopes/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
class AuthScopes {
32
public static SCOPE_DELIMITER = ',';
43

src/auth/session/test/session.test.ts src/auth/session/__tests__/session.test.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import '../../../test/test_helper';
21
import {Session} from '..';
32

43
describe('session', () => {
54
it('can clone a session', () => {
6-
const session = new Session('original', 'original-shop', 'original-state', true);
5+
const session = new Session(
6+
'original',
7+
'original-shop',
8+
'original-state',
9+
true,
10+
);
711
const sessionClone = Session.cloneSession(session, 'new');
812

913
expect(session.id).not.toEqual(sessionClone.id);
@@ -30,7 +34,12 @@ describe('isActive', () => {
3034
});
3135

3236
it('returns false if session is not active', () => {
33-
const session = new Session('not_active', 'inactive-shop', 'not_same', true);
37+
const session = new Session(
38+
'not_active',
39+
'inactive-shop',
40+
'not_same',
41+
true,
42+
);
3443
session.scope = 'test_scope';
3544
session.expires = new Date(Date.now() - 1);
3645
expect(session.isActive()).toBeFalsy();

src/auth/session/session_storage.ts

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {SessionInterface} from './types';
44
* Defines the strategy to be used to store sessions for the Shopify App.
55
*/
66
interface SessionStorage {
7-
87
/**
98
* Creates or updates the given session in storage.
109
*

src/auth/session/storage/test/custom.test.ts src/auth/session/storage/__tests__/custom.test.ts

+24-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import '../../../../test/test_helper';
2-
31
import {Session} from '../../session';
42
import {CustomSessionStorage} from '../custom';
53
import {SessionStorageError} from '../../../../error';
64

75
describe('custom session storage', () => {
86
test('can perform actions', async () => {
97
const sessionId = 'test_session';
10-
let session: Session | undefined = new Session(sessionId, 'shop-url', 'state', true);
8+
let session: Session | undefined = new Session(
9+
sessionId,
10+
'shop-url',
11+
'state',
12+
true,
13+
);
1114

1215
let storeCalled = false;
1316
let loadCalled = false;
@@ -99,7 +102,12 @@ describe('custom session storage', () => {
99102
const expiration = new Date();
100103
expiration.setDate(expiration.getDate() + 10);
101104

102-
let session: Session | undefined = new Session(sessionId, 'shop', 'state', true);
105+
let session: Session | undefined = new Session(
106+
sessionId,
107+
'shop',
108+
'state',
109+
true,
110+
);
103111
session.expires = expiration;
104112

105113
const storage = new CustomSessionStorage(
@@ -128,7 +136,12 @@ describe('custom session storage', () => {
128136
expiration.setDate(expiration.getDate() + 10);
129137

130138
/* eslint-disable @typescript-eslint/naming-convention */
131-
let session: Session | undefined = new Session(sessionId, 'test.myshopify.io', '1234', true);
139+
let session: Session | undefined = new Session(
140+
sessionId,
141+
'test.myshopify.io',
142+
'1234',
143+
true,
144+
);
132145
session.scope = 'read_products';
133146
session.expires = expiration;
134147
session.isOnline = true;
@@ -174,7 +187,12 @@ describe('custom session storage', () => {
174187
it('allows empty fields in serialized object', async () => {
175188
const sessionId = 'test_session';
176189

177-
let session: Session | undefined = new Session(sessionId, 'shop', 'state', true);
190+
let session: Session | undefined = new Session(
191+
sessionId,
192+
'shop',
193+
'state',
194+
true,
195+
);
178196

179197
let serializedSession = '';
180198
const storage = new CustomSessionStorage(

src/auth/session/storage/test/memory.test.ts src/auth/session/storage/__tests__/memory.test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import '../../../../test/test_helper';
2-
31
import {Session} from '../../session';
42
import {MemorySessionStorage} from '../memory';
53

src/auth/session/storage/custom.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export class CustomSessionStorage implements SessionStorage {
88
readonly storeCallback: (session: SessionInterface) => Promise<boolean>,
99
readonly loadCallback: (
1010
id: string,
11-
) => Promise<SessionInterface | {[key: string]: unknown;} | undefined>,
11+
) => Promise<SessionInterface | {[key: string]: unknown} | undefined>,
1212
readonly deleteCallback: (id: string) => Promise<boolean>,
1313
) {
1414
this.storeCallback = storeCallback;
@@ -27,7 +27,7 @@ export class CustomSessionStorage implements SessionStorage {
2727
}
2828

2929
public async loadSession(id: string): Promise<SessionInterface | undefined> {
30-
let result: SessionInterface | {[key: string]: unknown;} | undefined;
30+
let result: SessionInterface | {[key: string]: unknown} | undefined;
3131
try {
3232
result = await this.loadCallback(id);
3333
} catch (error) {

src/auth/session/storage/memory.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {SessionInterface} from '../types';
22
import {SessionStorage} from '../session_storage';
33

44
export class MemorySessionStorage implements SessionStorage {
5-
private sessions: {[id: string]: SessionInterface;} = {};
5+
private sessions: {[id: string]: SessionInterface} = {};
66

77
public async storeSession(session: SessionInterface): Promise<boolean> {
88
this.sessions[session.id] = session;

0 commit comments

Comments
 (0)