@superblocksteam/shared 0.9607.2 → 0.9608.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.
- package/dist/database-lifecycle/appDatabaseCompatibility.d.ts +49 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.d.ts.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.js +32 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.js.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.d.ts +2 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.d.ts.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.js +47 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.js.map +1 -0
- package/dist/database-lifecycle/destructiveMigrations.d.ts +12 -0
- package/dist/database-lifecycle/destructiveMigrations.d.ts.map +1 -1
- package/dist/database-lifecycle/destructiveMigrations.js +114 -0
- package/dist/database-lifecycle/destructiveMigrations.js.map +1 -1
- package/dist/database-lifecycle/destructiveMigrations.test.js +79 -0
- package/dist/database-lifecycle/destructiveMigrations.test.js.map +1 -1
- package/dist/database-lifecycle/index.d.ts +46 -2
- package/dist/database-lifecycle/index.d.ts.map +1 -1
- package/dist/database-lifecycle/index.js +127 -1
- package/dist/database-lifecycle/index.js.map +1 -1
- package/dist/database-lifecycle/providerDiagnostics.test.d.ts +2 -0
- package/dist/database-lifecycle/providerDiagnostics.test.d.ts.map +1 -0
- package/dist/database-lifecycle/providerDiagnostics.test.js +119 -0
- package/dist/database-lifecycle/providerDiagnostics.test.js.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.d.ts +65 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.d.ts.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.js +87 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.js.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.d.ts +2 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.d.ts.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.js +285 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.js.map +1 -0
- package/dist/errors/http.d.ts +15 -4
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +25 -7
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/http.test.d.ts +2 -0
- package/dist/errors/http.test.d.ts.map +1 -0
- package/dist/errors/http.test.js +28 -0
- package/dist/errors/http.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/templates/restApiIntegration.d.ts.map +1 -1
- package/dist/plugins/templates/restApiIntegration.js +2 -0
- package/dist/plugins/templates/restApiIntegration.js.map +1 -1
- package/dist/plugins/templates/shared/auth.d.ts +3 -1
- package/dist/plugins/templates/shared/auth.d.ts.map +1 -1
- package/dist/plugins/templates/shared/auth.js +129 -17
- package/dist/plugins/templates/shared/auth.js.map +1 -1
- package/dist/plugins/templates/shared/auth.test.d.ts +2 -0
- package/dist/plugins/templates/shared/auth.test.d.ts.map +1 -0
- package/dist/plugins/templates/shared/auth.test.js +116 -0
- package/dist/plugins/templates/shared/auth.test.js.map +1 -0
- package/dist/plugins/templates/shared/restapiintegration.d.ts +2 -0
- package/dist/plugins/templates/shared/restapiintegration.d.ts.map +1 -1
- package/dist/plugins/templates/shared/restapiintegration.js +3 -1
- package/dist/plugins/templates/shared/restapiintegration.js.map +1 -1
- package/dist/socket/dist-entry.test.d.ts +2 -0
- package/dist/socket/dist-entry.test.d.ts.map +1 -0
- package/dist/socket/dist-entry.test.js +34 -0
- package/dist/socket/dist-entry.test.js.map +1 -0
- package/dist/socket/heartbeat.d.ts +258 -0
- package/dist/socket/heartbeat.d.ts.map +1 -0
- package/dist/socket/heartbeat.js +307 -0
- package/dist/socket/heartbeat.js.map +1 -0
- package/dist/socket/heartbeat.test.d.ts +2 -0
- package/dist/socket/heartbeat.test.d.ts.map +1 -0
- package/dist/socket/heartbeat.test.js +431 -0
- package/dist/socket/heartbeat.test.js.map +1 -0
- package/dist/socket/index.d.ts +1 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +1 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/socket/util.d.ts.map +1 -1
- package/dist/socket/util.js +15 -1
- package/dist/socket/util.js.map +1 -1
- package/dist/socket/util.test.js +12 -2
- package/dist/socket/util.test.js.map +1 -1
- package/dist/types/ai/index.d.ts +3 -0
- package/dist/types/ai/index.d.ts.map +1 -1
- package/dist/types/ai/index.js +3 -0
- package/dist/types/ai/index.js.map +1 -1
- package/dist/types/application/index.d.ts +12 -0
- package/dist/types/application/index.d.ts.map +1 -1
- package/dist/types/application/index.js.map +1 -1
- package/dist/types/codeSecurity/index.d.ts +55 -1
- package/dist/types/codeSecurity/index.d.ts.map +1 -1
- package/dist/types/codeSecurity/index.js +21 -1
- package/dist/types/codeSecurity/index.js.map +1 -1
- package/dist/types/codeSecurity/index.test.d.ts +2 -0
- package/dist/types/codeSecurity/index.test.d.ts.map +1 -0
- package/dist/types/codeSecurity/index.test.js +19 -0
- package/dist/types/codeSecurity/index.test.js.map +1 -0
- package/dist/types/datasource/auth.d.ts +12 -1
- package/dist/types/datasource/auth.d.ts.map +1 -1
- package/dist/types/datasource/auth.js +20 -2
- package/dist/types/datasource/auth.js.map +1 -1
- package/dist/types/datasource/auth.test.js +3 -1
- package/dist/types/datasource/auth.test.js.map +1 -1
- package/dist/types/group/index.d.ts +1 -3
- package/dist/types/group/index.d.ts.map +1 -1
- package/dist/types/group/index.js +1 -3
- package/dist/types/group/index.js.map +1 -1
- package/dist/types/integration/index.d.ts +11 -1
- package/dist/types/integration/index.d.ts.map +1 -1
- package/dist/types/integration/index.js +11 -1
- package/dist/types/integration/index.js.map +1 -1
- package/dist/types/plugin/form.d.ts +32 -0
- package/dist/types/plugin/form.d.ts.map +1 -1
- package/dist/types/plugin/form.js +73 -1
- package/dist/types/plugin/form.js.map +1 -1
- package/dist/types/plugin/form.test.js +128 -0
- package/dist/types/plugin/form.test.js.map +1 -1
- package/dist/types/profile/index.d.ts +16 -1
- package/dist/types/profile/index.d.ts.map +1 -1
- package/dist/types/profile/index.js +7 -1
- package/dist/types/profile/index.js.map +1 -1
- package/dist/types/rbac/index.d.ts +2 -0
- package/dist/types/rbac/index.d.ts.map +1 -1
- package/dist/types/rbac/index.js +2 -0
- package/dist/types/rbac/index.js.map +1 -1
- package/dist/types/response/GetRecentApplicationsResponseBody.d.ts +4 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.d.ts.map +1 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.js +3 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.js.map +1 -0
- package/dist/types/response/index.d.ts +1 -0
- package/dist/types/response/index.d.ts.map +1 -1
- package/dist/types/response/index.js +1 -0
- package/dist/types/response/index.js.map +1 -1
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.d.ts +49 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.js +28 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.js.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.d.ts +2 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.js +45 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.js.map +1 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts +12 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.js +113 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.js.map +1 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js +80 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js.map +1 -1
- package/dist-esm/database-lifecycle/index.d.ts +46 -2
- package/dist-esm/database-lifecycle/index.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/index.js +123 -1
- package/dist-esm/database-lifecycle/index.js.map +1 -1
- package/dist-esm/database-lifecycle/providerDiagnostics.test.d.ts +2 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.js +117 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.js.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.d.ts +65 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.d.ts.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.js +79 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.js.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.d.ts +2 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.d.ts.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.js +283 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.js.map +1 -0
- package/dist-esm/errors/http.d.ts +15 -4
- package/dist-esm/errors/http.d.ts.map +1 -1
- package/dist-esm/errors/http.js +22 -6
- package/dist-esm/errors/http.js.map +1 -1
- package/dist-esm/errors/http.test.d.ts +2 -0
- package/dist-esm/errors/http.test.d.ts.map +1 -0
- package/dist-esm/errors/http.test.js +26 -0
- package/dist-esm/errors/http.test.js.map +1 -0
- package/dist-esm/index.d.ts +2 -0
- package/dist-esm/index.d.ts.map +1 -1
- package/dist-esm/index.js +2 -0
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/plugins/templates/restApiIntegration.d.ts.map +1 -1
- package/dist-esm/plugins/templates/restApiIntegration.js +2 -0
- package/dist-esm/plugins/templates/restApiIntegration.js.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.d.ts +3 -1
- package/dist-esm/plugins/templates/shared/auth.d.ts.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.js +129 -17
- package/dist-esm/plugins/templates/shared/auth.js.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.test.d.ts +2 -0
- package/dist-esm/plugins/templates/shared/auth.test.d.ts.map +1 -0
- package/dist-esm/plugins/templates/shared/auth.test.js +114 -0
- package/dist-esm/plugins/templates/shared/auth.test.js.map +1 -0
- package/dist-esm/plugins/templates/shared/restapiintegration.d.ts +2 -0
- package/dist-esm/plugins/templates/shared/restapiintegration.d.ts.map +1 -1
- package/dist-esm/plugins/templates/shared/restapiintegration.js +3 -1
- package/dist-esm/plugins/templates/shared/restapiintegration.js.map +1 -1
- package/dist-esm/socket/dist-entry.test.d.ts +2 -0
- package/dist-esm/socket/dist-entry.test.d.ts.map +1 -0
- package/dist-esm/socket/dist-entry.test.js +29 -0
- package/dist-esm/socket/dist-entry.test.js.map +1 -0
- package/dist-esm/socket/heartbeat.d.ts +258 -0
- package/dist-esm/socket/heartbeat.d.ts.map +1 -0
- package/dist-esm/socket/heartbeat.js +303 -0
- package/dist-esm/socket/heartbeat.js.map +1 -0
- package/dist-esm/socket/heartbeat.test.d.ts +2 -0
- package/dist-esm/socket/heartbeat.test.d.ts.map +1 -0
- package/dist-esm/socket/heartbeat.test.js +429 -0
- package/dist-esm/socket/heartbeat.test.js.map +1 -0
- package/dist-esm/socket/index.d.ts +1 -0
- package/dist-esm/socket/index.d.ts.map +1 -1
- package/dist-esm/socket/index.js +1 -0
- package/dist-esm/socket/index.js.map +1 -1
- package/dist-esm/socket/util.d.ts.map +1 -1
- package/dist-esm/socket/util.js +15 -1
- package/dist-esm/socket/util.js.map +1 -1
- package/dist-esm/socket/util.test.js +12 -2
- package/dist-esm/socket/util.test.js.map +1 -1
- package/dist-esm/types/ai/index.d.ts +3 -0
- package/dist-esm/types/ai/index.d.ts.map +1 -1
- package/dist-esm/types/ai/index.js +3 -0
- package/dist-esm/types/ai/index.js.map +1 -1
- package/dist-esm/types/application/index.d.ts +12 -0
- package/dist-esm/types/application/index.d.ts.map +1 -1
- package/dist-esm/types/application/index.js.map +1 -1
- package/dist-esm/types/codeSecurity/index.d.ts +55 -1
- package/dist-esm/types/codeSecurity/index.d.ts.map +1 -1
- package/dist-esm/types/codeSecurity/index.js +17 -1
- package/dist-esm/types/codeSecurity/index.js.map +1 -1
- package/dist-esm/types/codeSecurity/index.test.d.ts +2 -0
- package/dist-esm/types/codeSecurity/index.test.d.ts.map +1 -0
- package/dist-esm/types/codeSecurity/index.test.js +17 -0
- package/dist-esm/types/codeSecurity/index.test.js.map +1 -0
- package/dist-esm/types/datasource/auth.d.ts +12 -1
- package/dist-esm/types/datasource/auth.d.ts.map +1 -1
- package/dist-esm/types/datasource/auth.js +19 -2
- package/dist-esm/types/datasource/auth.js.map +1 -1
- package/dist-esm/types/datasource/auth.test.js +3 -1
- package/dist-esm/types/datasource/auth.test.js.map +1 -1
- package/dist-esm/types/group/index.d.ts +1 -3
- package/dist-esm/types/group/index.d.ts.map +1 -1
- package/dist-esm/types/group/index.js +1 -3
- package/dist-esm/types/group/index.js.map +1 -1
- package/dist-esm/types/integration/index.d.ts +11 -1
- package/dist-esm/types/integration/index.d.ts.map +1 -1
- package/dist-esm/types/integration/index.js +11 -1
- package/dist-esm/types/integration/index.js.map +1 -1
- package/dist-esm/types/plugin/form.d.ts +32 -0
- package/dist-esm/types/plugin/form.d.ts.map +1 -1
- package/dist-esm/types/plugin/form.js +68 -0
- package/dist-esm/types/plugin/form.js.map +1 -1
- package/dist-esm/types/plugin/form.test.js +129 -1
- package/dist-esm/types/plugin/form.test.js.map +1 -1
- package/dist-esm/types/profile/index.d.ts +16 -1
- package/dist-esm/types/profile/index.d.ts.map +1 -1
- package/dist-esm/types/profile/index.js +7 -1
- package/dist-esm/types/profile/index.js.map +1 -1
- package/dist-esm/types/rbac/index.d.ts +2 -0
- package/dist-esm/types/rbac/index.d.ts.map +1 -1
- package/dist-esm/types/rbac/index.js +2 -0
- package/dist-esm/types/rbac/index.js.map +1 -1
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.d.ts +4 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.d.ts.map +1 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.js +2 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.js.map +1 -0
- package/dist-esm/types/response/index.d.ts +1 -0
- package/dist-esm/types/response/index.d.ts.map +1 -1
- package/dist-esm/types/response/index.js +1 -0
- package/dist-esm/types/response/index.js.map +1 -1
- package/package.json +1 -1
- package/src/database-lifecycle/appDatabaseCompatibility.test.ts +55 -0
- package/src/database-lifecycle/appDatabaseCompatibility.ts +62 -0
- package/src/database-lifecycle/destructiveMigrations.test.ts +108 -1
- package/src/database-lifecycle/destructiveMigrations.ts +129 -0
- package/src/database-lifecycle/index.ts +173 -0
- package/src/database-lifecycle/providerDiagnostics.test.ts +134 -0
- package/src/environment-compatibility/appEnvironmentCompatibility.test.ts +326 -0
- package/src/environment-compatibility/appEnvironmentCompatibility.ts +173 -0
- package/src/errors/http.test.ts +32 -0
- package/src/errors/http.ts +24 -6
- package/src/index.ts +2 -0
- package/src/plugins/templates/restApiIntegration.ts +2 -0
- package/src/plugins/templates/shared/auth.test.ts +162 -0
- package/src/plugins/templates/shared/auth.ts +135 -18
- package/src/plugins/templates/shared/restapiintegration.ts +3 -1
- package/src/socket/dist-entry.test.ts +29 -0
- package/src/socket/heartbeat.test.ts +538 -0
- package/src/socket/heartbeat.ts +469 -0
- package/src/socket/index.ts +1 -0
- package/src/socket/util.test.ts +14 -2
- package/src/socket/util.ts +15 -1
- package/src/types/ai/index.ts +3 -0
- package/src/types/application/index.ts +14 -0
- package/src/types/codeSecurity/index.test.ts +21 -0
- package/src/types/codeSecurity/index.ts +83 -1
- package/src/types/datasource/auth.test.ts +3 -1
- package/src/types/datasource/auth.ts +24 -3
- package/src/types/group/index.ts +1 -3
- package/src/types/integration/index.ts +14 -0
- package/src/types/plugin/form.test.ts +174 -1
- package/src/types/plugin/form.ts +100 -2
- package/src/types/profile/index.ts +19 -1
- package/src/types/rbac/index.ts +2 -0
- package/src/types/response/GetRecentApplicationsResponseBody.ts +4 -0
- package/src/types/response/index.ts +1 -0
package/src/errors/http.ts
CHANGED
|
@@ -10,6 +10,18 @@ export class HttpError extends Error {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* An upstream failure that may resolve on its own, so the caller is invited to try again.
|
|
15
|
+
* `retryAfterSeconds` is surfaced to HTTP clients as the Retry-After response header.
|
|
16
|
+
*/
|
|
17
|
+
export abstract class RetryableHttpError extends HttpError {
|
|
18
|
+
retryAfterSeconds?: number;
|
|
19
|
+
constructor(status: number, message: string, title: string, retryAfterSeconds?: number) {
|
|
20
|
+
super(status, message, title);
|
|
21
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export class BadRequestError extends HttpError {
|
|
14
26
|
constructor(message: string) {
|
|
15
27
|
super(400, message, 'Bad request');
|
|
@@ -53,9 +65,9 @@ export class NotImplementedError extends HttpError {
|
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
|
|
56
|
-
export class BadGatewayError extends
|
|
57
|
-
constructor(message: string) {
|
|
58
|
-
super(502, message, 'Bad gateway');
|
|
68
|
+
export class BadGatewayError extends RetryableHttpError {
|
|
69
|
+
constructor(message: string, retryAfterSeconds?: number) {
|
|
70
|
+
super(502, message, 'Bad gateway', retryAfterSeconds);
|
|
59
71
|
}
|
|
60
72
|
}
|
|
61
73
|
|
|
@@ -96,9 +108,15 @@ export class FailedDependencyError extends HttpError {
|
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
export class ServiceUnavailableError extends
|
|
100
|
-
constructor(message?: string) {
|
|
101
|
-
super(503, message || 'Service Unavailable', 'Service Unavailable');
|
|
111
|
+
export class ServiceUnavailableError extends RetryableHttpError {
|
|
112
|
+
constructor(message?: string, retryAfterSeconds?: number) {
|
|
113
|
+
super(503, message || 'Service Unavailable', 'Service Unavailable', retryAfterSeconds);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class GatewayTimeoutError extends RetryableHttpError {
|
|
118
|
+
constructor(message?: string, retryAfterSeconds?: number) {
|
|
119
|
+
super(504, message || 'Gateway timeout', 'Gateway timeout', retryAfterSeconds);
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
|
package/src/index.ts
CHANGED
|
@@ -27,4 +27,6 @@ export * from './tracing/errorSanitizer.js';
|
|
|
27
27
|
export * from './jwt/index.js';
|
|
28
28
|
export * from './org-features/index.js';
|
|
29
29
|
export * from './database-lifecycle/index.js';
|
|
30
|
+
export * from './database-lifecycle/appDatabaseCompatibility.js';
|
|
30
31
|
export * from './database-lifecycle/edit-lifecycle-capability.js';
|
|
32
|
+
export * from './environment-compatibility/appEnvironmentCompatibility.js';
|
|
@@ -67,6 +67,8 @@ export const RestApiIntegrationPlugin: Plugin = {
|
|
|
67
67
|
},
|
|
68
68
|
...authSections({
|
|
69
69
|
startVersion: RestApiIntegrationPluginVersions.V1,
|
|
70
|
+
pkceStartVersion: RestApiIntegrationPluginVersions.V16,
|
|
71
|
+
confidentialPkceStartVersion: RestApiIntegrationPluginVersions.V17,
|
|
70
72
|
pluginId: ExtendedIntegrationPluginId.REST_API,
|
|
71
73
|
pluginName: 'REST API',
|
|
72
74
|
enabledMethods: {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ExtendedIntegrationPluginId,
|
|
5
|
+
FormComponentType,
|
|
6
|
+
FormItem,
|
|
7
|
+
getDisplayName,
|
|
8
|
+
getRowItemsFromSectionItem,
|
|
9
|
+
IntegrationAuthType
|
|
10
|
+
} from '../../../types/index.js';
|
|
11
|
+
import { authSections } from './auth.js';
|
|
12
|
+
|
|
13
|
+
const buildAuthFields = (pkceStartVersion?: string, confidentialPkceStartVersion?: string): FormItem[] =>
|
|
14
|
+
authSections({
|
|
15
|
+
startVersion: '0.0.1',
|
|
16
|
+
pkceStartVersion,
|
|
17
|
+
confidentialPkceStartVersion,
|
|
18
|
+
pluginId: ExtendedIntegrationPluginId.REST_API,
|
|
19
|
+
pluginName: 'REST API',
|
|
20
|
+
// Matches the REST API integration, the only plugin that offers PKCE.
|
|
21
|
+
enabledMethods: { basic: true, firebase: true, oauth: true, bearer: true, apiKey: true }
|
|
22
|
+
}).flatMap((section) => section.items.flatMap((item) => getRowItemsFromSectionItem(item)));
|
|
23
|
+
|
|
24
|
+
const findOrdinaryClientSecret = (fields: FormItem[]): FormItem | undefined =>
|
|
25
|
+
fields.find(
|
|
26
|
+
(field) =>
|
|
27
|
+
field.name === 'authConfig.clientSecret' &&
|
|
28
|
+
field.display?.show?.authType?.includes(IntegrationAuthType.OAUTH2_CODE) &&
|
|
29
|
+
field.display.show['authConfig.usePkce']?.includes('false')
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
describe('PKCE display conditions', () => {
|
|
33
|
+
test('shows the client secret for every way the PKCE marker can be unset', () => {
|
|
34
|
+
const show = findOrdinaryClientSecret(buildAuthFields('0.0.16'))?.display?.show;
|
|
35
|
+
|
|
36
|
+
// `display.show` compares String(value), so each of these is a form value
|
|
37
|
+
// that means "PKCE is off" and must keep the field visible.
|
|
38
|
+
expect(show?.['authConfig.usePkce']).toEqual(expect.arrayContaining(['', '0', 'false', 'null', 'undefined']));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('shows an optional client secret directly after the client ID for confidential PKCE clients', () => {
|
|
42
|
+
const publicFields = buildAuthFields('0.0.16');
|
|
43
|
+
const fields = buildAuthFields('0.0.16', '0.0.17');
|
|
44
|
+
const clientIdIndex = fields.findIndex(
|
|
45
|
+
(field) => field.name === 'authConfig.clientId' && field.display?.show?.authType?.includes(IntegrationAuthType.OAUTH2_CODE)
|
|
46
|
+
);
|
|
47
|
+
const clientSecretIndex = fields.findIndex(
|
|
48
|
+
(field) => field.name === 'authConfig.clientSecret' && !field.hidden && field.display?.show?.['authConfig.usePkce']?.includes('true')
|
|
49
|
+
);
|
|
50
|
+
const clientSecret = fields[clientSecretIndex];
|
|
51
|
+
const clientAuthMethod = fields.find(
|
|
52
|
+
(field) =>
|
|
53
|
+
field.name === 'authConfig.clientAuthMethod' && !field.hidden && field.display?.show?.['authConfig.usePkce']?.includes('true')
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
publicFields.find(
|
|
58
|
+
(field) =>
|
|
59
|
+
field.name === 'authConfig.clientSecret' && !field.hidden && field.display?.show?.['authConfig.usePkce']?.includes('true')
|
|
60
|
+
)
|
|
61
|
+
).toBeUndefined();
|
|
62
|
+
expect(clientSecretIndex).toBe(clientIdIndex + 1);
|
|
63
|
+
expect(clientSecret?.startVersion).toBe('0.0.17');
|
|
64
|
+
expect(clientSecret?.rules).toEqual([{ required: false }]);
|
|
65
|
+
expect(clientSecret?.tooltip).toEqual({
|
|
66
|
+
markdownText: 'Only required for confidential OAuth clients.'
|
|
67
|
+
});
|
|
68
|
+
expect(fields.some((field) => field.name === 'authConfig.usePkceClientSecret')).toBe(false);
|
|
69
|
+
expect(clientAuthMethod?.display?.show?.['authConfig.usePkce']).toEqual(['1', 'true']);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('leaves the condition off plugins that do not offer PKCE', () => {
|
|
73
|
+
const clientSecret = buildAuthFields().find(
|
|
74
|
+
(field) => field.name === 'authConfig.clientSecret' && field.display?.show?.authType?.includes(IntegrationAuthType.OAUTH2_CODE)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(clientSecret?.display?.show).toBeDefined();
|
|
78
|
+
expect(clientSecret?.display?.show?.['authConfig.usePkce']).toBeUndefined();
|
|
79
|
+
expect(clientSecret?.rules).toEqual([{ required: true, message: 'Client secret is required' }]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('PKCE field clearing', () => {
|
|
84
|
+
test('leaves client credential fields clearable so switching auth type still empties them', () => {
|
|
85
|
+
// cleanFormData skips any item marked doNotClearOnDependenciesChange, so a
|
|
86
|
+
// marked field survives every dependency change, including switching the
|
|
87
|
+
// auth type to Basic or None. That leaked authConfig.clientAuthMethod into
|
|
88
|
+
// payloads that should not have an authConfig at all. Keeping the value
|
|
89
|
+
// across PKCE toggles is done with the hidden preservation items below
|
|
90
|
+
// instead.
|
|
91
|
+
const fields = buildAuthFields('0.0.16', '0.0.17');
|
|
92
|
+
|
|
93
|
+
for (const name of ['authConfig.clientSecret', 'authConfig.clientAuthMethod']) {
|
|
94
|
+
const items = fields.filter((field) => field.name === name);
|
|
95
|
+
expect(items.length).toBeGreaterThan(0);
|
|
96
|
+
for (const item of items) {
|
|
97
|
+
expect(item.doNotClearOnDependenciesChange).toBeUndefined();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('keeps confidential credentials when only public PKCE is supported', () => {
|
|
103
|
+
const fields = buildAuthFields('0.0.16', '0.0.17');
|
|
104
|
+
|
|
105
|
+
for (const name of ['authConfig.clientSecret', 'authConfig.clientAuthMethod']) {
|
|
106
|
+
const preservation = fields.find(
|
|
107
|
+
(field) =>
|
|
108
|
+
field.name === name &&
|
|
109
|
+
field.startVersion === '0.0.16' &&
|
|
110
|
+
field.hidden === true &&
|
|
111
|
+
field.display?.show?.['authConfig.usePkce']?.includes('true')
|
|
112
|
+
);
|
|
113
|
+
expect(preservation, name).toBeDefined();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('PKCE dropdown option', () => {
|
|
119
|
+
test('labels itself off the ordinary authorization code option', () => {
|
|
120
|
+
const authTypeField = buildAuthFields('0.0.16').find((field) => field.name === 'authType');
|
|
121
|
+
const options = 'options' in authTypeField! ? authTypeField.options : [];
|
|
122
|
+
const pkceOption = options.find((option) => option.key === `${IntegrationAuthType.OAUTH2_CODE}-pkce`);
|
|
123
|
+
|
|
124
|
+
// Naming it by hand let it drift to "OAuth2.0" while every sibling said
|
|
125
|
+
// "OAuth2".
|
|
126
|
+
expect(pkceOption?.displayName).toBe(`${getDisplayName(IntegrationAuthType.OAUTH2_CODE)} (with PKCE)`);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('OAuth connect button', () => {
|
|
131
|
+
test('sends the PKCE marker along with the rest of the auth config', () => {
|
|
132
|
+
// No shipped plugin has both the connect button and PKCE today: the button
|
|
133
|
+
// needs oauth2BringYourOwn or oauth2SuperblocksClient, and PKCE is REST API
|
|
134
|
+
// only. Build a plugin with both so the forwarding contract is pinned down
|
|
135
|
+
// before some plugin ends up in that combination.
|
|
136
|
+
const fields = authSections({
|
|
137
|
+
startVersion: '0.0.1',
|
|
138
|
+
pkceStartVersion: '0.0.16',
|
|
139
|
+
pluginId: ExtendedIntegrationPluginId.REST_API,
|
|
140
|
+
pluginName: 'REST API',
|
|
141
|
+
enabledMethods: {
|
|
142
|
+
oauth: true,
|
|
143
|
+
oauth2BringYourOwn: {
|
|
144
|
+
tokenUrl: 'https://provider.example.com/token',
|
|
145
|
+
authorizationUrl: 'https://provider.example.com/authorize',
|
|
146
|
+
revokeTokenUrl: 'https://provider.example.com/revoke',
|
|
147
|
+
iconUrl: 'https://provider.example.com/icon.png'
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}).flatMap((section) => section.items.flatMap((item) => getRowItemsFromSectionItem(item)));
|
|
151
|
+
|
|
152
|
+
const forwardedValues = fields.flatMap((field) =>
|
|
153
|
+
field.name === 'oauth-connect-button' && field.componentType === FormComponentType.BUTTON ? (field.valuesFromContext ?? []) : []
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// The button forwards exactly these form values to the connect saga, and
|
|
157
|
+
// the saga decides whether to run PKCE from the marker. Leave it out and
|
|
158
|
+
// the saga can never see PKCE as enabled.
|
|
159
|
+
expect(forwardedValues).toContain('authConfig.usePkce');
|
|
160
|
+
expect(forwardedValues).not.toContain('authConfig.usePkceClientSecret');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -84,6 +84,26 @@ type OAuth2Config = {
|
|
|
84
84
|
|
|
85
85
|
type OAuth2HostedClientConfig = OAuth2Config & { clientId: string };
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Every value `authConfig.usePkce` can hold while PKCE is off. `display.show`
|
|
89
|
+
* matches on the stringified form value, so a spelling missing from this list
|
|
90
|
+
* hides the field it guards instead of showing it.
|
|
91
|
+
*/
|
|
92
|
+
const PKCE_OFF_MARKERS = ['', '0', 'false', 'null', 'undefined'];
|
|
93
|
+
const PKCE_ON_MARKERS = ['1', 'true'];
|
|
94
|
+
const CLIENT_AUTH_METHOD_OPTIONS: DropdownOption[] = [
|
|
95
|
+
{
|
|
96
|
+
displayName: 'Send client credentials in body',
|
|
97
|
+
key: ClientAuthMethod.POST,
|
|
98
|
+
value: ClientAuthMethod.POST
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
displayName: 'Send as Basic Auth header',
|
|
102
|
+
key: ClientAuthMethod.BASIC,
|
|
103
|
+
value: ClientAuthMethod.BASIC
|
|
104
|
+
}
|
|
105
|
+
];
|
|
106
|
+
|
|
87
107
|
const AUTH_METHODS_TO_TYPES = {
|
|
88
108
|
basic: IntegrationAuthType.BASIC,
|
|
89
109
|
firebase: IntegrationAuthType.FIREBASE,
|
|
@@ -103,6 +123,8 @@ const AUTH_METHODS_TO_TYPES = {
|
|
|
103
123
|
|
|
104
124
|
export const authSections = ({
|
|
105
125
|
startVersion,
|
|
126
|
+
pkceStartVersion,
|
|
127
|
+
confidentialPkceStartVersion,
|
|
106
128
|
endVersion,
|
|
107
129
|
pluginId,
|
|
108
130
|
pluginName,
|
|
@@ -115,6 +137,8 @@ export const authSections = ({
|
|
|
115
137
|
prependItems = []
|
|
116
138
|
}: {
|
|
117
139
|
startVersion: string;
|
|
140
|
+
pkceStartVersion?: string;
|
|
141
|
+
confidentialPkceStartVersion?: string;
|
|
118
142
|
endVersion?: string;
|
|
119
143
|
pluginId: ExtendedIntegrationPluginId;
|
|
120
144
|
pluginName: string;
|
|
@@ -171,10 +195,11 @@ export const authSections = ({
|
|
|
171
195
|
{
|
|
172
196
|
name: isProto ? 'connection.auth.method.case' : 'authType',
|
|
173
197
|
label: 'Authentication',
|
|
198
|
+
secondaryName: pkceStartVersion ? 'authConfig.usePkce' : undefined,
|
|
174
199
|
startVersion: startVersion,
|
|
175
200
|
componentType: FormComponentType.DROPDOWN,
|
|
176
201
|
initialValue: authTypeInitialValue,
|
|
177
|
-
options: authTypeOptions({ enabledMethods, allowNone,
|
|
202
|
+
options: authTypeOptions({ enabledMethods, allowNone, apiKeyFormDisplayName, pkceStartVersion }),
|
|
178
203
|
disabled: !allowNone && enabledMethodKeys.length === 1
|
|
179
204
|
}
|
|
180
205
|
],
|
|
@@ -789,6 +814,24 @@ export const authSections = ({
|
|
|
789
814
|
}
|
|
790
815
|
}
|
|
791
816
|
} as FormItem,
|
|
817
|
+
...(confidentialPkceStartVersion
|
|
818
|
+
? [
|
|
819
|
+
{
|
|
820
|
+
...BASE_CLIENT_SECRET,
|
|
821
|
+
startVersion: confidentialPkceStartVersion,
|
|
822
|
+
rules: [{ required: false }],
|
|
823
|
+
tooltip: {
|
|
824
|
+
markdownText: 'Only required for confidential OAuth clients.'
|
|
825
|
+
},
|
|
826
|
+
display: {
|
|
827
|
+
show: {
|
|
828
|
+
authType: [IntegrationAuthType.OAUTH2_CODE],
|
|
829
|
+
'authConfig.usePkce': PKCE_ON_MARKERS
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
} as FormItem
|
|
833
|
+
]
|
|
834
|
+
: []),
|
|
792
835
|
{
|
|
793
836
|
...BASE_CLIENT_ID,
|
|
794
837
|
startVersion,
|
|
@@ -804,10 +847,29 @@ export const authSections = ({
|
|
|
804
847
|
startVersion,
|
|
805
848
|
display: {
|
|
806
849
|
show: {
|
|
807
|
-
authType: [IntegrationAuthType.OAUTH2_PASSWORD, IntegrationAuthType.OAUTH2_CLIENT_CREDS, IntegrationAuthType.OAUTH2_CODE]
|
|
850
|
+
authType: [IntegrationAuthType.OAUTH2_PASSWORD, IntegrationAuthType.OAUTH2_CLIENT_CREDS, IntegrationAuthType.OAUTH2_CODE],
|
|
851
|
+
...(pkceStartVersion ? { 'authConfig.usePkce': PKCE_OFF_MARKERS } : {})
|
|
808
852
|
}
|
|
809
853
|
}
|
|
810
854
|
} as FormItem,
|
|
855
|
+
...(pkceStartVersion
|
|
856
|
+
? [
|
|
857
|
+
{
|
|
858
|
+
// Keep a confidential client's stored secret if the current
|
|
859
|
+
// agent only supports public PKCE.
|
|
860
|
+
...BASE_CLIENT_SECRET,
|
|
861
|
+
startVersion: pkceStartVersion,
|
|
862
|
+
hidden: true,
|
|
863
|
+
rules: [{ required: false }],
|
|
864
|
+
display: {
|
|
865
|
+
show: {
|
|
866
|
+
authType: [IntegrationAuthType.OAUTH2_CODE],
|
|
867
|
+
'authConfig.usePkce': PKCE_ON_MARKERS
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
} as FormItem
|
|
871
|
+
]
|
|
872
|
+
: []),
|
|
811
873
|
{
|
|
812
874
|
...BASE_CLIENT_SECRET,
|
|
813
875
|
startVersion,
|
|
@@ -883,24 +945,69 @@ export const authSections = ({
|
|
|
883
945
|
startVersion: startVersion,
|
|
884
946
|
componentType: FormComponentType.DROPDOWN,
|
|
885
947
|
initialValue: ClientAuthMethod.POST,
|
|
886
|
-
options:
|
|
887
|
-
{
|
|
888
|
-
displayName: 'Send client credentials in body',
|
|
889
|
-
key: ClientAuthMethod.POST,
|
|
890
|
-
value: ClientAuthMethod.POST
|
|
891
|
-
},
|
|
892
|
-
{
|
|
893
|
-
displayName: 'Send as Basic Auth header',
|
|
894
|
-
key: ClientAuthMethod.BASIC,
|
|
895
|
-
value: ClientAuthMethod.BASIC
|
|
896
|
-
}
|
|
897
|
-
],
|
|
948
|
+
options: CLIENT_AUTH_METHOD_OPTIONS,
|
|
898
949
|
display: {
|
|
899
950
|
show: {
|
|
900
|
-
authType: [IntegrationAuthType.OAUTH2_CODE]
|
|
951
|
+
authType: [IntegrationAuthType.OAUTH2_CODE],
|
|
952
|
+
...(pkceStartVersion ? { 'authConfig.usePkce': PKCE_OFF_MARKERS } : {})
|
|
901
953
|
}
|
|
902
954
|
}
|
|
903
955
|
},
|
|
956
|
+
...(confidentialPkceStartVersion
|
|
957
|
+
? [
|
|
958
|
+
{
|
|
959
|
+
label: 'Client authentication',
|
|
960
|
+
name: 'authConfig.clientAuthMethod',
|
|
961
|
+
startVersion: confidentialPkceStartVersion,
|
|
962
|
+
componentType: FormComponentType.DROPDOWN,
|
|
963
|
+
initialValue: ClientAuthMethod.POST,
|
|
964
|
+
options: CLIENT_AUTH_METHOD_OPTIONS,
|
|
965
|
+
display: {
|
|
966
|
+
show: {
|
|
967
|
+
authType: [IntegrationAuthType.OAUTH2_CODE],
|
|
968
|
+
'authConfig.usePkce': PKCE_ON_MARKERS
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
} satisfies FormItem
|
|
972
|
+
]
|
|
973
|
+
: []),
|
|
974
|
+
...(pkceStartVersion
|
|
975
|
+
? [
|
|
976
|
+
{
|
|
977
|
+
// Keep the stored method if the current agent only supports
|
|
978
|
+
// public PKCE. No initial value avoids writing a default into
|
|
979
|
+
// configs that never chose one.
|
|
980
|
+
label: 'Client authentication',
|
|
981
|
+
name: 'authConfig.clientAuthMethod',
|
|
982
|
+
startVersion: pkceStartVersion,
|
|
983
|
+
componentType: FormComponentType.DROPDOWN,
|
|
984
|
+
hidden: true,
|
|
985
|
+
options: CLIENT_AUTH_METHOD_OPTIONS,
|
|
986
|
+
display: {
|
|
987
|
+
show: {
|
|
988
|
+
authType: [IntegrationAuthType.OAUTH2_CODE],
|
|
989
|
+
'authConfig.usePkce': PKCE_ON_MARKERS
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
} satisfies FormItem
|
|
993
|
+
]
|
|
994
|
+
: []),
|
|
995
|
+
...(pkceStartVersion
|
|
996
|
+
? [
|
|
997
|
+
{
|
|
998
|
+
label: '',
|
|
999
|
+
name: 'authConfig.usePkce',
|
|
1000
|
+
startVersion: pkceStartVersion,
|
|
1001
|
+
componentType: FormComponentType.CHECKBOX,
|
|
1002
|
+
hidden: true,
|
|
1003
|
+
display: {
|
|
1004
|
+
show: {
|
|
1005
|
+
authType: [IntegrationAuthType.OAUTH2_CODE]
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
} satisfies FormItem
|
|
1009
|
+
]
|
|
1010
|
+
: []),
|
|
904
1011
|
{
|
|
905
1012
|
label: 'Send state parameter',
|
|
906
1013
|
name: 'authConfig.sendOAuthState',
|
|
@@ -1361,6 +1468,7 @@ export const authSections = ({
|
|
|
1361
1468
|
'authConfig.authorizationUrl',
|
|
1362
1469
|
'authConfig.refreshTokenFromServer',
|
|
1363
1470
|
'authConfig.clientAuthMethod',
|
|
1471
|
+
'authConfig.usePkce',
|
|
1364
1472
|
'dynamicWorkflowConfiguration.enabled',
|
|
1365
1473
|
'dynamicWorkflowConfiguration.workflowId'
|
|
1366
1474
|
],
|
|
@@ -1467,13 +1575,13 @@ function apiKeyAuthOptions(pluginId: ExtendedIntegrationPluginId): DropdownOptio
|
|
|
1467
1575
|
function authTypeOptions({
|
|
1468
1576
|
enabledMethods,
|
|
1469
1577
|
allowNone = true,
|
|
1470
|
-
|
|
1471
|
-
|
|
1578
|
+
apiKeyFormDisplayName,
|
|
1579
|
+
pkceStartVersion
|
|
1472
1580
|
}: {
|
|
1473
1581
|
enabledMethods: AuthMethods;
|
|
1474
1582
|
allowNone?: boolean;
|
|
1475
|
-
isProto?: boolean;
|
|
1476
1583
|
apiKeyFormDisplayName?: string;
|
|
1584
|
+
pkceStartVersion?: string;
|
|
1477
1585
|
}): DropdownOption[] {
|
|
1478
1586
|
const options: DropdownOption[] = allowNone
|
|
1479
1587
|
? [
|
|
@@ -1537,6 +1645,15 @@ function authTypeOptions({
|
|
|
1537
1645
|
value: IntegrationAuthType.OAUTH2_CODE,
|
|
1538
1646
|
key: IntegrationAuthType.OAUTH2_CODE
|
|
1539
1647
|
});
|
|
1648
|
+
if (pkceStartVersion) {
|
|
1649
|
+
options.push({
|
|
1650
|
+
displayName: `${getDisplayName(IntegrationAuthType.OAUTH2_CODE)} (with PKCE)`,
|
|
1651
|
+
value: IntegrationAuthType.OAUTH2_CODE,
|
|
1652
|
+
key: `${IntegrationAuthType.OAUTH2_CODE}-pkce`,
|
|
1653
|
+
secondaryValue: true,
|
|
1654
|
+
startVersion: pkceStartVersion
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1540
1657
|
options.push({
|
|
1541
1658
|
displayName: getDisplayName(IntegrationAuthType.OAUTH2_IMPLICIT),
|
|
1542
1659
|
value: IntegrationAuthType.OAUTH2_IMPLICIT,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gateway (and the CLI esbuild bundle Cursor MCP loads) resolve
|
|
9
|
+
* `@superblocksteam/shared` to this package's Node entry (`dist/`), not
|
|
10
|
+
* `src/`. A stale dist that predates SocketHeartbeat makes Cursor MCP crash
|
|
11
|
+
* with: "does not provide an export named 'SocketHeartbeat'". Rebuild shared
|
|
12
|
+
* before Gateway and the CLI after changing this export.
|
|
13
|
+
*/
|
|
14
|
+
describe('Node package entry', () => {
|
|
15
|
+
it('exports SocketHeartbeat as a named binding Gateway can import', async () => {
|
|
16
|
+
const require = createRequire(path.join(process.cwd(), 'package.json'));
|
|
17
|
+
let entry: string;
|
|
18
|
+
try {
|
|
19
|
+
entry = require.resolve('@superblocksteam/shared');
|
|
20
|
+
} catch {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!existsSync(entry)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const shared = await import(entry);
|
|
27
|
+
expect(typeof shared.SocketHeartbeat).toBe('function');
|
|
28
|
+
});
|
|
29
|
+
});
|