@intuned/runtime-dev 0.0.1-testing.0 → 0.0.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 (131) hide show
  1. package/.vite/deps_temp_01af7156/package.json +3 -0
  2. package/.vscode/extensions.json +3 -0
  3. package/.vscode/launch.json +102 -0
  4. package/.vscode/settings.json +12 -0
  5. package/WebTemplate/controllers/authSessions/create.ts +1 -1
  6. package/WebTemplate/controllers/runApi/helpers.ts +3 -1
  7. package/package.json +3 -3
  8. package/playwright.config.ts +48 -0
  9. package/src/commands/api/run.ts +225 -0
  10. package/src/commands/auth-sessions/load.ts +42 -0
  11. package/src/commands/auth-sessions/run-check.ts +70 -0
  12. package/src/commands/auth-sessions/run-create.ts +124 -0
  13. package/src/commands/browser/save-state.ts +22 -0
  14. package/src/commands/browser/start-browser.ts +17 -0
  15. package/src/commands/build.ts +125 -0
  16. package/src/commands/common/browserUtils.ts +80 -0
  17. package/src/commands/common/getDefaultExportFromFile.ts +13 -0
  18. package/{dist/commands/common/getFirstLineNumber.test.js → src/commands/common/getFirstLineNumber.test.ts} +121 -75
  19. package/src/commands/common/getFirstLineNumber.ts +146 -0
  20. package/src/commands/common/sendMessageToClient.ts +8 -0
  21. package/src/commands/common/utils/fileUtils.ts +25 -0
  22. package/src/commands/common/utils/settings.ts +23 -0
  23. package/src/commands/common/utils/webTemplate.ts +46 -0
  24. package/src/commands/testing/saveVisibleHtml.ts +29 -0
  25. package/src/commands/ts-check.ts +88 -0
  26. package/src/common/Logger/Logger/index.ts +64 -0
  27. package/{dist/common/Logger/types.d.ts → src/common/Logger/Logger/types.ts} +5 -4
  28. package/src/common/Logger/index.ts +64 -0
  29. package/{dist/common/Logger/Logger/types.d.ts → src/common/Logger/types.ts} +5 -4
  30. package/src/common/asyncLocalStorage/index.ts +29 -0
  31. package/src/common/cleanEnvironmentVariables.ts +13 -0
  32. package/src/common/constants.ts +1 -0
  33. package/src/common/contextStorageStateHelpers.ts +71 -0
  34. package/src/common/getPlaywrightConstructs.ts +283 -0
  35. package/src/common/jwtTokenManager.ts +111 -0
  36. package/src/common/settingsSchema.ts +16 -0
  37. package/src/common/telemetry.ts +49 -0
  38. package/src/index.ts +14 -0
  39. package/src/runtime/RunError.ts +16 -0
  40. package/src/runtime/downloadDirectory.ts +14 -0
  41. package/src/runtime/enums.ts +11 -0
  42. package/src/runtime/executionHelpers.test.ts +70 -0
  43. package/src/runtime/extendPayload.ts +22 -0
  44. package/src/runtime/extendTimeout.ts +32 -0
  45. package/{dist/runtime/index.d.ts → src/runtime/index.ts} +3 -1
  46. package/src/runtime/requestMoreInfo.ts +40 -0
  47. package/src/runtime/runInfo.ts +19 -0
  48. package/vite.config.ts +17 -0
  49. package/bin/intuned-api-run +0 -2
  50. package/bin/intuned-auth-session-check +0 -2
  51. package/bin/intuned-auth-session-create +0 -2
  52. package/bin/intuned-auth-session-load +0 -2
  53. package/bin/intuned-auth-session-refresh +0 -2
  54. package/bin/intuned-browser-save-state +0 -2
  55. package/bin/intuned-browser-start +0 -2
  56. package/bin/intuned-build +0 -2
  57. package/bin/intuned-ts-check +0 -2
  58. package/dist/commands/api/run.d.ts +0 -6
  59. package/dist/commands/api/run.js +0 -135
  60. package/dist/commands/auth-sessions/load.d.ts +0 -2
  61. package/dist/commands/auth-sessions/load.js +0 -26
  62. package/dist/commands/auth-sessions/run-check.d.ts +0 -2
  63. package/dist/commands/auth-sessions/run-check.js +0 -42
  64. package/dist/commands/auth-sessions/run-create.d.ts +0 -2
  65. package/dist/commands/auth-sessions/run-create.js +0 -75
  66. package/dist/commands/browser/save-state.d.ts +0 -2
  67. package/dist/commands/browser/save-state.js +0 -17
  68. package/dist/commands/browser/start-browser.d.ts +0 -2
  69. package/dist/commands/browser/start-browser.js +0 -14
  70. package/dist/commands/build.d.ts +0 -2
  71. package/dist/commands/build.js +0 -80
  72. package/dist/commands/common/browserUtils.d.ts +0 -14
  73. package/dist/commands/common/browserUtils.js +0 -58
  74. package/dist/commands/common/getDefaultExportFromFile.d.ts +0 -1
  75. package/dist/commands/common/getDefaultExportFromFile.js +0 -19
  76. package/dist/commands/common/getFirstLineNumber.d.ts +0 -9
  77. package/dist/commands/common/getFirstLineNumber.js +0 -103
  78. package/dist/commands/common/sendMessageToClient.d.ts +0 -1
  79. package/dist/commands/common/sendMessageToClient.js +0 -10
  80. package/dist/commands/common/utils/fileUtils.d.ts +0 -6
  81. package/dist/commands/common/utils/fileUtils.js +0 -33
  82. package/dist/commands/common/utils/settings.d.ts +0 -2
  83. package/dist/commands/common/utils/settings.js +0 -28
  84. package/dist/commands/common/utils/webTemplate.d.ts +0 -1
  85. package/dist/commands/common/utils/webTemplate.js +0 -31
  86. package/dist/commands/ts-check.d.ts +0 -2
  87. package/dist/commands/ts-check.js +0 -54
  88. package/dist/common/Logger/Logger/index.d.ts +0 -12
  89. package/dist/common/Logger/Logger/index.js +0 -60
  90. package/dist/common/Logger/Logger/types.js +0 -5
  91. package/dist/common/Logger/index.d.ts +0 -12
  92. package/dist/common/Logger/index.js +0 -60
  93. package/dist/common/Logger/types.js +0 -5
  94. package/dist/common/asyncLocalStorage/index.d.ts +0 -16
  95. package/dist/common/asyncLocalStorage/index.js +0 -17
  96. package/dist/common/cleanEnvironmentVariables.d.ts +0 -1
  97. package/dist/common/cleanEnvironmentVariables.js +0 -16
  98. package/dist/common/constants.d.ts +0 -1
  99. package/dist/common/constants.js +0 -7
  100. package/dist/common/contextStorageStateHelpers.d.ts +0 -15
  101. package/dist/common/contextStorageStateHelpers.js +0 -48
  102. package/dist/common/getPlaywrightConstructs.d.ts +0 -28
  103. package/dist/common/getPlaywrightConstructs.js +0 -175
  104. package/dist/common/jwtTokenManager.d.ts +0 -16
  105. package/dist/common/jwtTokenManager.js +0 -81
  106. package/dist/common/settingsSchema.d.ts +0 -19
  107. package/dist/common/settingsSchema.js +0 -17
  108. package/dist/common/telemetry.d.ts +0 -3
  109. package/dist/common/telemetry.js +0 -32
  110. package/dist/index.d.ts +0 -4
  111. package/dist/index.js +0 -69
  112. package/dist/runtime/RunError.d.ts +0 -5
  113. package/dist/runtime/RunError.js +0 -19
  114. package/dist/runtime/downloadDirectory.d.ts +0 -1
  115. package/dist/runtime/downloadDirectory.js +0 -19
  116. package/dist/runtime/enums.d.js +0 -5
  117. package/dist/runtime/enums.js +0 -18
  118. package/dist/runtime/executionHelpers.test.js +0 -53
  119. package/dist/runtime/export.d.js +0 -5
  120. package/dist/runtime/extendPayload.d.ts +0 -2
  121. package/dist/runtime/extendPayload.js +0 -21
  122. package/dist/runtime/extendTimeout.d.ts +0 -1
  123. package/dist/runtime/extendTimeout.js +0 -26
  124. package/dist/runtime/index.js +0 -53
  125. package/dist/runtime/requestMoreInfo.d.ts +0 -17
  126. package/dist/runtime/requestMoreInfo.js +0 -25
  127. package/dist/runtime/runInfo.d.ts +0 -2
  128. package/dist/runtime/runInfo.js +0 -21
  129. /package/{dist → src}/common/assets/browser_scripts.js +0 -0
  130. /package/{dist → src}/runtime/enums.d.ts +0 -0
  131. /package/{dist → src}/runtime/export.d.ts +0 -0
