Skip to content

Commit 5d091fd

Browse files
committed
refactor: split into multiple packages
In order to support multiple GraphQL server/gateway implementations we need to move apollo specific code to separate packages
1 parent 43f53b4 commit 5d091fd

Some content is hidden

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

49 files changed

+5144
-3834
lines changed

.changeset/config.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
"changelog": "@changesets/cli/changelog",
44
"commit": false,
55
"fixed": [],
6-
"linked": [],
6+
"linked": [
7+
[
8+
"@labdigital/federated-token*"
9+
]
10+
],
711
"access": "restricted",
812
"baseBranch": "main",
913
"updateInternalDependencies": "patch",

.changeset/good-pigs-add.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@labdigital/federated-token-apollo": minor
3+
"@labdigital/federated-token": minor
4+
---
5+
6+
Split the package in a `core` and a `apollo` specific package. This makes it
7+
possible to support other gateways/servers in the future

.eslintignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
**/*.js
1+
**/*.js
2+
**/dist/*
3+
dist/**

.eslintrc.cjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ module.exports = {
22
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
33
plugins: ["unused-imports"],
44
rules: {
5-
"@typescript-eslint/ban-ts-comment": "off",
65
"@typescript-eslint/no-explicit-any": "off",
76
"@typescript-eslint/no-empty-function": "off",
87
"@typescript-eslint/no-unused-vars": [

.github/workflows/release.yml

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- name: Checkout repo
13-
uses: actions/checkout@v3
13+
uses: actions/checkout@v4
1414

1515
- name: Set up Node.js
16-
uses: actions/setup-node@v3
16+
uses: actions/setup-node@v4
1717
with:
1818
node-version: 20
1919

20-
- uses: pnpm/action-setup@v2
20+
- uses: pnpm/action-setup@v4
2121
name: Install pnpm
2222
id: pnpm-install
2323
with:
24-
version: 8
2524
run_install: true
2625

2726
- name: Lint
@@ -33,52 +32,51 @@ jobs:
3332
needs: lint
3433
strategy:
3534
matrix:
36-
node: ["18.x", "20.x"]
35+
node: ["18.x", "20.x", "22.x"]
3736
os: [ubuntu-latest]
3837

3938
steps:
4039
- name: Checkout repo
41-
uses: actions/checkout@v3
40+
uses: actions/checkout@v4
4241

43-
- uses: pnpm/action-setup@v2
42+
- uses: pnpm/action-setup@v4
4443
name: Install pnpm
4544
id: pnpm-install
4645
with:
47-
version: 8
4846
run_install: true
4947

5048
- name: Use Node ${{ matrix.node }}
51-
uses: actions/setup-node@v3
49+
uses: actions/setup-node@v4
5250
with:
5351
node-version: ${{ matrix.node }}
5452
cache: "pnpm"
5553

56-
- name: Test
57-
run: pnpm run test:ci
58-
5954
- name: Build
6055
run: pnpm build
6156

57+
- name: Test
58+
run: pnpm test:ci
59+
60+
6261
release:
6362
timeout-minutes: 15
6463
runs-on: ubuntu-latest
6564
if: github.ref == 'refs/heads/main'
6665
needs: build
6766
steps:
6867
- name: Checkout
69-
uses: actions/checkout@v3
68+
uses: actions/checkout@v4
7069
with:
7170
fetch-depth: 0
7271

73-
- uses: pnpm/action-setup@v2
72+
- uses: pnpm/action-setup@v4
7473
name: Install pnpm
7574
id: pnpm-install
7675
with:
77-
version: 8
7876
run_install: true
7977

8078
- name: Install node.js
81-
uses: actions/setup-node@v3
79+
uses: actions/setup-node@v4
8280
with:
8381
node-version: 20
8482
cache: "pnpm"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
node_modules/*
2+
**/node_modules/*
3+
**/dist/*
4+
**/*.log
25
coverage/*
36
dist/*
47
test-reports/*
8+
9+
.turbo/

.prettierignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pnpm-lock.yaml
22

3-
node_modules/*
4-
coverage/*
3+
**/node_modules/*
4+
**/coverage/*
5+
**/dist/*
56
dist/*
67
test-reports/*

package.json

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
2-
"name": "@labdigital/federated-token",
3-
"version": "0.12.1",
2+
"name": "federated-token",
3+
"private": "true",
4+
"version": "0.0.0",
45
"description": "Federate JWT tokens between Apollo servers",
56
"main": "./dist/index.js",
67
"module": "./dist/index.mjs",
@@ -16,49 +17,24 @@
1617
"type": "git",
1718
"url": "https://github.com/labd/node-federated-token"
1819
},
19-
"publishConfig": {
20-
"access": "public"
21-
},
20+
"workspaces": [
21+
"packages/*"
22+
],
2223
"scripts": {
23-
"build": "tsup",
24+
"build": "pnpm turbo build",
25+
"format": "turbo run format",
26+
"lint": "turbo run lint",
2427
"publish:ci": "pnpm build && pnpm changeset publish",
2528
"test": "vitest run",
26-
"test:ci": "vitest run --coverage",
27-
"tsc": "tsc --noEmit",
28-
"format": "eslint src --fix && prettier --write .",
29-
"lint": "eslint src && prettier --check ."
30-
},
31-
"files": [
32-
"dist",
33-
"src"
34-
],
35-
"dependencies": {
36-
"jose": "4.14.4",
37-
"lodash.isequal": "^4.5.0"
29+
"test:ci": "vitest run --coverage"
3830
},
31+
"packageManager": "[email protected]",
3932
"devDependencies": {
40-
"@apollo/server": "^4.10.0",
41-
"@apollo/gateway": ">= 2.4",
42-
"@apollo/server-gateway-interface": "1.1.0",
43-
"@changesets/cli": "^2.26.2",
44-
"@sentry/types": "7.55.0",
45-
"@types/cookie": "^0.6.0",
46-
"@types/cookie-parser": "^1.4.3",
47-
"@types/express": "^4.17.17",
48-
"@types/lodash.isequal": "^4.5.6",
49-
"@typescript-eslint/eslint-plugin": "^5.60.1",
50-
"@vitest/coverage-v8": "0.32.2",
51-
"cookie": "^0.6.0",
52-
"eslint": "^8.40.0",
53-
"eslint-plugin-unused-imports": "^2.0.0",
54-
"node-mocks-http": "^1.12.2",
55-
"tsup": "^7.1.0",
56-
"typescript": "^5.1.5",
57-
"vitest": "0.32.2"
33+
"@changesets/cli": "^2.27.5",
34+
"@vitest/coverage-v8": "1.6.0",
35+
"vitest": "1.6.0"
5836
},
59-
"peerDependencies": {
60-
"@apollo/gateway": ">= 2.4",
61-
"@apollo/server": ">= 4.5",
62-
"graphql": ">= 16.6.0"
37+
"dependencies": {
38+
"turbo": "^2.0.3"
6339
}
6440
}

packages/apollo/.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/**

packages/apollo/.eslintrc.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
extends: ["../../.eslintrc.cjs"],
3+
};

packages/apollo/package.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"name": "@labdigital/federated-token-apollo",
3+
"version": "0.12.1",
4+
"description": "Federate JWT tokens between Apollo servers",
5+
"module": "./dist/index.js",
6+
"types": "./dist/index.d.ts",
7+
"type": "module",
8+
"keywords": [
9+
"graphql",
10+
"authentication",
11+
"apollo"
12+
],
13+
"author": "Lab Digital <[email protected]>",
14+
"license": "MIT",
15+
"repository": {
16+
"type": "git",
17+
"url": "https://github.com/labd/node-federated-token"
18+
},
19+
"publishConfig": {
20+
"access": "public"
21+
},
22+
"scripts": {
23+
"build": "tsup",
24+
"test": "vitest run",
25+
"test:ci": "vitest run --coverage",
26+
"tsc": "tsc --noEmit",
27+
"format": "eslint src --fix && prettier --write .",
28+
"lint": "eslint src && prettier --check ."
29+
},
30+
"files": [
31+
"dist",
32+
"src"
33+
],
34+
"dependencies": {
35+
"@labdigital/federated-token": "workspace:*"
36+
},
37+
"devDependencies": {
38+
"@apollo/gateway": "^2.8.0",
39+
"@apollo/server": "^4.10.4",
40+
"@apollo/server-gateway-interface": "1.1.1",
41+
"@types/express": "^4.17.21",
42+
"@typescript-eslint/eslint-plugin": "^7.12.0",
43+
"@vitest/coverage-v8": "1.6.0",
44+
"eslint": "^8.57.0",
45+
"eslint-plugin-unused-imports": "^4.0.0",
46+
"node-mocks-http": "^1.14.1",
47+
"prettier": "^3.3.1",
48+
"tsup": "^8.1.0",
49+
"typescript": "^5.4.5",
50+
"vitest": "1.6.0"
51+
},
52+
"peerDependencies": {
53+
"@apollo/gateway": ">= 2.4",
54+
"@apollo/server": ">= 4.5",
55+
"graphql": ">= 16.6.0"
56+
}
57+
}

packages/apollo/src/context.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { BaseContext } from "@apollo/server";
2+
import { PublicFederatedToken } from "@labdigital/federated-token";
3+
import { type Request, type Response } from "express";
4+
5+
export type PublicFederatedTokenContext = {
6+
federatedToken?: PublicFederatedToken;
7+
res: Response;
8+
req: Request;
9+
} & BaseContext;

src/datasource.ts renamed to packages/apollo/src/datasource.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import {
44
} from "@apollo/gateway";
55
import { HeaderMap } from "@apollo/server";
66
import { type GatewayGraphQLResponse } from "@apollo/server-gateway-interface";
7-
import { PublicFederatedToken, PublicFederatedTokenContext } from "./jwt";
7+
import { PublicFederatedToken } from "@labdigital/federated-token";
8+
import { PublicFederatedTokenContext } from "./context";
89

910
// FederatedGraphQLDataSource is a RemoteGraphQLDataSource that adds the
1011
// x-access-token and x-refresh-token headers to the request and reads the
1112
// x-access-token and x-refresh-token headers from the response.
1213
// It works in conjunction with the GatewayAuthPlugin.
1314
export class FederatedGraphQLDataSource<
14-
TContext extends PublicFederatedTokenContext
15+
TContext extends PublicFederatedTokenContext,
1516
> extends RemoteGraphQLDataSource<TContext> {
1617
willSendRequest(
17-
options: GraphQLDataSourceProcessOptions
18+
options: GraphQLDataSourceProcessOptions,
1819
): void | Promise<void> {
1920
const { request, context } = options;
2021
const headers = request.http?.headers ?? new HeaderMap();

src/gateway.test.ts renamed to packages/apollo/src/gateway.test.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import * as crypto from "crypto";
33
import httpMocks from "node-mocks-http";
44
import { assert, describe, expect, it } from "vitest";
55
import { GatewayAuthPlugin } from "./gateway";
6-
import { PublicFederatedToken, PublicFederatedTokenContext } from "./jwt";
7-
import { KeyManager, TokenSigner } from "./sign";
8-
import { HeaderTokenSource } from "./tokensource";
6+
import { PublicFederatedToken } from "@labdigital/federated-token";
7+
import { KeyManager, TokenSigner } from "@labdigital/federated-token";
8+
import { HeaderTokenSource } from "@labdigital/federated-token";
9+
import { PublicFederatedTokenContext } from "./context";
910

1011
describe("GatewayAuthPlugin", () => {
1112
const signOptions = {
@@ -40,9 +41,9 @@ describe("GatewayAuthPlugin", () => {
4041
const resolvers = {
4142
Query: {
4243
testToken: (
43-
_: any,
44+
_: unknown,
4445
{ create, value }: { create: boolean; value: string },
45-
context: PublicFederatedTokenContext
46+
context: PublicFederatedTokenContext,
4647
) => {
4748
if (!context.federatedToken) {
4849
throw new Error("No federated token");
@@ -62,7 +63,7 @@ describe("GatewayAuthPlugin", () => {
6263

6364
return JSON.stringify(context.federatedToken);
6465
},
65-
refreshToken: (_: any, context: PublicFederatedTokenContext) => {
66+
refreshToken: (_: unknown, context: PublicFederatedTokenContext) => {
6667
context.federatedToken?.setAccessToken("foo", {
6768
token: "bar",
6869
exp: Date.now() + 1000,
@@ -97,7 +98,7 @@ describe("GatewayAuthPlugin", () => {
9798
},
9899
{
99100
contextValue: context,
100-
}
101+
},
101102
);
102103
expect(context.res.statusCode).toBe(200);
103104
expect(context.res.get("x-access-token")).toBeDefined();
@@ -122,7 +123,7 @@ describe("GatewayAuthPlugin", () => {
122123
},
123124
{
124125
contextValue: context,
125-
}
126+
},
126127
);
127128
expect(context.res.statusCode).toBe(200);
128129
expect(context.res.get("x-access-token")).toBeDefined();
@@ -151,14 +152,14 @@ describe("GatewayAuthPlugin", () => {
151152
},
152153
{
153154
contextValue: newContext,
154-
}
155+
},
155156
);
156157
expect(response.body.kind).toBe("single");
157158
assert(response.body.kind === "single"); // Make typescript happy
158159
expect(response.body.singleResult).toBeDefined();
159160

160161
const token = JSON.parse(
161-
response.body.singleResult.data?.testToken as string
162+
response.body.singleResult.data?.testToken as string,
162163
) as PublicFederatedToken;
163164
expect(token.tokens.foo.token).toBe("bar");
164165
expect(newContext.res.get("x-access-token")).toBeUndefined();
@@ -183,7 +184,7 @@ describe("GatewayAuthPlugin", () => {
183184
},
184185
{
185186
contextValue: context,
186-
}
187+
},
187188
);
188189
expect(context.res.statusCode).toBe(200);
189190
expect(context.res.get("x-access-token")).toBeDefined();
@@ -213,7 +214,7 @@ describe("GatewayAuthPlugin", () => {
213214
},
214215
{
215216
contextValue: newContext,
216-
}
217+
},
217218
);
218219
const newAccessToken = newContext.res.get("x-access-token");
219220

0 commit comments

Comments
 (0)