Skip to content

Commit fc70e39

Browse files
authored
Merge pull request #29 from PoOwAa/feature/bigint-bitwise-operators
Rewrite encode/decode logic to use BigInt and bitwise operators.
2 parents 9272427 + 83d64da commit fc70e39

8 files changed

Lines changed: 10735 additions & 11187 deletions

File tree

.github/workflows/test.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212

1313
strategy:
1414
matrix:
15-
node-version: [10.x, 12.x, 14.x, 15.x]
15+
node-version: [22.x, 23.x, 24.x]
1616

1717
steps:
1818
- uses: actions/checkout@v2
@@ -28,7 +28,9 @@ jobs:
2828
run: npm test
2929

3030
- name: Code Coverage on Node LTS version
31-
if: ${{ matrix.node-version == '14.x' }}
32-
uses: codecov/codecov-action@v1
31+
if: ${{ matrix.node-version == '22.x' }}
32+
uses: codecov/codecov-action@v5
3333
with:
3434
fail_ci_if_error: true
35+
env:
36+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

jest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default async (): Promise<Config.InitialOptions> => {
77
testEnvironment: 'node',
88
coverageDirectory: './coverage/',
99
collectCoverage: true,
10+
testPathIgnorePatterns: ['<rootDir>/src/Aclatraz.performance.test.ts'],
1011
coverageThreshold: {
1112
global: {
1213
branches: 100,

package-lock.json

Lines changed: 10297 additions & 11133 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "0.1.4",
44
"description": "Simple dependency-free package for ACL. It can handle hundreds of roles easily.",
55
"main": "lib/index.js",
6+
"engines": {
7+
"node": ">=20.0.0"
8+
},
69
"scripts": {
710
"build": "rimraf ./lib && tsc",
811
"test": "jest",
@@ -35,18 +38,18 @@
3538
},
3639
"homepage": "https://github.com/PoOwAa/aclatraz#readme",
3740
"devDependencies": {
38-
"@types/jest": "^26.0.20",
39-
"@types/node": "^14.14.29",
40-
"@typescript-eslint/eslint-plugin": "^4.15.1",
41-
"@typescript-eslint/parser": "^4.15.1",
42-
"eslint": "^7.20.0",
43-
"eslint-config-prettier": "^7.2.0",
44-
"eslint-plugin-jest": "^24.1.5",
45-
"jest": "^26.6.3",
46-
"np": "^7.4.0",
47-
"rimraf": "^3.0.2",
48-
"ts-jest": "^26.5.1",
49-
"ts-node": "^9.1.1",
50-
"typescript": "^4.1.5"
41+
"@types/jest": "^29.5.11",
42+
"@types/node": "^20.11.30",
43+
"@typescript-eslint/eslint-plugin": "^7.7.0",
44+
"@typescript-eslint/parser": "^7.7.0",
45+
"eslint": "^8.57.0",
46+
"eslint-config-prettier": "^9.1.0",
47+
"eslint-plugin-jest": "^27.9.0",
48+
"jest": "^29.7.0",
49+
"np": "^8.0.4",
50+
"rimraf": "^5.0.5",
51+
"ts-jest": "^29.1.1",
52+
"ts-node": "^10.9.2",
53+
"typescript": "^5.4.5"
5154
}
52-
}
55+
}

src/Aclatraz.performance.test.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { performance } from 'perf_hooks';
2+
import { Aclatraz } from './Aclatraz';
3+
4+
describe('Aclatraz performance test', () => {
5+
test('generate permission code for 10,000 rules', () => {
6+
const rules = [];
7+
for (let i = 1; i <= 10000; i++) {
8+
rules.push({ id: i, slug: `rule${i}` });
9+
}
10+
const acl = new Aclatraz(rules);
11+
12+
const ruleIds = Array.from({ length: 10000 }, (_, i) => i + 1);
13+
14+
const start = performance.now();
15+
const code = acl.generateAclCode(ruleIds);
16+
const end = performance.now();
17+
18+
console.log(`Generated code length: ${code.length}`);
19+
console.log(`Time taken: ${(end - start).toFixed(2)} ms`);
20+
21+
expect(typeof code).toBe('string');
22+
});
23+
24+
test('grantPermission 100,000 times', () => {
25+
const rules = [];
26+
for (let i = 1; i <= 100; i++) {
27+
rules.push({ id: i, slug: `rule${i}` });
28+
}
29+
const acl = new Aclatraz(rules);
30+
const ruleIds = Array.from({ length: 100 }, (_, i) => i + 1);
31+
32+
const start = performance.now();
33+
for (let i = 0; i < 100000; i++) {
34+
acl.grantPermission('', ruleIds);
35+
}
36+
const end = performance.now();
37+
console.log(
38+
`grantPermission 100,000 times took: ${(end - start).toFixed(2)} ms`
39+
);
40+
expect(true).toBe(true);
41+
});
42+
43+
test('verify (decode) 100,000 times', () => {
44+
const rules = [];
45+
for (let i = 1; i <= 100; i++) {
46+
rules.push({ id: i, slug: `rule${i}` });
47+
}
48+
const acl = new Aclatraz(rules);
49+
const ruleIds = Array.from({ length: 100 }, (_, i) => i + 1);
50+
const permission = acl.grantPermission('', ruleIds);
51+
52+
const start = performance.now();
53+
for (let i = 0; i < 100000; i++) {
54+
acl.verify(permission, 50); // Arbitrary ruleId in the middle
55+
}
56+
const end = performance.now();
57+
console.log(
58+
`verify (decode) 100,000 times took: ${(end - start).toFixed(2)} ms`
59+
);
60+
expect(true).toBe(true);
61+
});
62+
63+
test('revokePermission 100,000 times', () => {
64+
const rules = [];
65+
for (let i = 1; i <= 100; i++) {
66+
rules.push({ id: i, slug: `rule${i}` });
67+
}
68+
const acl = new Aclatraz(rules);
69+
const ruleIds = Array.from({ length: 100 }, (_, i) => i + 1);
70+
const permission = acl.grantPermission('', ruleIds);
71+
72+
const start = performance.now();
73+
for (let i = 0; i < 100000; i++) {
74+
acl.revokePermission(permission, [50]); // Arbitrary ruleId
75+
}
76+
const end = performance.now();
77+
console.log(
78+
`revokePermission 100,000 times took: ${(end - start).toFixed(2)} ms`
79+
);
80+
expect(true).toBe(true);
81+
});
82+
83+
test('grantPermission with 100,000 rules', () => {
84+
const rules = [];
85+
for (let i = 1; i <= 100000; i++) {
86+
rules.push({ id: i, slug: `rule${i}` });
87+
}
88+
const acl = new Aclatraz(rules);
89+
const ruleIds = Array.from({ length: 100000 }, (_, i) => i + 1);
90+
91+
const start = performance.now();
92+
const permission = acl.grantPermission('', ruleIds);
93+
const end = performance.now();
94+
console.log(
95+
`grantPermission with 100,000 rules took: ${(end - start).toFixed(
96+
2
97+
)} ms, token length: ${permission.length}`
98+
);
99+
expect(typeof permission).toBe('string');
100+
});
101+
102+
test('verify (decode) with 100,000 rules', () => {
103+
const rules = [];
104+
for (let i = 1; i <= 100000; i++) {
105+
rules.push({ id: i, slug: `rule${i}` });
106+
}
107+
const acl = new Aclatraz(rules);
108+
const ruleIds = Array.from({ length: 100000 }, (_, i) => i + 1);
109+
const permission = acl.grantPermission('', ruleIds);
110+
111+
const start = performance.now();
112+
let count = 0;
113+
for (let i = 1; i <= 100000; i += 10000) {
114+
if (acl.verify(permission, i)) count++;
115+
}
116+
const end = performance.now();
117+
console.log(
118+
`verify (decode) with 100,000 rules (checked every 10,000th): ${(
119+
end - start
120+
).toFixed(2)} ms, found: ${count}`
121+
);
122+
expect(count).toBe(10);
123+
});
124+
125+
test('revokePermission with 100,000 rules', () => {
126+
const rules = [];
127+
for (let i = 1; i <= 100000; i++) {
128+
rules.push({ id: i, slug: `rule${i}` });
129+
}
130+
const acl = new Aclatraz(rules);
131+
const ruleIds = Array.from({ length: 100000 }, (_, i) => i + 1);
132+
const permission = acl.grantPermission('', ruleIds);
133+
134+
const start = performance.now();
135+
const revoked = acl.revokePermission(permission, [50000, 99999, 100000]);
136+
const end = performance.now();
137+
console.log(
138+
`revokePermission with 100,000 rules took: ${(end - start).toFixed(
139+
2
140+
)} ms, token length: ${revoked.length}`
141+
);
142+
expect(typeof revoked).toBe('string');
143+
});
144+
});

0 commit comments

Comments
 (0)