@@ -0,0 +1,283 @@
1
+ import * as playwright from "@intuned/playwright-core";
2
+ import { existsSync, mkdir, mkdtemp, rm, writeFile, readFile } from "fs-extra";
3
+ import {
4
+ IntunedStorageState,
5
+ setContextStorageState,
6
+ } from "./contextStorageStateHelpers";
7
+ import { join } from "path";
8
+ import path from "path";
9
+ import type { Browser, Page } from "@intuned/playwright-core";
10
+ import * as fs from "fs-extra";
11
+ import { getFullPathInProject } from "../commands/common/utils/fileUtils";
12
+ import waitOn from "wait-on";
13
+ import { getDownloadDirectoryPath } from "../runtime";
14
+
15
+ interface Proxy {
16
+ server: string;
17
+ username: string;
18
+ password: string;
19
+ }
20
+
21
+ interface GetPlaywrightConstructsOptions {
22
+ proxy?: Proxy;
23
+ headless?: boolean;
24
+ storageState?: IntunedStorageState;
25
+ downloadsPath: string;
26
+ userDataDir?: string;
27
+ }
28
+
29
+ async function createUserDirWithPreferences() {
30
+ const playwrightTempDir = await mkdtemp("/tmp/pw-");
31
+ const userDir = join(playwrightTempDir, "userdir");
32
+ const defaultDir = join(userDir, "Default");
33
+ await mkdir(defaultDir, {
34
+ recursive: true,
35
+ });
36
+ const preferences = {
37
+ plugins: {
38
+ always_open_pdf_externally: true,
39
+ },
40
+ };
41
+ await writeFile(join(defaultDir, "Preferences"), JSON.stringify(preferences));
42
+
43
+ return userDir;
44
+ }
45
+
46
+ export async function getProductionPlaywrightConstructs({
47
+ proxy,
48
+ headless = true,
49
+ storageState,
50
+ downloadsPath,
51
+ }: GetPlaywrightConstructsOptions): Promise<{
52
+ page: playwright.Page;
53
+ context: playwright.BrowserContext;
54
+ }> {
55
+ const extraArgs = [
56
+ "--no-first-run",
57
+ "--disable-sync",
58
+ "--disable-translate",
59
+ "--disable-features=TranslateUI",
60
+ "--disable-features=NetworkService",
61
+ "--lang=en",
62
+ ];
63
+
64
+ if (headless) {
65
+ extraArgs.push("--headless=new");
66
+ }
67
+
68
+ const executablePath = playwright.chromium.executablePath();
69
+ // use chromium 127 instead of 125, this depends on the docker image playwright version.
70
+ const chromium127Path = executablePath.replace(
71
+ "chromium-1117",
72
+ "chromium-1124"
73
+ );
74
+
75
+ const isChrome127There = existsSync(chromium127Path);
76
+
77
+ const userAgent = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${
78
+ isChrome127There ? 127 : 125
79
+ }.0.0.0 Safari/537.36`;
80
+
81
+ const userDataDir = await createUserDirWithPreferences();
82
+
83
+ const context = await playwright.chromium.launchPersistentContext(
84
+ userDataDir,
85
+ {
86
+ headless,
87
+ ignoreDefaultArgs: [...getChromiumLaunchArgsToIgnore(), "--headless"],
88
+ proxy,
89
+ executablePath: isChrome127There ? chromium127Path : executablePath,
90
+ args: extraArgs,
91
+ downloadsPath,
92
+ userAgent,
93
+ }
94
+ );
95
+
96
+ context.once("close", async () => {
97
+ try {
98
+ await rm(userDataDir, {
99
+ recursive: true,
100
+ force: true,
101
+ retryDelay: 1000,
102
+ maxRetries: 5,
103
+ });
104
+ } catch (error) {
105
+ console.error("Failed to remove user data dir", error);
106
+ }
107
+ });
108
+
109
+ if (storageState) {
110
+ await setContextStorageState(context, storageState);
111
+ }
112
+
113
+ const assetsFile = path.join(__dirname, "./assets/browser_scripts.js");
114
+ await context.addInitScript({
115
+ path: assetsFile,
116
+ });
117
+
118
+ let page = context.pages().at(0);
119
+
120
+ if (page) {
121
+ const scriptString = await readFile(assetsFile, "utf8");
122
+ await page.evaluate(scriptString);
123
+ } else {
124
+ page = await context.newPage();
125
+ }
126
+
127
+ return {
128
+ page,
129
+ context,
130
+ };
131
+ }
132
+
133
+ const getChromiumLaunchArgsToIgnore = () => [
134
+ "--disable-field-trial-config",
135
+ "--disable-background-networking",
136
+ "--enable-features=NetworkService,NetworkServiceInProcess",
137
+ "--disable-background-timer-throttling",
138
+ "--disable-backgrounding-occluded-windows",
139
+ "--disable-back-forward-cache",
140
+ "--disable-breakpad",
141
+ "--disable-client-side-phishing-detection",
142
+ "--disable-component-extensions-with-background-pages",
143
+ "--disable-component-update",
144
+ "--no-default-browser-check",
145
+ "--disable-default-apps",
146
+ "--disable-dev-shm-usage",
147
+ "--disable-extensions",
148
+ "--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,TranslateUI",
149
+ "--allow-pre-commit-input",
150
+ "--disable-hang-monitor",
151
+ "--disable-ipc-flooding-protection",
152
+ "--disable-prompt-on-repost",
153
+ "--disable-renderer-backgrounding",
154
+ "--force-color-profile=srgb",
155
+ "--metrics-recording-only",
156
+ "--no-first-run",
157
+ "--enable-automation",
158
+ "--password-store=basic",
159
+ "--use-mock-keychain",
160
+ "--no-service-autorun",
161
+ "--export-tagged-pdf",
162
+ "--enable-use-zoom-for-dsf=false",
163
+ ];
164
+
165
+ export async function getPlaywrightConstructsForMode(
166
+ mode:
167
+ | "vanilla"
168
+ | "playwright"
169
+ | "playwright-standalone"
170
+ | "playwright-headless",
171
+ cdpAddress: string | undefined,
172
+ authSessionPath?: string
173
+ ): Promise<{
174
+ page: playwright.Page;
175
+ context: playwright.BrowserContext;
176
+ }> {
177
+ if (mode == "playwright-standalone") {
178
+ if (!cdpAddress) {
179
+ throw new Error("cdpAddress is required");
180
+ }
181
+
182
+ const { context } = await getRemotePlaywrightContext(cdpAddress);
183
+ if (!context) {
184
+ throw new Error("no context found");
185
+ }
186
+
187
+ const assetsFile = path.join(__dirname, "./assets/browser_scripts.js");
188
+ await context.addInitScript({
189
+ path: assetsFile,
190
+ });
191
+
192
+ const pages = await context.pages();
193
+ let page: Page | null = null;
194
+ if (pages.length > 0) {
195
+ page = pages[0];
196
+ const scriptString = await fs.readFile(assetsFile, "utf8");
197
+ await page.evaluate(scriptString);
198
+ } else {
199
+ page = await context.newPage();
200
+ }
201
+
202
+ if (authSessionPath) {
203
+ await loadAuthSessionToContext(context, authSessionPath);
204
+ }
205
+
206
+ return {
207
+ page,
208
+ context,
209
+ };
210
+ }
211
+
212
+ const downloadsPath = getDownloadDirectoryPath();
213
+ if (mode === "playwright" || mode === "playwright-headless") {
214
+ const productionConstructs = await getProductionPlaywrightConstructs({
215
+ headless: mode === "playwright-headless",
216
+ downloadsPath,
217
+ });
218
+
219
+ if (authSessionPath) {
220
+ await loadAuthSessionToContext(
221
+ productionConstructs.context,
222
+ authSessionPath
223
+ );
224
+ }
225
+
226
+ return {
227
+ ...productionConstructs,
228
+ };
229
+ }
230
+
231
+ throw "invalid mode";
232
+ }
233
+
234
+ export async function loadAuthSessionToContext(
235
+ context: playwright.BrowserContext,
236
+ authSessionPath: string
237
+ ) {
238
+ const fullPath = getFullPathInProject(authSessionPath);
239
+ const data = await fs.readJson(fullPath);
240
+
241
+ await setContextStorageState(context, data);
242
+ }
243
+
244
+ export async function getRemotePlaywrightContext(cdpAddress: string) {
245
+ const playwright = await import("@intuned/playwright-core");
246
+ let browser: Browser | null = null;
247
+
248
+ if (!cdpAddress) {
249
+ throw new Error("cdpAddress is required");
250
+ }
251
+
252
+ const cdpAddressWithoutProtocol = cdpAddress
253
+ .replace("http://", "")
254
+ .replace("https://", "")
255
+ .replace("localhost", "127.0.0.1");
256
+
257
+ try {
258
+ await waitOn({
259
+ resources: [`http-get://${cdpAddressWithoutProtocol}/json/version`],
260
+ delay: 100,
261
+ interval: 100,
262
+ timeout: 5000,
263
+ tcpTimeout: 1000,
264
+ window: 1000,
265
+ });
266
+ } catch (error) {
267
+ console.error("Failed to connect to the browser");
268
+ // 128 is the exit code for SIGINT https://tldp.org/LDP/abs/html/exitcodes.html
269
+ // 9 is the SIGKILL signal
270
+ process.exit(128 + 9);
271
+ }
272
+
273
+ try {
274
+ browser = await playwright.chromium.connectOverCDP(cdpAddress);
275
+ } catch (e) {
276
+ console.log(e);
277
+ throw new Error("failed to connect to the browser");
278
+ }
279
+
280
+ const context = browser.contexts()[0];
281
+
282
+ return { browser, context };
283
+ }
@@ -0,0 +1,111 @@
1
+ import fetch from "cross-fetch";
2
+ import * as jwt from "jsonwebtoken";
3
+ import { err, ResultAsync } from "neverthrow";
4
+
5
+ // Manages JWT token with renewal
6
+ class JwtTokenManager {
7
+ private _token: string | undefined;
8
+ private tokenRefreshTimeout: NodeJS.Timeout | undefined;
9
+ private refreshTokenPath: string;
10
+
11
+ constructor(refreshTokenPath: string) {
12
+ this.refreshTokenPath = refreshTokenPath;
13
+ this._token = undefined;
14
+ }
15
+
16
+ public get token() {
17
+ return this._token;
18
+ }
19
+
20
+ // When the token is set, the schedule for renewal is issued automatically
21
+ // This is currently being set it two places:
22
+ // 1. Whenever the runner starts, initializes it from the environment variable (set whenever the api is run from the authoring IDE)
23
+ // 2. Whenever a published api is called to run (/api/run/*), it is set to the token received in the run request.
24
+ public set token(newToken: string | undefined) {
25
+ if (this._token != newToken) {
26
+ this._token = newToken;
27
+ void this.scheduleTokenRefresh();
28
+ }
29
+ }
30
+
31
+ private get timeToRefresh() {
32
+ if (!this._token) return;
33
+
34
+ const payload = jwt.decode(this._token);
35
+
36
+ if (!payload || typeof payload == "string") return;
37
+
38
+ const expiry = payload.expiry;
39
+ if (!expiry || typeof expiry !== "number") return;
40
+
41
+ const timeWindow = 60 * 1000; // 1 minute
42
+
43
+ const timeToRefresh = expiry - Date.now() - timeWindow;
44
+ return Math.max(timeToRefresh, timeWindow);
45
+ }
46
+
47
+ private async scheduleTokenRefresh() {
48
+ if (process.env.RUN_ENVIRONMENT?.toLowerCase() !== "authoring") return;
49
+ const timeToRefresh = this.timeToRefresh;
50
+ if (timeToRefresh === undefined) return;
51
+
52
+ if (this.tokenRefreshTimeout) clearTimeout(this.tokenRefreshTimeout);
53
+
54
+ this.tokenRefreshTimeout = setTimeout(async () => {
55
+ const result = await this.refreshToken();
56
+ if (result && result.isErr()) {
57
+ console.error(`[Internal Error] ${result.error}`);
58
+ return;
59
+ }
60
+ await this.scheduleTokenRefresh();
61
+ }, timeToRefresh);
62
+ }
63
+
64
+ private async refreshToken() {
65
+ if (process.env.RUN_ENVIRONMENT?.toLowerCase() !== "authoring") return;
66
+ const res = await this.fetchWithToken(this.refreshTokenPath, {
67
+ method: "GET",
68
+ });
69
+
70
+ if (res.status === 401) {
71
+ return err("Unauthorized");
72
+ }
73
+
74
+ const jsonResult = await ResultAsync.fromPromise(
75
+ res.json(),
76
+ () => "not json"
77
+ );
78
+
79
+ if (jsonResult.isErr()) return;
80
+
81
+ const newToken = jsonResult.value.token;
82
+ if (newToken) this._token = newToken;
83
+ }
84
+
85
+ public fetchWithToken(...[input, init]: Parameters<typeof fetch>) {
86
+ const headers = new Headers(init?.headers);
87
+ headers.set("Authorization", `Bearer ${this.token}`);
88
+ return fetch(input, {
89
+ ...init,
90
+ headers,
91
+ });
92
+ }
93
+ }
94
+
95
+ const backendFunctionsPath = `${process.env.FUNCTIONS_DOMAIN}/api/${process.env.INTUNED_WORKSPACE_ID}/functions/${process.env.INTUNED_INTEGRATION_ID}`;
96
+
97
+ export const backendFunctionsTokenManager = new JwtTokenManager(
98
+ `${backendFunctionsPath}/refreshBackendFunctionsToken`
99
+ );
100
+ backendFunctionsTokenManager.token =
101
+ process.env.INTUNED_AUTHORING_SESSION_BACKEND_FUNCTIONS_TOKEN;
102
+
103
+ export function callBackendFunctionWithToken(
104
+ path: string,
105
+ init?: Parameters<typeof fetch>[1]
106
+ ) {
107
+ return backendFunctionsTokenManager.fetchWithToken(
108
+ `${backendFunctionsPath}/${path}`,
109
+ init
110
+ );
111
+ }
@@ -0,0 +1,16 @@
1
+ import * as z from "zod";
2
+
3
+ const authSessionsSchema = z
4
+ .object({
5
+ enabled: z.boolean(),
6
+ })
7
+ .optional()
8
+ .default({
9
+ enabled: false,
10
+ });
11
+
12
+ export const settingsSchema = z.object({
13
+ authSessions: authSessionsSchema,
14
+ });
15
+
16
+ export type IntunedSettings = z.infer<typeof settingsSchema>;
@@ -0,0 +1,49 @@
1
+ import * as appInsights from "applicationinsights";
2
+
3
+ function gracefulShutdown() {
4
+ console.log("Shutting down, so flushing app insights.");
5
+
6
+ appInsights.defaultClient.flush();
7
+
8
+ process.exit();
9
+ }
10
+
11
+ export function initializeAppInsights() {
12
+ const appInsightsConnectionString = process.env.APPINSIGHTS_CONNECTION_STRING;
13
+
14
+ if (appInsightsConnectionString) {
15
+ console.log("Initializing app insights.");
16
+
17
+ appInsights
18
+ .setup(appInsightsConnectionString)
19
+ .setAutoCollectConsole(true, true)
20
+ .setAutoCollectDependencies(true)
21
+ .setAutoCollectExceptions(true)
22
+ .setAutoCollectHeartbeat(true)
23
+ .setAutoCollectPerformance(true, true)
24
+ .setAutoCollectRequests(true)
25
+ .setAutoDependencyCorrelation(true)
26
+ .setDistributedTracingMode(appInsights.DistributedTracingModes.AI_AND_W3C)
27
+ .setSendLiveMetrics(true)
28
+ .setUseDiskRetryCaching(true);
29
+
30
+ appInsights.defaultClient.context.tags[
31
+ appInsights.defaultClient.context.keys.cloudRole
32
+ ] = "@intuned/sdk";
33
+
34
+ if (process.env.FLY_APP_NAME) {
35
+ appInsights.defaultClient.context.tags[
36
+ appInsights.defaultClient.context.keys.cloudRoleInstance
37
+ ] = process.env.FLY_APP_NAME;
38
+ }
39
+
40
+ process.on("SIGTERM", gracefulShutdown);
41
+ process.on("SIGINT", gracefulShutdown);
42
+
43
+ appInsights.start();
44
+ }
45
+ }
46
+
47
+ export function getTelemetryClient(): appInsights.TelemetryClient | undefined {
48
+ return appInsights.defaultClient;
49
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export {
2
+ extendPayload,
3
+ extendTimeout,
4
+ runInfo,
5
+ RunError,
6
+ requestMultipleChoice,
7
+ requestOTP,
8
+ } from "./runtime";
9
+ export {
10
+ runWithContext,
11
+ getExecutionContext,
12
+ } from "./common/asyncLocalStorage";
13
+ export { getDownloadDirectoryPath } from "./runtime/downloadDirectory";
14
+ export { getProductionPlaywrightConstructs } from "./common/getPlaywrightConstructs";
@@ -0,0 +1,16 @@
1
+ import { RunErrorOptions } from "./export";
2
+
3
+ export class RunError extends Error {
4
+ options: RunErrorOptions;
5
+ constructor(message: string, options?: RunErrorOptions) {
6
+ super(message);
7
+ this.message = message;
8
+ this.name = "USER_GENERATED_ERROR";
9
+ this.options = options ?? {
10
+ retryable: false,
11
+ };
12
+ Object.setPrototypeOf(this, RunError.prototype);
13
+ }
14
+ }
15
+
16
+ new RunError("", {});
@@ -0,0 +1,14 @@
1
+ import { getExecutionContext } from "..";
2
+ import { ensureDirSync } from "fs-extra";
3
+
4
+ export function getDownloadDirectoryPath() {
5
+ const context = getExecutionContext();
6
+ if (!context) {
7
+ throw new Error("ExecutionContext not found");
8
+ }
9
+ const path = `/tmp/downloads/${context.runId}`;
10
+ ensureDirSync(path, {
11
+ mode: 0o2775,
12
+ });
13
+ return path;
14
+ }
@@ -0,0 +1,11 @@
1
+ export enum RunEnvironment {
2
+ IDE = "IDE",
3
+ DEPLOYED = "DEPLOYED",
4
+ }
5
+
6
+ export enum RunType {
7
+ SYNC = "SYNC",
8
+ ASYNC = "ASYNC",
9
+ JOB = "JOB",
10
+ QUEUE = "QUEUE",
11
+ }
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ getExecutionContext,
4
+ runWithContext,
5
+ } from "../common/asyncLocalStorage";
6
+ import { RunError, extendPayload, runInfo } from "./index";
7
+ import { RunEnvironment, RunType } from "./enums";
8
+
9
+ describe("Execution Helpers", () => {
10
+ it("should be able to get execution info", () => {
11
+ runWithContext(
12
+ {
13
+ runEnvironment: RunEnvironment.IDE,
14
+ // runType: RunType.SYNC,
15
+ runId: "test-run-id",
16
+ extendedPayloads: [],
17
+ },
18
+ () => {
19
+ expect(runInfo().runId).toEqual("test-run-id");
20
+ }
21
+ );
22
+ });
23
+
24
+ it("should be able to mutate extendedPayloads and get the accmulated value at the end ", () => {
25
+ const context = {
26
+ extendedPayloads: [],
27
+ runId: "test-run-id",
28
+ };
29
+
30
+ runWithContext(
31
+ {
32
+ runEnvironment: RunEnvironment.IDE,
33
+ // runType: RunType.SYNC,
34
+ runId: "test-run-id",
35
+ extendedPayloads: [],
36
+ },
37
+ () => {
38
+ expect(getExecutionContext()?.extendedPayloads).toEqual([]);
39
+ extendPayload({
40
+ api: "test-api",
41
+ parameters: {},
42
+ });
43
+
44
+ expect(getExecutionContext()?.extendedPayloads).toEqual([
45
+ {
46
+ api: "test-api",
47
+ parameters: {},
48
+ },
49
+ ]);
50
+
51
+ extendPayload({
52
+ api: "test-api",
53
+ parameters: {},
54
+ });
55
+ extendPayload({
56
+ api: "test-api",
57
+ parameters: {},
58
+ });
59
+ extendPayload({
60
+ api: "test-api",
61
+ parameters: {},
62
+ });
63
+
64
+ const context = getExecutionContext();
65
+
66
+ expect(context?.extendedPayloads).toHaveLength(4);
67
+ }
68
+ );
69
+ });
70
+ });
@@ -0,0 +1,22 @@
1
+ import { getExecutionContext } from "../common/asyncLocalStorage";
2
+ import { Payload } from "./export";
3
+ import { extendTimeout } from "./extendTimeout";
4
+
5
+ export function extendPayload(payload: Payload | Payload[]) {
6
+ const context = getExecutionContext();
7
+
8
+ if (!context) {
9
+ throw new Error("extendPayload failed due to an internal error.");
10
+ }
11
+
12
+ const items = Array.isArray(payload) ? payload : [payload];
13
+
14
+ if (!context.extendedPayloads) {
15
+ context.extendedPayloads = [...items];
16
+ return;
17
+ }
18
+
19
+ context?.extendedPayloads.push(...items);
20
+
21
+ extendTimeout();
22
+ }
@@ -0,0 +1,32 @@
1
+ import { getExecutionContext } from "../common/asyncLocalStorage";
2
+
3
+ const _DEBOUNCE_TIME = 60_000;
4
+
5
+ export function extendTimeout() {
6
+ const context = getExecutionContext();
7
+
8
+ if (!context) {
9
+ throw new Error("extendTimeout failed due to an internal error.");
10
+ }
11
+
12
+ const { timeoutInfo } = context;
13
+
14
+ if (
15
+ !timeoutInfo ||
16
+ timeoutInfo.timeoutTimestamp === undefined ||
17
+ timeoutInfo.timeoutDuration === undefined ||
18
+ timeoutInfo.extendTimeoutCallback === undefined
19
+ ) {
20
+ return;
21
+ }
22
+
23
+ const newTimeoutStamp = Date.now() + timeoutInfo.timeoutDuration;
24
+
25
+ if (newTimeoutStamp - timeoutInfo.timeoutTimestamp < _DEBOUNCE_TIME) {
26
+ return;
27
+ }
28
+
29
+ timeoutInfo.timeoutTimestamp = newTimeoutStamp;
30
+
31
+ void timeoutInfo.extendTimeoutCallback().catch(() => undefined);
32
+ }
@@ -2,5 +2,7 @@ export { extendPayload } from "./extendPayload";
2
2
  export { extendTimeout } from "./extendTimeout";
