mcp-creatio 0.4.0 → 0.4.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 (160) hide show
  1. package/dist/cli.d.ts +5 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +18 -11
  4. package/dist/cli.js.map +1 -1
  5. package/dist/creatio/auth/auth.d.ts +2 -0
  6. package/dist/creatio/auth/auth.d.ts.map +1 -1
  7. package/dist/creatio/auth/auth.js.map +1 -1
  8. package/dist/creatio/auth/providers/base-provider.d.ts +1 -0
  9. package/dist/creatio/auth/providers/base-provider.d.ts.map +1 -1
  10. package/dist/creatio/auth/providers/base-provider.js +3 -0
  11. package/dist/creatio/auth/providers/base-provider.js.map +1 -1
  12. package/dist/creatio/auth/providers/oauth2-code-provider.d.ts +3 -0
  13. package/dist/creatio/auth/providers/oauth2-code-provider.d.ts.map +1 -1
  14. package/dist/creatio/auth/providers/oauth2-code-provider.js +30 -24
  15. package/dist/creatio/auth/providers/oauth2-code-provider.js.map +1 -1
  16. package/dist/creatio/services/http-client.d.ts.map +1 -1
  17. package/dist/creatio/services/http-client.js +0 -1
  18. package/dist/creatio/services/http-client.js.map +1 -1
  19. package/dist/creatio/services/metadata-store.d.ts +5 -0
  20. package/dist/creatio/services/metadata-store.d.ts.map +1 -1
  21. package/dist/creatio/services/metadata-store.js +18 -6
  22. package/dist/creatio/services/metadata-store.js.map +1 -1
  23. package/dist/creatio/services/odata-crud-provider.d.ts +2 -0
  24. package/dist/creatio/services/odata-crud-provider.d.ts.map +1 -1
  25. package/dist/creatio/services/odata-crud-provider.js +10 -1
  26. package/dist/creatio/services/odata-crud-provider.js.map +1 -1
  27. package/dist/server/http/creatio-oauth-handlers.d.ts +0 -1
  28. package/dist/server/http/creatio-oauth-handlers.d.ts.map +1 -1
  29. package/dist/server/http/creatio-oauth-handlers.js +30 -23
  30. package/dist/server/http/creatio-oauth-handlers.js.map +1 -1
  31. package/dist/server/http/httpServer.d.ts +9 -0
  32. package/dist/server/http/httpServer.d.ts.map +1 -1
  33. package/dist/server/http/httpServer.js +34 -11
  34. package/dist/server/http/httpServer.js.map +1 -1
  35. package/dist/server/http/mcp-handlers.d.ts.map +1 -1
  36. package/dist/server/http/mcp-handlers.js +4 -1
  37. package/dist/server/http/mcp-handlers.js.map +1 -1
  38. package/dist/server/http/mcp-oauth-handlers.d.ts.map +1 -1
  39. package/dist/server/http/mcp-oauth-handlers.js +18 -6
  40. package/dist/server/http/mcp-oauth-handlers.js.map +1 -1
  41. package/dist/server/http/middleware.d.ts +7 -0
  42. package/dist/server/http/middleware.d.ts.map +1 -1
  43. package/dist/server/http/middleware.js +23 -0
  44. package/dist/server/http/middleware.js.map +1 -1
  45. package/dist/server/http/rate-limiter.d.ts +24 -0
  46. package/dist/server/http/rate-limiter.d.ts.map +1 -0
  47. package/dist/server/http/rate-limiter.js +42 -0
  48. package/dist/server/http/rate-limiter.js.map +1 -0
  49. package/dist/server/oauth/oauth-server.d.ts +0 -1
  50. package/dist/server/oauth/oauth-server.d.ts.map +1 -1
  51. package/dist/server/oauth/oauth-server.js +11 -21
  52. package/dist/server/oauth/oauth-server.js.map +1 -1
  53. package/dist/server/oauth/storage.d.ts +0 -2
  54. package/dist/server/oauth/storage.d.ts.map +1 -1
  55. package/dist/server/oauth/storage.js +0 -6
  56. package/dist/server/oauth/storage.js.map +1 -1
  57. package/dist/server/oauth/validators.d.ts +6 -0
  58. package/dist/server/oauth/validators.d.ts.map +1 -1
  59. package/dist/server/oauth/validators.js +28 -0
  60. package/dist/server/oauth/validators.js.map +1 -1
  61. package/dist/services/session-context.d.ts +8 -7
  62. package/dist/services/session-context.d.ts.map +1 -1
  63. package/dist/services/session-context.js +7 -27
  64. package/dist/services/session-context.js.map +1 -1
  65. package/package.json +12 -3
  66. package/.dockerignore +0 -12
  67. package/.editorconfig +0 -14
  68. package/.eslintrc.cjs +0 -18
  69. package/.gitattributes +0 -8
  70. package/.github/workflows/docker-publish.yml +0 -50
  71. package/.prettierignore +0 -3
  72. package/.prettierrc +0 -9
  73. package/.vscode/launch.json +0 -23
  74. package/.vscode/mcp.json +0 -13
  75. package/.vscode/settings.json +0 -16
  76. package/Agent.md +0 -190
  77. package/Debug.md +0 -32
  78. package/Dockerfile +0 -23
  79. package/docs/coding-style.md +0 -30
  80. package/eslint.config.cjs +0 -95
  81. package/src/cli.ts +0 -162
  82. package/src/config-builder.ts +0 -76
  83. package/src/consts.ts +0 -3
  84. package/src/creatio/auth/auth-manager.ts +0 -27
  85. package/src/creatio/auth/auth.ts +0 -31
  86. package/src/creatio/auth/index.ts +0 -3
  87. package/src/creatio/auth/providers/base-oauth2-provider.ts +0 -62
  88. package/src/creatio/auth/providers/base-provider.ts +0 -42
  89. package/src/creatio/auth/providers/index.ts +0 -4
  90. package/src/creatio/auth/providers/legacy-provider.ts +0 -70
  91. package/src/creatio/auth/providers/oauth2-code-provider.ts +0 -252
  92. package/src/creatio/auth/providers/oauth2-provider.ts +0 -91
  93. package/src/creatio/auth/providers/type.ts +0 -5
  94. package/src/creatio/client-config.ts +0 -34
  95. package/src/creatio/engines/admin-operation/admin-operation-engine.ts +0 -44
  96. package/src/creatio/engines/configuration/configuration-engine.ts +0 -26
  97. package/src/creatio/engines/crud/crud-engine.ts +0 -47
  98. package/src/creatio/engines/engine-manager.ts +0 -157
  99. package/src/creatio/engines/engine-registry.ts +0 -39
  100. package/src/creatio/engines/engine.ts +0 -3
  101. package/src/creatio/engines/feature/feature-engine.ts +0 -20
  102. package/src/creatio/engines/index.ts +0 -10
  103. package/src/creatio/engines/process/process-engine.ts +0 -20
  104. package/src/creatio/engines/sys-settings/sys-settings-engine.ts +0 -41
  105. package/src/creatio/engines/user/user-engine.ts +0 -20
  106. package/src/creatio/index.ts +0 -6
  107. package/src/creatio/provider-context.ts +0 -21
  108. package/src/creatio/providers/admin-operation-provider.ts +0 -34
  109. package/src/creatio/providers/configuration-provider.ts +0 -22
  110. package/src/creatio/providers/crud-provider.ts +0 -45
  111. package/src/creatio/providers/feature-provider.ts +0 -10
  112. package/src/creatio/providers/index.ts +0 -7
  113. package/src/creatio/providers/process-provider.ts +0 -15
  114. package/src/creatio/providers/sys-settings-provider.ts +0 -63
  115. package/src/creatio/providers/user-provider.ts +0 -12
  116. package/src/creatio/services/admin-operation-service-provider.ts +0 -115
  117. package/src/creatio/services/configuration-service-provider.ts +0 -127
  118. package/src/creatio/services/creatio-service-context.ts +0 -55
  119. package/src/creatio/services/feature-service-provider.ts +0 -60
  120. package/src/creatio/services/http-client.ts +0 -174
  121. package/src/creatio/services/index.ts +0 -10
  122. package/src/creatio/services/metadata-store.ts +0 -181
  123. package/src/creatio/services/odata-crud-provider.ts +0 -210
  124. package/src/creatio/services/process-service-provider.ts +0 -76
  125. package/src/creatio/services/sys-settings-service-provider.ts +0 -192
  126. package/src/creatio/services/user-info-provider.ts +0 -41
  127. package/src/index.ts +0 -44
  128. package/src/log.ts +0 -183
  129. package/src/server/http/creatio-oauth-handlers.ts +0 -146
  130. package/src/server/http/httpServer.ts +0 -150
  131. package/src/server/http/index.ts +0 -5
  132. package/src/server/http/mcp-handlers.ts +0 -92
  133. package/src/server/http/mcp-oauth-handlers.ts +0 -108
  134. package/src/server/http/middleware.ts +0 -91
  135. package/src/server/index.ts +0 -2
  136. package/src/server/mcp/filters.ts +0 -97
  137. package/src/server/mcp/index.ts +0 -1
  138. package/src/server/mcp/prompts-data.ts +0 -1292
  139. package/src/server/mcp/server.ts +0 -442
  140. package/src/server/mcp/tools-data.ts +0 -748
  141. package/src/server/oauth/client-manager.ts +0 -47
  142. package/src/server/oauth/index.ts +0 -6
  143. package/src/server/oauth/oauth-server.ts +0 -185
  144. package/src/server/oauth/storage.ts +0 -106
  145. package/src/server/oauth/token-manager.ts +0 -80
  146. package/src/server/oauth/types.ts +0 -55
  147. package/src/server/oauth/validators.ts +0 -56
  148. package/src/services/index.ts +0 -2
  149. package/src/services/session-context.ts +0 -232
  150. package/src/services/token-refresh-scheduler.ts +0 -68
  151. package/src/types/index.ts +0 -1
  152. package/src/types/network.ts +0 -7
  153. package/src/utils/context.ts +0 -49
  154. package/src/utils/env.ts +0 -12
  155. package/src/utils/index.ts +0 -5
  156. package/src/utils/mcp.ts +0 -8
  157. package/src/utils/network.ts +0 -65
  158. package/src/utils/pkce.ts +0 -39
  159. package/src/version.ts +0 -15
  160. package/tsconfig.json +0 -28
