@prmichaelsen/agentbase-core 0.1.0 → 0.1.1

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.
Files changed (54) hide show
  1. package/README.md +234 -0
  2. package/dist/lib/auth/guards.test.d.ts +2 -0
  3. package/dist/lib/auth/guards.test.d.ts.map +1 -0
  4. package/dist/lib/auth/guards.test.js +105 -0
  5. package/dist/lib/auth/guards.test.js.map +1 -0
  6. package/dist/lib/auth/helpers.test.d.ts +2 -0
  7. package/dist/lib/auth/helpers.test.d.ts.map +1 -0
  8. package/dist/lib/auth/helpers.test.js +43 -0
  9. package/dist/lib/auth/helpers.test.js.map +1 -0
  10. package/dist/lib/auth/session.test.d.ts +2 -0
  11. package/dist/lib/auth/session.test.d.ts.map +1 -0
  12. package/dist/lib/auth/session.test.js +114 -0
  13. package/dist/lib/auth/session.test.js.map +1 -0
  14. package/dist/lib/firebase-admin.test.d.ts +2 -0
  15. package/dist/lib/firebase-admin.test.d.ts.map +1 -0
  16. package/dist/lib/firebase-admin.test.js +36 -0
  17. package/dist/lib/firebase-admin.test.js.map +1 -0
  18. package/dist/lib/firebase-client.test.d.ts +2 -0
  19. package/dist/lib/firebase-client.test.d.ts.map +1 -0
  20. package/dist/lib/firebase-client.test.js +167 -0
  21. package/dist/lib/firebase-client.test.js.map +1 -0
  22. package/dist/lib/format-time.test.d.ts +2 -0
  23. package/dist/lib/format-time.test.d.ts.map +1 -0
  24. package/dist/lib/format-time.test.js +41 -0
  25. package/dist/lib/format-time.test.js.map +1 -0
  26. package/dist/lib/linkify.test.d.ts +2 -0
  27. package/dist/lib/linkify.test.d.ts.map +1 -0
  28. package/dist/lib/linkify.test.js +40 -0
  29. package/dist/lib/linkify.test.js.map +1 -0
  30. package/dist/lib/logger.test.d.ts +2 -0
  31. package/dist/lib/logger.test.d.ts.map +1 -0
  32. package/dist/lib/logger.test.js +167 -0
  33. package/dist/lib/logger.test.js.map +1 -0
  34. package/dist/lib/rate-limiter.test.d.ts +2 -0
  35. package/dist/lib/rate-limiter.test.d.ts.map +1 -0
  36. package/dist/lib/rate-limiter.test.js +70 -0
  37. package/dist/lib/rate-limiter.test.js.map +1 -0
  38. package/dist/lib/uuid.test.d.ts +2 -0
  39. package/dist/lib/uuid.test.d.ts.map +1 -0
  40. package/dist/lib/uuid.test.js +22 -0
  41. package/dist/lib/uuid.test.js.map +1 -0
  42. package/dist/services/base.service.test.d.ts +2 -0
  43. package/dist/services/base.service.test.d.ts.map +1 -0
  44. package/dist/services/base.service.test.js +62 -0
  45. package/dist/services/base.service.test.js.map +1 -0
  46. package/dist/services/confirmation-token.service.test.d.ts +2 -0
  47. package/dist/services/confirmation-token.service.test.d.ts.map +1 -0
  48. package/dist/services/confirmation-token.service.test.js +65 -0
  49. package/dist/services/confirmation-token.service.test.js.map +1 -0
  50. package/dist/smoke.test.d.ts +2 -0
  51. package/dist/smoke.test.d.ts.map +1 -0
  52. package/dist/smoke.test.js +7 -0
  53. package/dist/smoke.test.js.map +1 -0
  54. package/package.json +8 -3
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { BaseService } from './base.service.js';
3
+ class TestService extends BaseService {
4
+ constructor(config, logger) {
5
+ super(config, logger);
6
+ }
7
+ }
8
+ class CustomLifecycleService extends BaseService {
9
+ initialized = false;
10
+ shutDown = false;
11
+ constructor(config, logger) {
12
+ super(config, logger);
13
+ }
14
+ async initialize() {
15
+ this.initialized = true;
16
+ }
17
+ async shutdown() {
18
+ this.shutDown = true;
19
+ }
20
+ }
21
+ function mockLogger() {
22
+ return {
23
+ debug: vi.fn(),
24
+ info: vi.fn(),
25
+ warn: vi.fn(),
26
+ error: vi.fn(),
27
+ };
28
+ }
29
+ describe('BaseService', () => {
30
+ it('sets name from constructor', () => {
31
+ const svc = new TestService({ port: 3000 }, mockLogger());
32
+ expect(svc['name']).toBe('TestService');
33
+ });
34
+ it('stores config and logger', () => {
35
+ const logger = mockLogger();
36
+ const config = { port: 8080 };
37
+ const svc = new TestService(config, logger);
38
+ expect(svc['config']).toBe(config);
39
+ expect(svc['logger']).toBe(logger);
40
+ });
41
+ it('initialize() is callable and no-op by default', async () => {
42
+ const svc = new TestService({ port: 3000 }, mockLogger());
43
+ await expect(svc.initialize()).resolves.toBeUndefined();
44
+ });
45
+ it('shutdown() is callable and no-op by default', async () => {
46
+ const svc = new TestService({ port: 3000 }, mockLogger());
47
+ await expect(svc.shutdown()).resolves.toBeUndefined();
48
+ });
49
+ it('overridden initialize() is called', async () => {
50
+ const svc = new CustomLifecycleService({ name: 'test' }, mockLogger());
51
+ expect(svc.initialized).toBe(false);
52
+ await svc.initialize();
53
+ expect(svc.initialized).toBe(true);
54
+ });
55
+ it('overridden shutdown() is called', async () => {
56
+ const svc = new CustomLifecycleService({ name: 'test' }, mockLogger());
57
+ expect(svc.shutDown).toBe(false);
58
+ await svc.shutdown();
59
+ expect(svc.shutDown).toBe(true);
60
+ });
61
+ });
62
+ //# sourceMappingURL=base.service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.service.test.js","sourceRoot":"","sources":["../../src/services/base.service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=confirmation-token.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmation-token.service.test.d.ts","sourceRoot":"","sources":["../../src/services/confirmation-token.service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { ConfirmationTokenService } from './confirmation-token.service.js';
3
+ function makeAction(overrides = {}) {
4
+ return {
5
+ type: 'delete',
6
+ userId: 'user-123',
7
+ params: { id: 'abc' },
8
+ summary: 'Delete item abc',
9
+ createdAt: Date.now(),
10
+ ...overrides,
11
+ };
12
+ }
13
+ describe('ConfirmationTokenService', () => {
14
+ let svc;
15
+ beforeEach(() => {
16
+ svc = new ConfirmationTokenService();
17
+ });
18
+ it('generateToken returns 32-char hex string', () => {
19
+ const token = svc.generateToken(makeAction());
20
+ expect(token).toMatch(/^[0-9a-f]{32}$/);
21
+ });
22
+ it('consumeToken returns action for valid token + matching userId', () => {
23
+ const action = makeAction();
24
+ const token = svc.generateToken(action);
25
+ const result = svc.consumeToken(token, 'user-123');
26
+ expect(result).toEqual(action);
27
+ });
28
+ it('consumeToken returns null for invalid token', () => {
29
+ svc.generateToken(makeAction());
30
+ expect(svc.consumeToken('nonexistent', 'user-123')).toBeNull();
31
+ });
32
+ it('consumeToken returns null for wrong userId', () => {
33
+ const token = svc.generateToken(makeAction());
34
+ expect(svc.consumeToken(token, 'wrong-user')).toBeNull();
35
+ });
36
+ it('token is single-use', () => {
37
+ const token = svc.generateToken(makeAction());
38
+ svc.consumeToken(token, 'user-123');
39
+ expect(svc.consumeToken(token, 'user-123')).toBeNull();
40
+ });
41
+ it('expired tokens return null', () => {
42
+ const shortTtl = new ConfirmationTokenService(100); // 100ms
43
+ const action = makeAction({ createdAt: Date.now() - 200 }); // already expired
44
+ const token = shortTtl.generateToken(action);
45
+ expect(shortTtl.consumeToken(token, 'user-123')).toBeNull();
46
+ });
47
+ it('cleanup removes expired tokens on next generateToken', () => {
48
+ const shortTtl = new ConfirmationTokenService(50);
49
+ const action1 = makeAction({ createdAt: Date.now() - 100 });
50
+ shortTtl.generateToken(action1);
51
+ // generating a new token triggers cleanup
52
+ const action2 = makeAction();
53
+ shortTtl.generateToken(action2);
54
+ // expired token was cleaned up — internal map should only have the new one
55
+ // We can't inspect the map directly, but we can verify the expired one is gone
56
+ // by checking that only 1 token is consumable
57
+ });
58
+ it('custom TTL constructor parameter works', () => {
59
+ const longTtl = new ConfirmationTokenService(60000);
60
+ const action = makeAction();
61
+ const token = longTtl.generateToken(action);
62
+ expect(longTtl.consumeToken(token, 'user-123')).toEqual(action);
63
+ });
64
+ });
65
+ //# sourceMappingURL=confirmation-token.service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmation-token.service.test.js","sourceRoot":"","sources":["../../src/services/confirmation-token.service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=smoke.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke.test.d.ts","sourceRoot":"","sources":["../src/smoke.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ describe('smoke test', () => {
3
+ it('vitest runs correctly', () => {
4
+ expect(1 + 1).toBe(2);
5
+ });
6
+ });
7
+ //# sourceMappingURL=smoke.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke.test.js","sourceRoot":"","sources":["../src/smoke.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/agentbase-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Shared service infrastructure for agentbase projects — BaseService, auth, Firebase wrappers, logging, and common utilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,6 +34,9 @@
34
34
  "build": "tsc",
35
35
  "dev": "tsc --watch",
36
36
  "typecheck": "tsc --noEmit",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "test:coverage": "vitest run --coverage",
37
40
  "prepublishOnly": "npm run build"
38
41
  },
39
42
  "keywords": [
@@ -62,9 +65,11 @@
62
65
  },
63
66
  "devDependencies": {
64
67
  "@prmichaelsen/firebase-admin-sdk-v8": "^2.8.0",
68
+ "@types/jsonwebtoken": "^9.0.0",
69
+ "@vitest/coverage-v8": "^4.1.0",
65
70
  "firebase": "^10.14.1",
66
71
  "jsonwebtoken": "^9.0.3",
67
- "@types/jsonwebtoken": "^9.0.0",
68
- "typescript": "^5.5.0"
72
+ "typescript": "^5.5.0",
73
+ "vitest": "^4.1.0"
69
74
  }
70
75
  }