@stratum-hq/lib 0.1.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.
Files changed (109) hide show
  1. package/dist/__tests__/crypto.test.d.ts +2 -0
  2. package/dist/__tests__/crypto.test.d.ts.map +1 -0
  3. package/dist/__tests__/crypto.test.js +41 -0
  4. package/dist/__tests__/crypto.test.js.map +1 -0
  5. package/dist/crypto.d.ts +7 -0
  6. package/dist/crypto.d.ts.map +1 -0
  7. package/dist/crypto.js +74 -0
  8. package/dist/crypto.js.map +1 -0
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +13 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/pool-helpers.d.ts +4 -0
  14. package/dist/pool-helpers.d.ts.map +1 -0
  15. package/dist/pool-helpers.js +31 -0
  16. package/dist/pool-helpers.js.map +1 -0
  17. package/dist/services/__tests__/audit-service.test.d.ts +2 -0
  18. package/dist/services/__tests__/audit-service.test.d.ts.map +1 -0
  19. package/dist/services/__tests__/audit-service.test.js +220 -0
  20. package/dist/services/__tests__/audit-service.test.js.map +1 -0
  21. package/dist/services/__tests__/config-service.test.d.ts +2 -0
  22. package/dist/services/__tests__/config-service.test.d.ts.map +1 -0
  23. package/dist/services/__tests__/config-service.test.js +555 -0
  24. package/dist/services/__tests__/config-service.test.js.map +1 -0
  25. package/dist/services/__tests__/consent-service.test.d.ts +2 -0
  26. package/dist/services/__tests__/consent-service.test.d.ts.map +1 -0
  27. package/dist/services/__tests__/consent-service.test.js +159 -0
  28. package/dist/services/__tests__/consent-service.test.js.map +1 -0
  29. package/dist/services/__tests__/event-service.test.d.ts +2 -0
  30. package/dist/services/__tests__/event-service.test.d.ts.map +1 -0
  31. package/dist/services/__tests__/event-service.test.js +151 -0
  32. package/dist/services/__tests__/event-service.test.js.map +1 -0
  33. package/dist/services/__tests__/permission-service.test.d.ts +2 -0
  34. package/dist/services/__tests__/permission-service.test.d.ts.map +1 -0
  35. package/dist/services/__tests__/permission-service.test.js +470 -0
  36. package/dist/services/__tests__/permission-service.test.js.map +1 -0
  37. package/dist/services/__tests__/retention-service.test.d.ts +2 -0
  38. package/dist/services/__tests__/retention-service.test.d.ts.map +1 -0
  39. package/dist/services/__tests__/retention-service.test.js +126 -0
  40. package/dist/services/__tests__/retention-service.test.js.map +1 -0
  41. package/dist/services/__tests__/tenant-service.test.d.ts +2 -0
  42. package/dist/services/__tests__/tenant-service.test.d.ts.map +1 -0
  43. package/dist/services/__tests__/tenant-service.test.js +451 -0
  44. package/dist/services/__tests__/tenant-service.test.js.map +1 -0
  45. package/dist/services/__tests__/test-helpers.d.ts +9 -0
  46. package/dist/services/__tests__/test-helpers.d.ts.map +1 -0
  47. package/dist/services/__tests__/test-helpers.js +20 -0
  48. package/dist/services/__tests__/test-helpers.js.map +1 -0
  49. package/dist/services/__tests__/webhook-service.test.d.ts +2 -0
  50. package/dist/services/__tests__/webhook-service.test.d.ts.map +1 -0
  51. package/dist/services/__tests__/webhook-service.test.js +174 -0
  52. package/dist/services/__tests__/webhook-service.test.js.map +1 -0
  53. package/dist/services/api-key-service.d.ts +61 -0
  54. package/dist/services/api-key-service.d.ts.map +1 -0
  55. package/dist/services/api-key-service.js +164 -0
  56. package/dist/services/api-key-service.js.map +1 -0
  57. package/dist/services/audit-service.d.ts +6 -0
  58. package/dist/services/audit-service.d.ts.map +1 -0
  59. package/dist/services/audit-service.js +85 -0
  60. package/dist/services/audit-service.js.map +1 -0
  61. package/dist/services/config-service.d.ts +33 -0
  62. package/dist/services/config-service.d.ts.map +1 -0
  63. package/dist/services/config-service.js +271 -0
  64. package/dist/services/config-service.js.map +1 -0
  65. package/dist/services/consent-service.d.ts +7 -0
  66. package/dist/services/consent-service.d.ts.map +1 -0
  67. package/dist/services/consent-service.js +71 -0
  68. package/dist/services/consent-service.js.map +1 -0
  69. package/dist/services/event-service.d.ts +39 -0
  70. package/dist/services/event-service.d.ts.map +1 -0
  71. package/dist/services/event-service.js +331 -0
  72. package/dist/services/event-service.js.map +1 -0
  73. package/dist/services/key-rotation-service.d.ts +15 -0
  74. package/dist/services/key-rotation-service.d.ts.map +1 -0
  75. package/dist/services/key-rotation-service.js +41 -0
  76. package/dist/services/key-rotation-service.js.map +1 -0
  77. package/dist/services/permission-service.d.ts +21 -0
  78. package/dist/services/permission-service.d.ts.map +1 -0
  79. package/dist/services/permission-service.js +213 -0
  80. package/dist/services/permission-service.js.map +1 -0
  81. package/dist/services/region-service.d.ts +9 -0
  82. package/dist/services/region-service.d.ts.map +1 -0
  83. package/dist/services/region-service.js +105 -0
  84. package/dist/services/region-service.js.map +1 -0
  85. package/dist/services/retention-service.d.ts +19 -0
  86. package/dist/services/retention-service.d.ts.map +1 -0
  87. package/dist/services/retention-service.js +88 -0
  88. package/dist/services/retention-service.js.map +1 -0
  89. package/dist/services/role-service.d.ts +35 -0
  90. package/dist/services/role-service.d.ts.map +1 -0
  91. package/dist/services/role-service.js +101 -0
  92. package/dist/services/role-service.js.map +1 -0
  93. package/dist/services/tenant-service.d.ts +25 -0
  94. package/dist/services/tenant-service.d.ts.map +1 -0
  95. package/dist/services/tenant-service.js +335 -0
  96. package/dist/services/tenant-service.js.map +1 -0
  97. package/dist/services/webhook-service.d.ts +12 -0
  98. package/dist/services/webhook-service.d.ts.map +1 -0
  99. package/dist/services/webhook-service.js +129 -0
  100. package/dist/services/webhook-service.js.map +1 -0
  101. package/dist/stratum.d.ts +107 -0
  102. package/dist/stratum.d.ts.map +1 -0
  103. package/dist/stratum.js +531 -0
  104. package/dist/stratum.js.map +1 -0
  105. package/dist/telemetry.d.ts +27 -0
  106. package/dist/telemetry.d.ts.map +1 -0
  107. package/dist/telemetry.js +94 -0
  108. package/dist/telemetry.js.map +1 -0
  109. package/package.json +46 -0
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const vitest_1 = require("vitest");
27
+ // Mock pool-helpers before importing webhook-service
28
+ vitest_1.vi.mock("../../pool-helpers.js", () => ({
29
+ withClient: vitest_1.vi.fn(),
30
+ withTransaction: vitest_1.vi.fn(),
31
+ }));
32
+ const poolHelpers = __importStar(require("../../pool-helpers.js"));
33
+ const webhookService = __importStar(require("../webhook-service.js"));
34
+ const core_1 = require("@stratum-hq/core");
35
+ function makeMockPool() {
36
+ return {};
37
+ }
38
+ const mockWebhook = {
39
+ id: "550e8400-e29b-41d4-a716-446655440000",
40
+ tenant_id: null,
41
+ url: "https://example.com/webhook",
42
+ secret_hash: "mock-encrypted-secret",
43
+ events: ["tenant.created"],
44
+ active: true,
45
+ created_at: "2024-01-01T00:00:00.000Z",
46
+ updated_at: "2024-01-01T00:00:00.000Z",
47
+ };
48
+ (0, vitest_1.beforeEach)(() => {
49
+ vitest_1.vi.clearAllMocks();
50
+ });
51
+ (0, vitest_1.describe)("secret encryption", () => {
52
+ (0, vitest_1.it)("encrypts and decrypts a secret round-trip", () => {
53
+ // We test the exported decryptSecret by creating an encrypted value
54
+ // through the createWebhook flow (which calls encryptSecret internally).
55
+ // For a direct test, we check that decryptSecret can recover the original.
56
+ (0, vitest_1.expect)(typeof webhookService.decryptSecret).toBe("function");
57
+ });
58
+ (0, vitest_1.it)("decryptSecret throws on invalid format", () => {
59
+ (0, vitest_1.expect)(() => webhookService.decryptSecret("invalid")).toThrow("Invalid encrypted value format");
60
+ });
61
+ });
62
+ (0, vitest_1.describe)("createWebhook", () => {
63
+ (0, vitest_1.it)("inserts webhook and returns it", async () => {
64
+ const pool = makeMockPool();
65
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
66
+ const client = {
67
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [mockWebhook] }),
68
+ };
69
+ return fn(client);
70
+ });
71
+ const result = await webhookService.createWebhook(pool, {
72
+ tenant_id: null,
73
+ url: "https://example.com/webhook",
74
+ secret: "mysecretatleast16chars",
75
+ events: ["tenant.created"],
76
+ });
77
+ (0, vitest_1.expect)(result).toEqual(mockWebhook);
78
+ });
79
+ });
80
+ (0, vitest_1.describe)("getWebhook", () => {
81
+ (0, vitest_1.it)("returns webhook when found", async () => {
82
+ const pool = makeMockPool();
83
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
84
+ const client = {
85
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [mockWebhook] }),
86
+ };
87
+ return fn(client);
88
+ });
89
+ const result = await webhookService.getWebhook(pool, mockWebhook.id);
90
+ (0, vitest_1.expect)(result).toEqual(mockWebhook);
91
+ });
92
+ (0, vitest_1.it)("throws WebhookNotFoundError when not found", async () => {
93
+ const pool = makeMockPool();
94
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
95
+ const client = {
96
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [] }),
97
+ };
98
+ return fn(client);
99
+ });
100
+ await (0, vitest_1.expect)(webhookService.getWebhook(pool, "nonexistent-id")).rejects.toThrow(core_1.WebhookNotFoundError);
101
+ });
102
+ });
103
+ (0, vitest_1.describe)("listWebhooks", () => {
104
+ (0, vitest_1.it)("returns all webhooks when no tenantId", async () => {
105
+ const pool = makeMockPool();
106
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
107
+ const client = {
108
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [mockWebhook] }),
109
+ };
110
+ return fn(client);
111
+ });
112
+ const result = await webhookService.listWebhooks(pool);
113
+ (0, vitest_1.expect)(result).toEqual([mockWebhook]);
114
+ });
115
+ (0, vitest_1.it)("filters by tenantId when provided", async () => {
116
+ const pool = makeMockPool();
117
+ const mockQuery = vitest_1.vi.fn().mockResolvedValue({ rows: [mockWebhook] });
118
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
119
+ const client = {
120
+ query: mockQuery,
121
+ };
122
+ return fn(client);
123
+ });
124
+ await webhookService.listWebhooks(pool, "tenant-123");
125
+ // Should have used a parameterized query with tenant_id
126
+ (0, vitest_1.expect)(mockQuery).toHaveBeenCalledWith(vitest_1.expect.stringContaining("tenant_id"), ["tenant-123"]);
127
+ });
128
+ });
129
+ (0, vitest_1.describe)("updateWebhook", () => {
130
+ (0, vitest_1.it)("returns existing webhook when no fields to update", async () => {
131
+ const pool = makeMockPool();
132
+ vitest_1.vi.mocked(poolHelpers.withTransaction).mockImplementation(async (_pool, fn) => {
133
+ const client = {
134
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [mockWebhook] }),
135
+ };
136
+ return fn(client);
137
+ });
138
+ const result = await webhookService.updateWebhook(pool, mockWebhook.id, {});
139
+ (0, vitest_1.expect)(result).toEqual(mockWebhook);
140
+ });
141
+ (0, vitest_1.it)("throws WebhookNotFoundError when webhook not found", async () => {
142
+ const pool = makeMockPool();
143
+ vitest_1.vi.mocked(poolHelpers.withTransaction).mockImplementation(async (_pool, fn) => {
144
+ const client = {
145
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [] }),
146
+ };
147
+ return fn(client);
148
+ });
149
+ await (0, vitest_1.expect)(webhookService.updateWebhook(pool, "nonexistent", { active: false })).rejects.toThrow(core_1.WebhookNotFoundError);
150
+ });
151
+ });
152
+ (0, vitest_1.describe)("deleteWebhook", () => {
153
+ (0, vitest_1.it)("resolves when webhook exists", async () => {
154
+ const pool = makeMockPool();
155
+ vitest_1.vi.mocked(poolHelpers.withTransaction).mockImplementation(async (_pool, fn) => {
156
+ const client = {
157
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [{ id: mockWebhook.id }] }),
158
+ };
159
+ return fn(client);
160
+ });
161
+ await (0, vitest_1.expect)(webhookService.deleteWebhook(pool, mockWebhook.id)).resolves.toBeUndefined();
162
+ });
163
+ (0, vitest_1.it)("throws WebhookNotFoundError when webhook not found", async () => {
164
+ const pool = makeMockPool();
165
+ vitest_1.vi.mocked(poolHelpers.withTransaction).mockImplementation(async (_pool, fn) => {
166
+ const client = {
167
+ query: vitest_1.vi.fn().mockResolvedValue({ rows: [] }),
168
+ };
169
+ return fn(client);
170
+ });
171
+ await (0, vitest_1.expect)(webhookService.deleteWebhook(pool, "nonexistent-id")).rejects.toThrow(core_1.WebhookNotFoundError);
172
+ });
173
+ });
174
+ //# sourceMappingURL=webhook-service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-service.test.js","sourceRoot":"","sources":["../../../src/services/__tests__/webhook-service.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAA8D;AAE9D,qDAAqD;AACrD,WAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;IACnB,eAAe,EAAE,WAAE,CAAC,EAAE,EAAE;CACzB,CAAC,CAAC,CAAC;AAEJ,mEAAqD;AACrD,sEAAwD;AACxD,2CAAwD;AAGxD,SAAS,YAAY;IACnB,OAAO,EAAuB,CAAC;AACjC,CAAC;AAED,MAAM,WAAW,GAAY;IAC3B,EAAE,EAAE,sCAAsC;IAC1C,SAAS,EAAE,IAAI;IACf,GAAG,EAAE,6BAA6B;IAClC,WAAW,EAAE,uBAAuB;IACpC,MAAM,EAAE,CAAC,gBAAgB,CAAC;IAC1B,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,0BAA0B;IACtC,UAAU,EAAE,0BAA0B;CACvC,CAAC;AAEF,IAAA,mBAAU,EAAC,GAAG,EAAE;IACd,WAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAA,WAAE,EAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,oEAAoE;QACpE,yEAAyE;QACzE,2EAA2E;QAC3E,IAAA,eAAM,EAAC,OAAO,cAAc,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,IAAA,eAAM,EAAC,GAAG,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAClG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,WAAE,EAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE;YACtD,SAAS,EAAE,IAAI;YACf,GAAG,EAAE,6BAA6B;YAClC,MAAM,EAAE,wBAAwB;YAChC,MAAM,EAAE,CAAC,gBAA0D,CAAC;SACrE,CAAC,CAAC;QAEH,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAA,WAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACT,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAA,eAAM,EAAC,cAAc,CAAC,UAAU,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC7E,2BAAoB,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,WAAE,EAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACrE,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,SAAS;aACqB,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,cAAc,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACtD,wDAAwD;QACxD,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,eAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,WAAE,EAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5E,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5E,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5E,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACT,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAA,eAAM,EAAC,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAChG,2BAAoB,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,WAAE,EAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5E,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;aAC/B,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAA,eAAM,EAAC,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5E,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACT,CAAC;YACxC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAA,eAAM,EAAC,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAChF,2BAAoB,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,61 @@
1
+ import pg from "pg";
2
+ export interface ApiKeyRecord {
3
+ id: string;
4
+ tenant_id: string | null;
5
+ key_hash: string;
6
+ key_prefix: string | null;
7
+ name: string | null;
8
+ created_at: Date;
9
+ last_used_at: Date | null;
10
+ revoked_at: Date | null;
11
+ expires_at: Date | null;
12
+ hash_version: number;
13
+ }
14
+ export interface CreatedApiKey {
15
+ id: string;
16
+ tenant_id: string | null;
17
+ key_prefix: string | null;
18
+ name: string | null;
19
+ created_at: Date;
20
+ /** Plaintext key — only returned on creation, never stored */
21
+ plaintext_key: string;
22
+ }
23
+ export declare function generateKey(keyPrefix: string): {
24
+ plaintextKey: string;
25
+ keyHash: string;
26
+ hashVersion: number;
27
+ };
28
+ export interface CreateApiKeyOptions {
29
+ name?: string;
30
+ expiresAt?: Date;
31
+ rateLimitMax?: number;
32
+ rateLimitWindow?: string;
33
+ }
34
+ export declare function createApiKey(pool: pg.Pool, keyPrefix: string, tenantId: string, nameOrOptions?: string | CreateApiKeyOptions, expiresAt?: Date): Promise<CreatedApiKey>;
35
+ export interface ValidatedApiKey {
36
+ tenant_id: string | null;
37
+ key_id: string;
38
+ scopes: string[];
39
+ rate_limit_max: number | null;
40
+ rate_limit_window: string | null;
41
+ }
42
+ export declare function validateApiKey(pool: pg.Pool, key: string): Promise<ValidatedApiKey | null>;
43
+ export declare function revokeApiKey(pool: pg.Pool, keyId: string): Promise<boolean>;
44
+ export declare function rotateApiKey(pool: pg.Pool, keyPrefix: string, oldKeyId: string, newName?: string): Promise<CreatedApiKey>;
45
+ export declare function listApiKeys(pool: pg.Pool, tenantId?: string): Promise<Array<{
46
+ id: string;
47
+ tenant_id: string | null;
48
+ name: string | null;
49
+ created_at: Date;
50
+ last_used_at: Date | null;
51
+ revoked_at: Date | null;
52
+ expires_at: Date | null;
53
+ }>>;
54
+ export declare function listDormantKeys(pool: pg.Pool, dormantDays?: number): Promise<Array<{
55
+ id: string;
56
+ tenant_id: string | null;
57
+ name: string | null;
58
+ last_used_at: Date | null;
59
+ created_at: Date;
60
+ }>>;
61
+ //# sourceMappingURL=api-key-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-service.d.ts","sourceRoot":"","sources":["../../src/services/api-key-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listDormantKeys = exports.listApiKeys = exports.rotateApiKey = exports.revokeApiKey = exports.validateApiKey = exports.createApiKey = exports.generateKey = void 0;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const pool_helpers_js_1 = require("../pool-helpers.js");
9
+ // --- Hashing ---
10
+ const HASH_V1_SHA256 = 1;
11
+ const HASH_V2_HMAC = 2;
12
+ function getHmacSecret() {
13
+ return process.env.STRATUM_API_KEY_HMAC_SECRET;
14
+ }
15
+ /** Legacy SHA-256 hash (v1). */
16
+ function sha256Hash(key) {
17
+ return node_crypto_1.default.createHash("sha256").update(key).digest("hex");
18
+ }
19
+ /** HMAC-SHA256 hash (v2). Requires STRATUM_API_KEY_HMAC_SECRET. */
20
+ function hmacHash(key, secret) {
21
+ return node_crypto_1.default.createHmac("sha256", secret).update(key).digest("hex");
22
+ }
23
+ /**
24
+ * Hash a key using the best available method.
25
+ * Returns HMAC-SHA256 if STRATUM_API_KEY_HMAC_SECRET is set, otherwise SHA-256.
26
+ */
27
+ function hashKey(key) {
28
+ const secret = getHmacSecret();
29
+ if (secret) {
30
+ return { keyHash: hmacHash(key, secret), hashVersion: HASH_V2_HMAC };
31
+ }
32
+ return { keyHash: sha256Hash(key), hashVersion: HASH_V1_SHA256 };
33
+ }
34
+ function generateKey(keyPrefix) {
35
+ const random = node_crypto_1.default.randomBytes(32).toString("base64url");
36
+ const plaintextKey = `${keyPrefix}${random}`;
37
+ const { keyHash, hashVersion } = hashKey(plaintextKey);
38
+ return { plaintextKey, keyHash, hashVersion };
39
+ }
40
+ exports.generateKey = generateKey;
41
+ async function createApiKey(pool, keyPrefix, tenantId, nameOrOptions, expiresAt) {
42
+ // Support both old signature (name, expiresAt) and new options object
43
+ const opts = typeof nameOrOptions === "object" && nameOrOptions !== null
44
+ ? nameOrOptions
45
+ : { name: nameOrOptions, expiresAt };
46
+ const { plaintextKey, keyHash, hashVersion } = generateKey(keyPrefix);
47
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
48
+ const res = await client.query(`INSERT INTO api_keys (tenant_id, key_hash, key_prefix, name, expires_at, rate_limit_max, rate_limit_window, hash_version)
49
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
50
+ RETURNING *`, [tenantId, keyHash, keyPrefix, opts.name ?? null, opts.expiresAt ?? null, opts.rateLimitMax ?? null, opts.rateLimitWindow ?? null, hashVersion]);
51
+ const row = res.rows[0];
52
+ return {
53
+ id: row.id,
54
+ tenant_id: row.tenant_id,
55
+ key_prefix: row.key_prefix,
56
+ name: row.name,
57
+ created_at: row.created_at,
58
+ plaintext_key: plaintextKey,
59
+ };
60
+ });
61
+ }
62
+ exports.createApiKey = createApiKey;
63
+ async function validateApiKey(pool, key) {
64
+ const hmacSecret = getHmacSecret();
65
+ // Build candidate hashes: try HMAC first (if secret is set), then SHA-256 fallback
66
+ const candidates = [];
67
+ if (hmacSecret) {
68
+ candidates.push({ hash: hmacHash(key, hmacSecret), version: HASH_V2_HMAC });
69
+ }
70
+ candidates.push({ hash: sha256Hash(key), version: HASH_V1_SHA256 });
71
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
72
+ for (const candidate of candidates) {
73
+ const res = await client.query(`SELECT id, tenant_id, key_hash, key_prefix, name, created_at, last_used_at, revoked_at, expires_at, scopes, rate_limit_max, rate_limit_window, hash_version
74
+ FROM api_keys WHERE key_hash = $1 AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > now())`, [candidate.hash]);
75
+ if (res.rows.length === 0)
76
+ continue;
77
+ const row = res.rows[0];
78
+ // Transparent upgrade: if we matched via legacy SHA-256 but HMAC secret is available,
79
+ // re-hash with HMAC and update the stored hash in-place
80
+ if (row.hash_version === HASH_V1_SHA256 && hmacSecret) {
81
+ const upgradedHash = hmacHash(key, hmacSecret);
82
+ pool
83
+ .query(`UPDATE api_keys SET key_hash = $1, hash_version = $2, last_used_at = now() WHERE id = $3`, [upgradedHash, HASH_V2_HMAC, row.id])
84
+ .catch(() => {
85
+ // Non-critical: upgrade will happen on next request
86
+ });
87
+ }
88
+ else {
89
+ // Update last_used_at — fire-and-forget
90
+ pool
91
+ .query(`UPDATE api_keys SET last_used_at = now() WHERE id = $1`, [row.id])
92
+ .catch(() => { });
93
+ }
94
+ return {
95
+ tenant_id: row.tenant_id,
96
+ key_id: row.id,
97
+ scopes: row.scopes ?? ["read"],
98
+ rate_limit_max: row.rate_limit_max,
99
+ rate_limit_window: row.rate_limit_window,
100
+ };
101
+ }
102
+ return null;
103
+ });
104
+ }
105
+ exports.validateApiKey = validateApiKey;
106
+ async function revokeApiKey(pool, keyId) {
107
+ return (0, pool_helpers_js_1.withTransaction)(pool, async (client) => {
108
+ const res = await client.query(`UPDATE api_keys SET revoked_at = now() WHERE id = $1 AND revoked_at IS NULL RETURNING id`, [keyId]);
109
+ return res.rows.length > 0;
110
+ });
111
+ }
112
+ exports.revokeApiKey = revokeApiKey;
113
+ async function rotateApiKey(pool, keyPrefix, oldKeyId, newName) {
114
+ return (0, pool_helpers_js_1.withTransaction)(pool, async (client) => {
115
+ // Verify old key exists and is not revoked
116
+ const oldRes = await client.query(`SELECT id, tenant_id, name, key_prefix FROM api_keys WHERE id = $1 AND revoked_at IS NULL`, [oldKeyId]);
117
+ if (oldRes.rows.length === 0) {
118
+ throw new Error(`API key not found or already revoked: ${oldKeyId}`);
119
+ }
120
+ const old = oldRes.rows[0];
121
+ // Create new key for same tenant
122
+ const { plaintextKey, keyHash, hashVersion } = generateKey(keyPrefix);
123
+ const res = await client.query(`INSERT INTO api_keys (tenant_id, key_hash, key_prefix, name, hash_version)
124
+ VALUES ($1, $2, $3, $4, $5)
125
+ RETURNING id, tenant_id, name, key_prefix, created_at`, [old.tenant_id, keyHash, keyPrefix, newName ?? `${old.name ?? "key"} (rotated)`, hashVersion]);
126
+ // Revoke old key
127
+ await client.query(`UPDATE api_keys SET revoked_at = now() WHERE id = $1`, [oldKeyId]);
128
+ const row = res.rows[0];
129
+ return {
130
+ id: row.id,
131
+ tenant_id: row.tenant_id,
132
+ key_prefix: row.key_prefix,
133
+ name: row.name,
134
+ created_at: row.created_at,
135
+ plaintext_key: plaintextKey,
136
+ };
137
+ });
138
+ }
139
+ exports.rotateApiKey = rotateApiKey;
140
+ async function listApiKeys(pool, tenantId) {
141
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
142
+ if (tenantId) {
143
+ const res = await client.query(`SELECT id, tenant_id, name, created_at, last_used_at, revoked_at, expires_at
144
+ FROM api_keys WHERE tenant_id = $1 ORDER BY created_at DESC`, [tenantId]);
145
+ return res.rows;
146
+ }
147
+ const res = await client.query(`SELECT id, tenant_id, name, created_at, last_used_at, revoked_at, expires_at
148
+ FROM api_keys ORDER BY created_at DESC`);
149
+ return res.rows;
150
+ });
151
+ }
152
+ exports.listApiKeys = listApiKeys;
153
+ async function listDormantKeys(pool, dormantDays = 90) {
154
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
155
+ const res = await client.query(`SELECT id, tenant_id, name, last_used_at, created_at
156
+ FROM api_keys
157
+ WHERE revoked_at IS NULL
158
+ AND (last_used_at IS NULL OR last_used_at < now() - ($1 || ' days')::interval)
159
+ ORDER BY last_used_at ASC NULLS FIRST`, [dormantDays]);
160
+ return res.rows;
161
+ });
162
+ }
163
+ exports.listDormantKeys = listDormantKeys;
164
+ //# sourceMappingURL=api-key-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-service.js","sourceRoot":"","sources":["../../src/services/api-key-service.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAiC;AAEjC,wDAAiE;AAyBjE,kBAAkB;AAElB,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,SAAS,aAAa;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;AACjD,CAAC;AAED,gCAAgC;AAChC,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,qBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,mEAAmE;AACnE,SAAS,QAAQ,CAAC,GAAW,EAAE,MAAc;IAC3C,OAAO,qBAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AACnE,CAAC;AAED,SAAgB,WAAW,CAAC,SAAiB;IAC3C,MAAM,MAAM,GAAG,qBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,GAAG,SAAS,GAAG,MAAM,EAAE,CAAC;IAC7C,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAChD,CAAC;AALD,kCAKC;AASM,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,SAAiB,EACjB,QAAgB,EAChB,aAA4C,EAC5C,SAAgB;IAEhB,sEAAsE;IACtE,MAAM,IAAI,GAAwB,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;QAC3F,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;IACvC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAEtE,OAAO,IAAA,4BAAU,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;;mBAEa,EACb,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,IAAI,CAAC,eAAe,IAAI,IAAI,EAAE,WAAW,CAAC,CAChJ,CAAC;QAEF,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,aAAa,EAAE,YAAY;SAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AA/BD,oCA+BC;AAUM,KAAK,UAAU,cAAc,CAClC,IAAa,EACb,GAAW;IAEX,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,mFAAmF;IACnF,MAAM,UAAU,GAA6C,EAAE,CAAC;IAChE,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAEpE,OAAO,IAAA,4BAAU,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;iHACyG,EACzG,CAAC,SAAS,CAAC,IAAI,CAAC,CACjB,CAAC;YAEF,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEpC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAExB,sFAAsF;YACtF,wDAAwD;YACxD,IAAI,GAAG,CAAC,YAAY,KAAK,cAAc,IAAI,UAAU,EAAE,CAAC;gBACtD,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBAC/C,IAAI;qBACD,KAAK,CACJ,0FAA0F,EAC1F,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,CACrC;qBACA,KAAK,CAAC,GAAG,EAAE;oBACV,oDAAoD;gBACtD,CAAC,CAAC,CAAC;YACP,CAAC;iBAAM,CAAC;gBACN,wCAAwC;gBACxC,IAAI;qBACD,KAAK,CAAC,wDAAwD,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;qBACzE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACrB,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM,EAAE,GAAG,CAAC,EAAE;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC;gBAC9B,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;aACzC,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAvDD,wCAuDC;AAEM,KAAK,UAAU,YAAY,CAAC,IAAa,EAAE,KAAa;IAC7D,OAAO,IAAA,iCAAe,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,0FAA0F,EAC1F,CAAC,KAAK,CAAC,CACR,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AARD,oCAQC;AAEM,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,SAAiB,EACjB,QAAgB,EAChB,OAAgB;IAEhB,OAAO,IAAA,iCAAe,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC5C,2CAA2C;QAC3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B,2FAA2F,EAC3F,CAAC,QAAQ,CAAC,CACX,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3B,iCAAiC;QACjC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;QACtE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;;6DAEuD,EACvD,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,KAAK,YAAY,EAAE,WAAW,CAAC,CAC9F,CAAC;QAEF,iBAAiB;QACjB,MAAM,MAAM,CAAC,KAAK,CAChB,sDAAsD,EACtD,CAAC,QAAQ,CAAC,CACX,CAAC;QAEF,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,aAAa,EAAE,YAAY;SAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AA1CD,oCA0CC;AAEM,KAAK,UAAU,WAAW,CAC/B,IAAa,EACb,QAAiB;IAEjB,OAAO,IAAA,4BAAU,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;qEAC6D,EAC7D,CAAC,QAAQ,CAAC,CACX,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;8CACwC,CACzC,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAnBD,kCAmBC;AAEM,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,cAAsB,EAAE;IAExB,OAAO,IAAA,4BAAU,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B;;;;6CAIuC,EACvC,CAAC,WAAW,CAAC,CACd,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAfD,0CAeC"}
@@ -0,0 +1,6 @@
1
+ import pg from "pg";
2
+ import type { AuditContext, AuditEntry, AuditLogQuery } from "@stratum-hq/core";
3
+ export declare function createAuditEntry(pool: pg.Pool, context: AuditContext, action: string, resourceType: string, resourceId: string | null, tenantId: string | null, beforeState?: Record<string, unknown> | null, afterState?: Record<string, unknown> | null, metadata?: Record<string, unknown>): Promise<AuditEntry>;
4
+ export declare function queryAuditLogs(pool: pg.Pool, query: AuditLogQuery): Promise<AuditEntry[]>;
5
+ export declare function getAuditEntry(pool: pg.Pool, id: string): Promise<AuditEntry | null>;
6
+ //# sourceMappingURL=audit-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-service.d.ts","sourceRoot":"","sources":["../../src/services/audit-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEhF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAC5C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,UAAU,CAAC,CAwBrB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAkDvB;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAY5B"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAuditEntry = exports.queryAuditLogs = exports.createAuditEntry = void 0;
4
+ const pool_helpers_js_1 = require("../pool-helpers.js");
5
+ async function createAuditEntry(pool, context, action, resourceType, resourceId, tenantId, beforeState, afterState, metadata) {
6
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
7
+ const res = await client.query(`INSERT INTO audit_logs (actor_id, actor_type, action, resource_type, resource_id, tenant_id, source_ip, request_id, before_state, after_state, metadata)
8
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
9
+ RETURNING id, actor_id, actor_type, action, resource_type, resource_id, tenant_id,
10
+ source_ip::text as source_ip, request_id, before_state, after_state, metadata,
11
+ created_at::text as created_at`, [
12
+ context.actor_id,
13
+ context.actor_type,
14
+ action,
15
+ resourceType,
16
+ resourceId,
17
+ tenantId,
18
+ context.source_ip ?? null,
19
+ context.request_id ?? null,
20
+ beforeState ? JSON.stringify(beforeState) : null,
21
+ afterState ? JSON.stringify(afterState) : null,
22
+ JSON.stringify(metadata ?? {}),
23
+ ]);
24
+ return res.rows[0];
25
+ });
26
+ }
27
+ exports.createAuditEntry = createAuditEntry;
28
+ async function queryAuditLogs(pool, query) {
29
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
30
+ const conditions = [];
31
+ const values = [];
32
+ let idx = 1;
33
+ if (query.tenant_id !== undefined) {
34
+ conditions.push(`tenant_id = $${idx++}`);
35
+ values.push(query.tenant_id);
36
+ }
37
+ if (query.action !== undefined) {
38
+ conditions.push(`action = $${idx++}`);
39
+ values.push(query.action);
40
+ }
41
+ if (query.resource_type !== undefined) {
42
+ conditions.push(`resource_type = $${idx++}`);
43
+ values.push(query.resource_type);
44
+ }
45
+ if (query.actor_id !== undefined) {
46
+ conditions.push(`actor_id = $${idx++}`);
47
+ values.push(query.actor_id);
48
+ }
49
+ if (query.from !== undefined) {
50
+ conditions.push(`created_at >= $${idx++}`);
51
+ values.push(query.from);
52
+ }
53
+ if (query.to !== undefined) {
54
+ conditions.push(`created_at <= $${idx++}`);
55
+ values.push(query.to);
56
+ }
57
+ if (query.cursor !== undefined) {
58
+ conditions.push(`id < $${idx++}`);
59
+ values.push(query.cursor);
60
+ }
61
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
62
+ values.push(query.limit ?? 100);
63
+ const res = await client.query(`SELECT id, actor_id, actor_type, action, resource_type, resource_id, tenant_id,
64
+ source_ip::text as source_ip, request_id, before_state, after_state, metadata,
65
+ created_at::text as created_at
66
+ FROM audit_logs
67
+ ${where}
68
+ ORDER BY created_at DESC, id DESC
69
+ LIMIT $${idx}`, values);
70
+ return res.rows;
71
+ });
72
+ }
73
+ exports.queryAuditLogs = queryAuditLogs;
74
+ async function getAuditEntry(pool, id) {
75
+ return (0, pool_helpers_js_1.withClient)(pool, async (client) => {
76
+ const res = await client.query(`SELECT id, actor_id, actor_type, action, resource_type, resource_id, tenant_id,
77
+ source_ip::text as source_ip, request_id, before_state, after_state, metadata,
78
+ created_at::text as created_at
79
+ FROM audit_logs
80
+ WHERE id = $1`, [id]);
81
+ return res.rows[0] ?? null;
82
+ });
83
+ }
84
+ exports.getAuditEntry = getAuditEntry;
85
+ //# sourceMappingURL=audit-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-service.js","sourceRoot":"","sources":["../../src/services/audit-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import pg from "pg";
2
+ import { type ConfigEntry, type SetConfigInput, type ResolvedConfig, type BatchSetConfigResult } from "@stratum-hq/core";
3
+ /**
4
+ * Resolve the effective config for a tenant by batch-loading ancestor configs
5
+ * in a single query and walking root→leaf.
6
+ */
7
+ export declare function resolveConfig(pool: pg.Pool, tenantId: string): Promise<ResolvedConfig>;
8
+ /**
9
+ * Set (upsert) a config key for a tenant.
10
+ * Rejects if the key is locked by an ancestor.
11
+ */
12
+ export declare function setConfig(pool: pg.Pool, tenantId: string, key: string, input: SetConfigInput): Promise<ConfigEntry>;
13
+ /**
14
+ * Set multiple config keys for a tenant in a single transaction.
15
+ * Partial success: locked keys are skipped and reported as errors,
16
+ * while unlocked keys are set successfully within the same transaction.
17
+ */
18
+ export declare function batchSetConfig(pool: pg.Pool, tenantId: string, entries: Array<{
19
+ key: string;
20
+ value: unknown;
21
+ locked?: boolean;
22
+ sensitive?: boolean;
23
+ }>): Promise<BatchSetConfigResult>;
24
+ /**
25
+ * Delete a config override for a tenant, revealing the inherited parent value.
26
+ */
27
+ export declare function deleteConfig(pool: pg.Pool, tenantId: string, key: string): Promise<void>;
28
+ /**
29
+ * Return all config entries for a tenant showing inheritance status:
30
+ * inherited (from ancestor), overridden (tenant has own value), or locked.
31
+ */
32
+ export declare function getConfigWithInheritance(pool: pg.Pool, tenantId: string): Promise<ResolvedConfig>;
33
+ //# sourceMappingURL=config-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-service.d.ts","sourceRoot":"","sources":["../../src/services/config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAO1B,MAAM,kBAAkB,CAAC;AAG1B;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAyE5F;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,WAAW,CAAC,CA8CtB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACrF,OAAO,CAAC,oBAAoB,CAAC,CAuE/B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CA0GzB"}