3
3
  export { runInfo } from "./runInfo";
4
4
  export { RunError } from "./RunError";
5
+
5
6
  export { requestMultipleChoice, requestOTP } from "./requestMoreInfo";
6
- export { getDownloadDirectoryPath } from "./downloadDirectory";
7
+
8
+ export {getDownloadDirectoryPath} from "./downloadDirectory";
@@ -0,0 +1,40 @@
1
+ interface RequestMoreInfoReturnTypeBase {
2
+ [REQUEST_MORE_INFO_KEY]: true;
3
+ action: "request_more_info";
4
+ }
5
+
6
+ interface RequestMultipleChoiceReturnType
7
+ extends RequestMoreInfoReturnTypeBase {
8
+ messageToUser: string;
9
+ choices: string[];
10
+ requestType: "multiple_choice";
11
+ }
12
+
13
+ interface RequestOtpReturnType extends RequestMoreInfoReturnTypeBase {
14
+ messageToUser: string;
15
+ requestType: "otp";
16
+ }
17
+
18
+ const REQUEST_MORE_INFO_KEY: unique symbol = Symbol("REQUEST_MORE_INFO");
19
+
20
+ export function requestOTP(messageToUser: string): RequestOtpReturnType {
21
+ return {
22
+ [REQUEST_MORE_INFO_KEY]: true,
23
+ action: "request_more_info",
24
+ messageToUser,
25
+ requestType: "otp",
26
+ };
27
+ }
28
+
29
+ export function requestMultipleChoice(
30
+ messageToUser: string,
31
+ choices: string[]
32
+ ): RequestMultipleChoiceReturnType {
33
+ return {
34
+ [REQUEST_MORE_INFO_KEY]: true,
35
+ action: "request_more_info",
36
+ messageToUser,
37
+ requestType: "multiple_choice",
38
+ choices,
39
+ };
40
+ }