@@ -1,62 +0,0 @@
1
- import { OAuth2AuthConfig, OAuth2CodeAuthConfig } from '../../client-config';
2
- import { EXPIRES_MARGIN_SECONDS, buildHeaders } from '../auth';
3
-
4
- import { BaseProvider } from './base-provider';
5
-
6
- type OAuthConfig = OAuth2AuthConfig | OAuth2CodeAuthConfig;
7
-
8
- export abstract class BaseOAuth2Provider<
9
- T extends OAuthConfig = OAuthConfig,
10
- > extends BaseProvider<T> {
11
- protected abstract readonly authErrorCode: string;
12
-
13
- protected accessToken: string | undefined;
14
-
15
- protected accessTokenExpiryMs: number | undefined;
16
-
17
- protected abstract ensureAccessToken(force?: boolean): Promise<string | undefined>;
18
-
19
- protected computeExpiryMs(expiresInSeconds: number, minSeconds: number = 1): number {
20
- return Date.now() + Math.max(minSeconds, expiresInSeconds - EXPIRES_MARGIN_SECONDS) * 1000;
21
- }
22
-
23
- protected getIdentityBase(): string {
24
- if (this.authConfig.idBaseUrl) {
25
- let base = String(this.authConfig.idBaseUrl).replace(/\/$/, '');
26
- if (!/\/0$/.test(base)) {
27
- base = base + '/0';
28
- }
29
- return base;
30
- }
31
- let base = this.config.baseUrl.replace(/\/$/, '');
32
- if (!/\/0$/.test(base)) {
33
- base = base + '/0';
34
- }
35
- return base;
36
- }
37
-
38
- protected storageKey(userKey: string): string {
39
- const base = this.getIdentityBase();
40
- const kind = (this.config as any)?.auth?.kind ?? 'unknown';
41
- const clientId = (this.config as any)?.auth?.clientId ?? 'noclient';
42
- return `${kind}|${base}|${clientId}|${userKey}`;
43
- }
44
-
45
- protected throwNoTokenError(): void {
46
- throw new Error(this.authErrorCode);
47
- }
48
-
49
- public async getHeaders(accept: string, isJson?: boolean): Promise<Record<string, string>> {
50
- const token = await this.ensureAccessToken(false);
51
- if (!token) {
52
- this.throwNoTokenError();
53
- }
54
- return buildHeaders(accept, Boolean(isJson), token);
55
- }
56
-
57
- public async refresh(): Promise<void> {
58
- this.accessToken = undefined;
59
- this.accessTokenExpiryMs = undefined;
60
- await this.ensureAccessToken(true);
61
- }
62
- }
@@ -1,42 +0,0 @@
1
- import { CreatioClientAuthConfig, CreatioClientConfig } from '../../client-config';
2
- import { ICreatioAuthProvider } from '../auth';
3
-
4
- import { AuthProviderType } from './type';
5
-
6
- export abstract class BaseProvider<
7
- T extends CreatioClientAuthConfig = CreatioClientAuthConfig,
8
- > implements ICreatioAuthProvider {
9
- protected readonly config: CreatioClientConfig;
10
-
11
- protected get authConfig(): T {
12
- return this.config.auth as T;
13
- }
14
-
15
- public get type(): AuthProviderType {
16
- return this.authConfig.kind;
17
- }
18
-
19
- constructor(config: CreatioClientConfig) {
20
- this.config = config;
21
- }
22
-
23
- public getHeaders(accept: string, isJson?: boolean): Promise<Record<string, string>> {
24
- throw new Error('Method not implemented.');
25
- }
26
-
27
- public refresh(): Promise<void> {
28
- throw new Error('Method not implemented.');
29
- }
30
-
31
- public revoke(): Promise<void> {
32
- throw new Error('Method not implemented.');
33
- }
34
-
35
- public getAuthorizeUrl(state: string): Promise<string> {
36
- throw new Error('Method not implemented.');
37
- }
38
-
39
- public finishAuthorization(code: string): Promise<void> {
40
- throw new Error('Method not implemented.');
41
- }
42
- }
@@ -1,4 +0,0 @@
1
- export * from './legacy-provider';
2
- export * from './oauth2-provider';
3
- export * from './oauth2-code-provider';
4
- export * from './type';
@@ -1,70 +0,0 @@
1
- import log from '../../../log';
2
- import { JSON_ACCEPT } from '../../../types';
3
- import { parseSetCookie } from '../../../utils';
4
- import { LegacyAuthConfig } from '../../client-config';
5
- import { buildHeaders } from '../auth';
6
-
7
- import { BaseProvider } from './base-provider';
8
-
9
- export class LegacyProvider extends BaseProvider<LegacyAuthConfig> {
10
- private _bpmCsrf: string | undefined;
11
-
12
- private _cookieHeader: string | undefined;
13
-
14
- private async _ensureSession() {
15
- if (this._cookieHeader) {
16
- return;
17
- }
18
- const url = `${this.config.baseUrl.replace(/\/$/, '')}/ServiceModel/AuthService.svc/Login`;
19
- const body = JSON.stringify({
20
- UserName: this.authConfig.login,
21
- UserPassword: this.authConfig.password,
22
- });
23
- log.creatioAuthStart(this.config.baseUrl, 'legacy');
24
- const res = await fetch(url, {
25
- method: 'POST',
26
- headers: buildHeaders(JSON_ACCEPT, true),
27
- body,
28
- redirect: 'manual',
29
- });
30
- if (!res.ok) {
31
- const responseText = await res.text().catch(() => '');
32
- log.creatioAuthFailed(this.config.baseUrl, `${res.status} ${responseText}`, 'legacy');
33
- throw new Error(`auth_failed:${res.status} ${responseText}`);
34
- }
35
- log.creatioAuthOk(this.config.baseUrl, 'legacy');
36
- let setCookie: string[] = [];
37
- if (typeof (res.headers as any).getSetCookie === 'function') {
38
- setCookie = (res.headers as any).getSetCookie();
39
- } else if ((res.headers as any).raw && (res.headers as any).raw()['set-cookie']) {
40
- setCookie = (res.headers as any).raw()['set-cookie'];
41
- } else {
42
- setCookie = [];
43
- }
44
- const pairs = parseSetCookie(setCookie);
45
- if (!pairs.length) {
46
- throw new Error('auth_failed:no_set_cookie');
47
- }
48
- this._cookieHeader = pairs.map((c) => `${c.name}=${c.value}`).join('; ');
49
- const csrf = pairs.find((c) => c.name.toUpperCase() === 'BPMCSRF')?.value;
50
- if (csrf) {
51
- this._bpmCsrf = csrf;
52
- }
53
- }
54
-
55
- public async getHeaders(accept: string, isJson?: boolean): Promise<Record<string, string>> {
56
- await this._ensureSession();
57
- const h = buildHeaders(accept, Boolean(isJson));
58
- h['ForceUseSession'] = 'true';
59
- h['Cookie'] = this._cookieHeader!;
60
- if (this._bpmCsrf) {
61
- h['BPMCSRF'] = this._bpmCsrf;
62
- }
63
- return h;
64
- }
65
-
66
- public async refresh(): Promise<void> {
67
- this._cookieHeader = undefined;
68
- await this._ensureSession();
69
- }
70
- }
@@ -1,252 +0,0 @@
1
- import { HTTP_MCP_PORT } from '../../../consts';
2
- import log from '../../../log';
3
- import { SessionContext, TokenRefreshScheduler, type UserTokens } from '../../../services';
4
- import { getEffectiveUserKey, getUserKey } from '../../../utils';
5
- import { CreatioClientConfig, OAuth2CodeAuthConfig } from '../../client-config';
6
- import { AUTHORIZE_ENDPOINT, REVOCATION_ENDPOINT, TOKEN_ENDPOINT } from '../auth';
7
-
8
- import { BaseOAuth2Provider } from './base-oauth2-provider';
9
-
10
- export class OAuth2CodeProvider extends BaseOAuth2Provider<OAuth2CodeAuthConfig> {
11
- private readonly _sessionContext = SessionContext.instance;
12
- private readonly _tokenRefreshScheduler = new TokenRefreshScheduler();
13
-
14
- protected readonly authErrorCode = 'oauth2_code_need_consent';
15
-
16
- private get _scope() {
17
- return this.authConfig.scope || 'offline_access';
18
- }
19
-
20
- constructor(config: CreatioClientConfig) {
21
- super(config);
22
- this._tokenRefreshScheduler.setRefreshCallback(this.refreshUserTokens.bind(this));
23
- }
24
-
25
- private async _exchangeCodeForTokens(code: string): Promise<UserTokens> {
26
- const idBase = this.getIdentityBase();
27
- const url = idBase + TOKEN_ENDPOINT;
28
- const body = new URLSearchParams();
29
- body.set('grant_type', 'authorization_code');
30
- body.set('client_id', this.authConfig.clientId);
31
- if (this.authConfig.clientSecret) {
32
- body.set('client_secret', this.authConfig.clientSecret);
33
- }
34
- body.set('code', code);
35
- body.set('redirect_uri', this.authConfig.redirectUri);
36
- body.set('scope', this._scope);
37
- log.creatioAuthStart(this.config.baseUrl, 'oauth2_code');
38
- const res = await fetch(url, {
39
- method: 'POST',
40
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
41
- body: body.toString(),
42
- });
43
- const txt = await res.text().catch(() => '');
44
- if (!res.ok || !txt) {
45
- log.creatioAuthFailed(this.config.baseUrl, `token:${res.status} ${txt}`, 'oauth2_code');
46
- throw new Error(`oauth2_code_token_error:${res.status}`);
47
- }
48
- let j: any;
49
- try {
50
- j = JSON.parse(txt);
51
- } catch {
52
- log.creatioAuthFailed(this.config.baseUrl, 'token_parse_failed', 'oauth2_code');
53
- throw new Error('oauth2_code_token_parse_failed');
54
- }
55
- if (!j.access_token) {
56
- throw new Error('oauth2_code_no_access_token');
57
- }
58
- const expiresIn = Number(j.expires_in) || 180;
59
- const accessTokenExpiryMs = this.computeExpiryMs(expiresIn, 1);
60
- log.creatioAuthOk(this.config.baseUrl, 'oauth2_code');
61
- return {
62
- accessToken: String(j.access_token),
63
- accessTokenExpiryMs,
64
- refreshToken: j.refresh_token ? String(j.refresh_token) : undefined,
65
- };
66
- }
67
-
68
- private async _refreshTokens(refreshToken: string): Promise<UserTokens> {
69
- const idBase = this.getIdentityBase();
70
- const url = idBase + TOKEN_ENDPOINT;
71
- log.info('oauth2_code.refresh_attempt', { url, refreshTokenLength: refreshToken.length });
72
- const body = new URLSearchParams();
73
- body.set('grant_type', 'refresh_token');
74
- body.set('client_id', this.authConfig.clientId);
75
- if (this.authConfig.clientSecret) {
76
- body.set('client_secret', this.authConfig.clientSecret);
77
- }
78
- body.set('refresh_token', refreshToken);
79
- body.set('redirect_uri', this.authConfig.redirectUri);
80
- body.set('scope', this._scope);
81
- const res = await fetch(url, {
82
- method: 'POST',
83
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
84
- body: body.toString(),
85
- });
86
- const txt = await res.text().catch(() => '');
87
- log.info('oauth2_code.refresh_response', {
88
- status: res.status,
89
- hasBody: !!txt,
90
- bodyLength: txt.length,
91
- });
92
- if (!res.ok || !txt) {
93
- log.error('oauth2_code.refresh_failed', {
94
- status: res.status,
95
- body: txt.substring(0, 200),
96
- });
97
- throw new Error(`oauth2_code_refresh_error:${res.status}`);
98
- }
99
- let j: any;
100
- try {
101
- j = JSON.parse(txt);
102
- } catch {
103
- throw new Error('oauth2_code_refresh_parse_failed');
104
- }
105
- if (!j.access_token) {
106
- throw new Error('oauth2_code_refresh_no_access_token');
107
- }
108
- const expiresIn = Number(j.expires_in) || 180;
109
- const accessTokenExpiryMs = this.computeExpiryMs(expiresIn, 1);
110
- const newTokens = {
111
- accessToken: String(j.access_token),
112
- accessTokenExpiryMs,
113
- refreshToken: j.refresh_token ? String(j.refresh_token) : refreshToken,
114
- };
115
- log.info('oauth2_code.refresh_success', {
116
- hasNewRefreshToken: !!j.refresh_token,
117
- expiresIn,
118
- accessTokenLength: newTokens.accessToken.length,
119
- });
120
- return newTokens;
121
- }
122
-
123
- protected throwNoTokenError(): void {
124
- const userKey = getEffectiveUserKey();
125
- const errorMessage = userKey
126
- ? `${this.authErrorCode}:http://localhost:${HTTP_MCP_PORT}/oauth/start?userKey=${encodeURIComponent(userKey)}`
127
- : this.authErrorCode;
128
- throw new Error(errorMessage);
129
- }
130
-
131
- protected async ensureAccessToken(force = false): Promise<string | undefined> {
132
- log.info('oauth2_code.ensure_access_token.start', { force });
133
- const now = Date.now();
134
- if (
135
- !force &&
136
- this.accessToken &&
137
- this.accessTokenExpiryMs &&
138
- now < this.accessTokenExpiryMs
139
- ) {
140
- return this.accessToken;
141
- }
142
- const userKey = getEffectiveUserKey();
143
- if (!userKey) {
144
- log.warn('oauth2_code.no_user_key');
145
- return undefined;
146
- }
147
- const saved = await this._sessionContext.getTokensForUser(userKey);
148
- if (!saved) {
149
- log.warn('oauth2_code.no_saved_tokens', { userKey });
150
- return undefined;
151
- }
152
- if (
153
- !force &&
154
- saved.accessToken &&
155
- saved.accessTokenExpiryMs &&
156
- now < saved.accessTokenExpiryMs
157
- ) {
158
- this.accessToken = saved.accessToken;
159
- this.accessTokenExpiryMs = saved.accessTokenExpiryMs;
160
- return this.accessToken;
161
- }
162
- if (saved.refreshToken) {
163
- const updated = await this._refreshTokens(saved.refreshToken);
164
- await this._sessionContext.setTokensForUser(userKey, updated);
165
- this.accessToken = updated.accessToken;
166
- this.accessTokenExpiryMs = updated.accessTokenExpiryMs;
167
- return this.accessToken;
168
- }
169
- await this._sessionContext.deleteTokensForUser(userKey);
170
- return undefined;
171
- }
172
-
173
- public async finishAuthorization(code: string): Promise<void> {
174
- const userKey = getEffectiveUserKey();
175
- log.info('oauth2_code.finish_authorization', { userKey, hasCode: !!code });
176
- if (!userKey) {
177
- throw new Error('oauth2_code_missing_user');
178
- }
179
- const tokens = await this._exchangeCodeForTokens(code);
180
- await this._sessionContext.setTokensForUser(userKey, tokens);
181
- this.accessToken = tokens.accessToken;
182
- this.accessTokenExpiryMs = tokens.accessTokenExpiryMs;
183
- this._tokenRefreshScheduler.scheduleRefresh(userKey);
184
- log.info('oauth2_code.authorization_complete', { userKey });
185
- }
186
-
187
- public async getAuthorizeUrl(state: string): Promise<string> {
188
- const idBase = this.getIdentityBase();
189
- const u = new URL(idBase + AUTHORIZE_ENDPOINT);
190
- u.searchParams.set('client_id', this.authConfig.clientId);
191
- u.searchParams.set('redirect_uri', this.authConfig.redirectUri);
192
- u.searchParams.set('response_type', 'code');
193
- u.searchParams.set('state', state);
194
- const scopeParam = encodeURIComponent(this._scope);
195
- u.search += '&scope=' + scopeParam;
196
- log.info('oauth2_code.authorize_url', {
197
- idBase,
198
- url: u.toString(),
199
- });
200
- return u.toString();
201
- }
202
-
203
- public async revoke(): Promise<void> {
204
- try {
205
- const userKey = getUserKey();
206
- if (!userKey) {
207
- return;
208
- }
209
- const saved = await this._sessionContext.getTokensForUser(userKey);
210
- if (!saved?.refreshToken) {
211
- await this._sessionContext.deleteTokensForUser(userKey);
212
- return;
213
- }
214
- const idBase = this.getIdentityBase();
215
- const url = idBase + REVOCATION_ENDPOINT;
216
- const body = new URLSearchParams();
217
- body.set('client_id', this.authConfig.clientId);
218
- if (this.authConfig.clientSecret) {
219
- body.set('client_secret', this.authConfig.clientSecret);
220
- }
221
- body.set('token', saved.refreshToken);
222
- body.set('token_type_hint', 'refresh_token');
223
- const res = await fetch(url, {
224
- method: 'POST',
225
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
226
- body: body.toString(),
227
- });
228
- if (!res.ok) {
229
- const t = await res.text().catch(() => '');
230
- log.error('oauth2_code.revoke_failed', { status: res.status, t });
231
- }
232
- } finally {
233
- const userKey = getUserKey();
234
- if (userKey) {
235
- await this._sessionContext.deleteTokensForUser(userKey);
236
- this._tokenRefreshScheduler.cancelRefresh(userKey);
237
- }
238
- this.accessToken = undefined;
239
- this.accessTokenExpiryMs = undefined;
240
- }
241
- }
242
-
243
- public async refreshUserTokens(userKey: string): Promise<void> {
244
- const saved = await this._sessionContext.getTokensForUser(userKey);
245
- if (!saved?.refreshToken) {
246
- throw new Error('oauth2_no_refresh_token');
247
- }
248
- const updated = await this._refreshTokens(saved.refreshToken);
249
- await this._sessionContext.setTokensForUser(userKey, updated);
250
- log.info('oauth2_code.background_refresh_success', { userKey });
251
- }
252
- }
@@ -1,91 +0,0 @@
1
- import log from '../../../log';
2
- import { CreatioClientConfig, OAuth2AuthConfig } from '../../client-config';
3
- import { TOKEN_BODY_SNIPPET_MAX, TOKEN_ENDPOINT } from '../auth';
4
-
5
- import { BaseOAuth2Provider } from './base-oauth2-provider';
6
-
7
- export class OAuth2Provider extends BaseOAuth2Provider<OAuth2AuthConfig> {
8
- private readonly _config: CreatioClientConfig;
9
-
10
- protected readonly authErrorCode = 'oauth2_auth_failed';
11
-
12
- constructor(config: CreatioClientConfig) {
13
- super(config);
14
- this._config = config;
15
- }
16
-
17
- protected async ensureAccessToken(): Promise<string | undefined> {
18
- const now = Date.now();
19
- if (this.accessToken && this.accessTokenExpiryMs && now < this.accessTokenExpiryMs) {
20
- return this.accessToken;
21
- }
22
- const url = `${this.getIdentityBase()}${TOKEN_ENDPOINT}`;
23
- const body = new URLSearchParams();
24
- body.set('grant_type', 'client_credentials');
25
- body.set('client_id', this.authConfig.clientId);
26
- body.set('client_secret', this.authConfig.clientSecret);
27
- try {
28
- log.creatioAuthStart(this._config.baseUrl, 'oauth2');
29
- const response = await fetch(url, {
30
- method: 'POST',
31
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
32
- body: body.toString(),
33
- });
34
- const responseText = await response.text().catch(() => '');
35
- const contentType = (response.headers as any)?.get?.('content-type') ?? '';
36
- const bodySnippet =
37
- responseText && responseText.length > TOKEN_BODY_SNIPPET_MAX
38
- ? responseText.slice(0, TOKEN_BODY_SNIPPET_MAX) + '\n... [truncated]'
39
- : responseText;
40
- if (!response.ok) {
41
- log.error('oauth.token.error', {
42
- url,
43
- status: response.status,
44
- contentType,
45
- bodySnippet,
46
- });
47
- log.creatioAuthFailed(
48
- this._config.baseUrl,
49
- `token_error:${response.status}`,
50
- 'oauth2',
51
- );
52
- throw new Error(`oauth2_token_error:${response.status}`);
53
- }
54
- if (!responseText) {
55
- log.error('oauth.token.empty_body', { url, status: response.status, contentType });
56
- log.creatioAuthFailed(this._config.baseUrl, 'empty_response_body', 'oauth2');
57
- throw new Error('oauth2_empty_token_response');
58
- }
59
- let tokenResponse: any = null;
60
- try {
61
- tokenResponse = JSON.parse(responseText);
62
- } catch (err) {
63
- log.error('oauth.token.parse_failed', {
64
- url,
65
- status: response.status,
66
- contentType,
67
- bodySnippet,
68
- });
69
- log.creatioAuthFailed(this._config.baseUrl, 'token_parse_failed', 'oauth2');
70
- throw new Error('oauth2_token_parse_failed');
71
- }
72
- if (!tokenResponse || !tokenResponse.access_token) {
73
- log.creatioAuthFailed(
74
- this._config.baseUrl,
75
- 'no_access_token_in_response',
76
- 'oauth2',
77
- );
78
- throw new Error('oauth2_no_access_token');
79
- }
80
- this.accessToken = String(tokenResponse.access_token);
81
- const expiresIn = Number(tokenResponse.expires_in) || 3600;
82
- this.accessTokenExpiryMs = this.computeExpiryMs(expiresIn, 1);
83
- log.creatioAuthOk(this._config.baseUrl, 'oauth2');
84
- return this.accessToken;
85
- } catch (e: any) {
86
- log.error('oauth.token.exception', { error: String(e?.message ?? e) });
87
- log.creatioAuthFailed(this._config.baseUrl, String(e?.message ?? e), 'oauth2');
88
- return undefined;
89
- }
90
- }
91
- }
@@ -1,5 +0,0 @@
1
- export enum AuthProviderType {
2
- Legacy = 'legacy',
3
- OAuth2 = 'oauth2',
4
- OAuth2Code = 'oauth2_code',
5
- }
@@ -1,34 +0,0 @@
1
- import { AuthProviderType } from './auth/providers';
2
-
3
- interface ICreatioAuthConfig {
4
- kind: AuthProviderType;
5
- }
6
-
7
- export interface LegacyAuthConfig extends ICreatioAuthConfig {
8
- kind: AuthProviderType.Legacy;
9
- login: string;
10
- password: string;
11
- }
12
-
13
- interface BaseOAuthConfig extends ICreatioAuthConfig {
14
- clientId: string;
15
- clientSecret: string;
16
- scope?: string;
17
- idBaseUrl?: string;
18
- }
19
-
20
- export interface OAuth2AuthConfig extends BaseOAuthConfig {
21
- kind: AuthProviderType.OAuth2;
22
- }
23
-
24
- export interface OAuth2CodeAuthConfig extends BaseOAuthConfig {
25
- kind: AuthProviderType.OAuth2Code;
26
- redirectUri: string;
27
- }
28
-
29
- export type CreatioClientAuthConfig = LegacyAuthConfig | OAuth2AuthConfig | OAuth2CodeAuthConfig;
30
-
31
- export interface CreatioClientConfig {
32
- baseUrl: string;
33
- auth: CreatioClientAuthConfig;
34
- }
@@ -1,44 +0,0 @@
1
- import {
2
- AdminOperationProvider,
3
- AdminOperationServiceResult,
4
- SetAdminOperationGranteeRequest,
5
- UpsertAdminOperationRequest,
6
- UpsertAdminOperationResult,
7
- } from '../../providers';
8
- import { CreatioEngine } from '../engine';
9
-
10
- export class AdminOperationEngine implements CreatioEngine {
11
- private readonly _provider: AdminOperationProvider;
12
-
13
- public readonly name = 'admin-operation';
14
-
15
- constructor(provider: AdminOperationProvider) {
16
- this._provider = provider;
17
- }
18
-
19
- public get kind(): string {
20
- return this._provider.kind;
21
- }
22
-
23
- public upsertAdminOperation(
24
- request: UpsertAdminOperationRequest,
25
- ): Promise<UpsertAdminOperationResult> {
26
- return this._provider.upsertAdminOperation(request);
27
- }
28
-
29
- public deleteAdminOperation(recordIds: string[]): Promise<AdminOperationServiceResult> {
30
- return this._provider.deleteAdminOperation(recordIds);
31
- }
32
-
33
- public setAdminOperationGrantee(
34
- request: SetAdminOperationGranteeRequest,
35
- ): Promise<AdminOperationServiceResult> {
36
- return this._provider.setAdminOperationGrantee(request);
37
- }
38
-
39
- public deleteAdminOperationGrantee(
40
- recordIds: string[],
41
- ): Promise<AdminOperationServiceResult> {
42
- return this._provider.deleteAdminOperationGrantee(recordIds);
43
- }
44
- }
@@ -1,26 +0,0 @@
1
- import {
2
- CallConfigurationServiceRequest,
3
- CallConfigurationServiceResult,
4
- ConfigurationProvider,
5
- } from '../../providers';
6
- import { CreatioEngine } from '../engine';
7
-
8
- export class ConfigurationEngine implements CreatioEngine {
9
- private readonly _provider: ConfigurationProvider;
10
-
11
- public readonly name = 'configuration';
12
-
13
- constructor(provider: ConfigurationProvider) {
14
- this._provider = provider;
15
- }
16
-
17
- public get kind(): string {
18
- return this._provider.kind;
19
- }
20
-
21
- public call(
22
- request: CallConfigurationServiceRequest,
23
- ): Promise<CallConfigurationServiceResult> {
24
- return this._provider.call(request);
25
- }
26
- }
@@ -1,47 +0,0 @@
1
- import {
2
- CrudDeleteParams,
3
- CrudProvider,
4
- CrudReadParams,
5
- CrudUpdateParams,
6
- CrudWriteParams,
7
- EntitySchemaDescription,
8
- } from '../../providers';
9
- import { CreatioEngine } from '../engine';
10
-
11
- export class CrudEngine implements CreatioEngine {
12
- private readonly _provider: CrudProvider;
13
-
14
- public readonly name = 'crud';
15
-
16
- constructor(provider: CrudProvider) {
17
- this._provider = provider;
18
- }
19
-
20
- public get kind(): string {
21
- return this._provider.kind;
22
- }
23
-
24
- public listEntitySets(): Promise<string[]> {
25
- return this._provider.listEntitySets();
26
- }
27
-
28
- public describeEntity(entitySet: string): Promise<EntitySchemaDescription> {
29
- return this._provider.describeEntity(entitySet);
30
- }
31
-
32
- public read(params: CrudReadParams): Promise<any> {
33
- return this._provider.read(params);
34
- }
35
-
36
- public create(params: CrudWriteParams): Promise<any> {
37
- return this._provider.create(params);
38
- }
39
-
40
- public update(params: CrudUpdateParams): Promise<any> {
41
- return this._provider.update(params);
42
- }
43
-
44
- public delete(params: CrudDeleteParams): Promise<any> {
45
- return this._provider.delete(params);
46
- }
47
- }