@inobeta/api 0.9.0 → 0.9.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.
@@ -3,6 +3,11 @@ import type { FastifyPluginAsync } from "fastify";
3
3
  declare module "fastify" {
4
4
  interface FastifyInstance {
5
5
  kc: KeycloakAdminClient;
6
+ kcAdminState: {
7
+ connected: boolean;
8
+ lastError: unknown | null;
9
+ lastAuthAt: Date | null;
10
+ };
6
11
  }
7
12
  }
8
13
  export interface KeycloakAdminPluginOptions {
@@ -10,6 +15,8 @@ export interface KeycloakAdminPluginOptions {
10
15
  realmName: string;
11
16
  clientId: string;
12
17
  clientSecret: string;
18
+ retryDelayMs?: number;
19
+ failOnStartup?: boolean;
13
20
  }
14
21
  export declare const keycloakAdminPlugin: FastifyPluginAsync<KeycloakAdminPluginOptions>;
15
22
  export default keycloakAdminPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,QAAQ,SAAS,CAAC;IACrB,UAAU,eAAe;QACrB,EAAE,EAAE,mBAAmB,CAAC;KAC3B;CACJ;AAMD,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACxB;AAiFD,eAAO,MAAM,mBAAmB,gDAE9B,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,QAAQ,SAAS,CAAC;IACrB,UAAU,eAAe;QACrB,EAAE,EAAE,mBAAmB,CAAC;QACxB,YAAY,EAAE;YACV,SAAS,EAAE,OAAO,CAAC;YACnB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;YAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;SAC3B,CAAC;KACL;CACJ;AAMD,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAwID,eAAO,MAAM,mBAAmB,gDAE9B,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
@@ -15,58 +15,101 @@ function getTokenExpirationMilliseconds(accessToken) {
15
15
  if (!decoded?.exp) {
16
16
  return 0;
17
17
  }
18
- return decoded.exp * 1000 - Date.now();
18
+ return Math.max(decoded.exp * 1000 - Date.now(), 0);
19
19
  }
20
- const keycloakAdminPluginAsync = async (instance, options) => {
21
- instance.log.info("Initializing Keycloak Admin Client");
22
- try {
23
- if (!instance.kc) {
24
- const kc = new keycloak_admin_client_1.default({
25
- baseUrl: options.baseUrl,
26
- realmName: options.realmName
27
- });
28
- const credentials = {
29
- grantType: "client_credentials",
30
- clientId: options.clientId,
31
- clientSecret: options.clientSecret
32
- };
33
- await loopConnect(kc, credentials);
34
- instance.decorate("kc", kc);
35
- const accessTokenLifespan = getTokenExpirationMilliseconds(kc.accessToken);
36
- const refreshIntervalMs = accessTokenLifespan > 0
37
- ? Math.floor(accessTokenLifespan * 0.9)
20
+ async function authenticate(kc, credentials) {
21
+ await kc.auth(credentials);
22
+ return getTokenExpirationMilliseconds(kc.accessToken);
23
+ }
24
+ const keycloakAdminPluginAsync = async (fastify, options) => {
25
+ fastify.log.info("Initializing Keycloak Admin Client");
26
+ const kc = new keycloak_admin_client_1.default({
27
+ baseUrl: options.baseUrl,
28
+ realmName: options.realmName,
29
+ });
30
+ const credentials = {
31
+ grantType: "client_credentials",
32
+ clientId: options.clientId,
33
+ clientSecret: options.clientSecret,
34
+ };
35
+ const state = {
36
+ connected: false,
37
+ lastError: null,
38
+ lastAuthAt: null,
39
+ };
40
+ fastify.decorate("kc", kc);
41
+ fastify.decorate("kcAdminState", state);
42
+ const retryDelayMs = options.retryDelayMs ?? 5000;
43
+ const failOnStartup = options.failOnStartup ?? false;
44
+ let stopped = false;
45
+ let timer = null;
46
+ let running = false;
47
+ const scheduleNext = (delayMs) => {
48
+ if (stopped)
49
+ return;
50
+ timer = setTimeout(() => {
51
+ void authLoop();
52
+ }, delayMs);
53
+ };
54
+ const authLoop = async () => {
55
+ if (stopped || running)
56
+ return;
57
+ running = true;
58
+ try {
59
+ const tokenLifespanMs = await authenticate(kc, credentials);
60
+ state.connected = true;
61
+ state.lastError = null;
62
+ state.lastAuthAt = new Date();
63
+ const nextRefreshMs = tokenLifespanMs > 0
64
+ ? Math.max(Math.floor(tokenLifespanMs * 0.9), 10000)
38
65
  : 60000;
39
- instance.log.info({
40
- accessTokenLifespanSeconds: Math.floor(accessTokenLifespan / 1000),
41
- refreshIntervalSeconds: Math.floor(refreshIntervalMs / 1000)
42
- }, "Keycloak Admin Client initialized");
43
- const refreshTokenInterval = setInterval(() => {
44
- void kc.auth(credentials);
45
- }, refreshIntervalMs);
46
- instance.addHook("onClose", (_fastify, done) => {
47
- clearInterval(refreshTokenInterval);
48
- done();
49
- });
66
+ fastify.log.info({
67
+ tokenLifespanSeconds: Math.floor(tokenLifespanMs / 1000),
68
+ nextRefreshSeconds: Math.floor(nextRefreshMs / 1000),
69
+ }, "Keycloak Admin Client authenticated");
70
+ scheduleNext(nextRefreshMs);
50
71
  }
51
- }
52
- catch (error) {
53
- instance.log.error(error, "Error initializing Keycloak Admin Client");
54
- }
55
- };
56
- async function loopConnect(kc, credentials) {
57
- while (true) {
72
+ catch (error) {
73
+ state.connected = false;
74
+ state.lastError = error;
75
+ fastify.log.error(error, "Keycloak Admin Client auth failed, retrying");
76
+ scheduleNext(retryDelayMs);
77
+ }
78
+ finally {
79
+ running = false;
80
+ }
81
+ };
82
+ if (failOnStartup) {
58
83
  try {
59
- await kc.auth(credentials);
60
- break;
84
+ const tokenLifespanMs = await authenticate(kc, credentials);
85
+ state.connected = true;
86
+ state.lastError = null;
87
+ state.lastAuthAt = new Date();
88
+ const nextRefreshMs = tokenLifespanMs > 0
89
+ ? Math.max(Math.floor(tokenLifespanMs * 0.9), 10000)
90
+ : 60000;
91
+ scheduleNext(nextRefreshMs);
61
92
  }
62
93
  catch (error) {
63
- console.error(error, "Error refreshing Keycloak Admin Client token, retrying in 5 seconds");
64
- await new Promise(resolve => setTimeout(resolve, 5000));
94
+ fastify.log.error(error, "Failed to authenticate Keycloak on startup");
95
+ throw error;
65
96
  }
66
97
  }
67
- }
98
+ else {
99
+ void authLoop();
100
+ }
101
+ fastify.addHook("onClose", (_instance, done) => {
102
+ stopped = true;
103
+ if (timer) {
104
+ clearTimeout(timer);
105
+ timer = null;
106
+ }
107
+ done();
108
+ });
109
+ fastify.log.info("Keycloak Admin plugin initialized");
110
+ };
68
111
  exports.keycloakAdminPlugin = (0, fastify_plugin_1.default)(keycloakAdminPluginAsync, {
69
- name: "inobeta-keycloak-admin"
112
+ name: "inobeta-keycloak-admin",
70
113
  });
71
114
  exports.default = exports.keycloakAdminPlugin;
72
115
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":";;;;;;AAAA,4FAAkE;AAGlE,oEAA2C;AAC3C,gEAA+B;AAmB/B,SAAS,8BAA8B,CAAC,WAAoB;IACxD,IAAI,CAAC,WAAW,EAAE;QACd,OAAO,CAAC,CAAC;KACZ;IAED,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,WAAW,CAAsB,CAAC;IAE7D,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;QACf,OAAO,CAAC,CAAC;KACZ;IAED,OAAO,OAAO,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,wBAAwB,GAE1B,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IAC5B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IAExD,IAAI;QACA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;YACd,MAAM,EAAE,GAAG,IAAI,+BAAmB,CAAC;gBAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,SAAS,EAAE,OAAO,CAAC,SAAS;aAC/B,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG;gBAChB,SAAS,EAAE,oBAA6B;gBACxC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;aACrC,CAAC;YAEF,MAAM,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;YACnC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE5B,MAAM,mBAAmB,GAAG,8BAA8B,CACtD,EAAE,CAAC,WAAW,CACjB,CAAC;YAEF,MAAM,iBAAiB,GACnB,mBAAmB,GAAG,CAAC;gBACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,GAAG,CAAC;gBACvC,CAAC,CAAC,KAAM,CAAC;YAEjB,QAAQ,CAAC,GAAG,CAAC,IAAI,CACb;gBACI,0BAA0B,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC;gBAClE,sBAAsB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;aAC/D,EACD,mCAAmC,CACtC,CAAC;YAEF,MAAM,oBAAoB,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC1C,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC,EAAE,iBAAiB,CAAC,CAAC;YAEtB,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE;gBAC3C,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBACpC,IAAI,EAAE,CAAC;YACX,CAAC,CAAC,CAAC;SACN;KACJ;IAAC,OAAO,KAAK,EAAE;QACZ,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,0CAA0C,CAAC,CAAC;KACzE;AACL,CAAC,CAAC;AAGF,KAAK,UAAU,WAAW,CAAC,EAAuB,EAAE,WAAwB;IACxE,OAAO,IAAI,EAAE;QACT,IAAI;YACA,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3B,MAAM;SACT;QAAC,OAAO,KAAK,EAAE;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,qEAAqE,CAAC,CAAC;YAC5F,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAK,CAAC,CAAC,CAAC;SAC5D;KACJ;AACL,CAAC;AAEY,QAAA,mBAAmB,GAAG,IAAA,wBAAa,EAAC,wBAAwB,EAAE;IACvE,IAAI,EAAE,wBAAwB;CACjC,CAAC,CAAC;AAEH,kBAAe,2BAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inobeta/api",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Shared backend library for Inobeta projects",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",