diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index d8549657..016df57b 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -19,25 +19,32 @@ jobs: tests: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [20, 22, 24] + test: ["unit", "integration:v5", "integration:v4"] + name: Node.js v${{ matrix.node-version }} - ${{ matrix.test }} tests steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: - node-version: "22" + node-version: ${{ matrix.node-version }} - name: Install Dependencies run: npm ci - - name: Run Tests and Add Annotations - run: npm test -- --ci --reporters=default --reporters=github-actions --reporters=jest-junit + - name: Run ${{ matrix.test }} Tests and Add Annotations + run: npm run test:${{ matrix.test }} -- --ci --reporters=default --reporters=github-actions --reporters=jest-junit env: - CONDUCTOR_SERVER_URL: ${{ vars.SERVER_URL }} - CONDUCTOR_AUTH_KEY: ${{ secrets.AUTH_KEY }} - CONDUCTOR_AUTH_SECRET: ${{ secrets.AUTH_SECRET }} - - name: Publish Dorny Test Results Summary + CONDUCTOR_SERVER_URL: ${{ matrix.test == 'integration:v4' && vars.SERVER_URL_V4 || vars.SERVER_URL }} + CONDUCTOR_AUTH_KEY: ${{ matrix.test == 'integration:v4' && secrets.AUTH_KEY_V4 || secrets.AUTH_KEY }} + CONDUCTOR_AUTH_SECRET: ${{ matrix.test == 'integration:v4' && secrets.AUTH_SECRET_V4 || secrets.AUTH_SECRET }} + JEST_JUNIT_OUTPUT_NAME: ${{ matrix.test }}-test-results.xml + - name: Publish ${{ matrix.test }} Test Results uses: dorny/test-reporter@v2 if: ${{ !cancelled() }} with: - name: Test report - path: reports/jest-junit.xml + name: ${{ matrix.test }} Test Report + path: reports/${{ matrix.test }}-test-results.xml reporter: jest-junit diff --git a/.node-version b/.node-version deleted file mode 100644 index 91d5f6ff..00000000 --- a/.node-version +++ /dev/null @@ -1 +0,0 @@ -22.18.0 diff --git a/src/common/open-api/__test__/EventResourceService.test.ts b/integration-tests/common/EventResourceService.test.ts similarity index 88% rename from src/common/open-api/__test__/EventResourceService.test.ts rename to integration-tests/common/EventResourceService.test.ts index bffe72c5..09718dd8 100644 --- a/src/common/open-api/__test__/EventResourceService.test.ts +++ b/integration-tests/common/EventResourceService.test.ts @@ -1,14 +1,15 @@ import { expect, describe, test } from "@jest/globals"; -import { orkesConductorClient } from "../../../orkes"; +import { orkesConductorClient } from "../../src/orkes"; describe("EventResourceService", () => { test("Should create an event handler with description and tags and then delete it", async () => { const orkesClient = await orkesConductorClient(); const eventApi = orkesClient.eventResource; + const now = Date.now(); const [eventName, event, eventDescription, eventTagKey, eventTagValue] = [ - "jsSdkTestEventName", - "jsSdkTest:eventHandler:1", + `jsSdkTest-EventName-${now}`, + `jsSdkTest:eventHandler:1${now}`, "jsSdkTestDescription", "jsSdkTestTagKey", "jsSdkTestTagValue", diff --git a/src/core/__test__/MetadataClient.test.ts b/integration-tests/common/MetadataClient.test.ts similarity index 93% rename from src/core/__test__/MetadataClient.test.ts rename to integration-tests/common/MetadataClient.test.ts index f5f6dc74..02ff50d8 100644 --- a/src/core/__test__/MetadataClient.test.ts +++ b/integration-tests/common/MetadataClient.test.ts @@ -1,10 +1,11 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { MetadataClient } from "../metadataClient"; -import { taskDefinition } from "../sdk"; -import { orkesConductorClient } from "../../orkes"; +import { MetadataClient } from "../../src/core/metadataClient"; +import { taskDefinition } from "../../src/core/sdk"; +import { orkesConductorClient } from "../../src/orkes"; describe("MetadataClient", () => { const clientPromise = orkesConductorClient(); + const taskName = `jsSdkTest-test_task_definition-${Date.now()}`; jest.setTimeout(15000); test("Should register a task definition", async () => { @@ -12,7 +13,7 @@ describe("MetadataClient", () => { const metadataClient = new MetadataClient(client); const newTaskDefinition = taskDefinition({ - name: "test_task_definition", + name: taskName, description: "New Task Definition", retryCount: 4, timeoutSeconds: 7200, @@ -62,7 +63,7 @@ describe("MetadataClient", () => { const metadataClient = new MetadataClient(client); const newTaskDefinition = taskDefinition({ - name: "test_task_definition", + name: taskName, description: "New Task Definition Update", retryCount: 5, timeoutSeconds: 7201, @@ -110,14 +111,13 @@ describe("MetadataClient", () => { test("Should unregister a task definition", async () => { const client = await clientPromise; const metadataClient = new MetadataClient(client); - const name ="test_task_definition"; await expect( - metadataClient.unregisterTask("test_task_definition") + metadataClient.unregisterTask(taskName) ).resolves.not.toThrow(); await expect(client.metadataResource.getTaskDef( - name + taskName )).rejects.toThrow(); }) }); diff --git a/src/task/__tests__/TaskManager.test.ts b/integration-tests/common/TaskManager.test.ts similarity index 78% rename from src/task/__tests__/TaskManager.test.ts rename to integration-tests/common/TaskManager.test.ts index d0fcc2ab..5f9cfbc2 100644 --- a/src/task/__tests__/TaskManager.test.ts +++ b/integration-tests/common/TaskManager.test.ts @@ -1,23 +1,25 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { simpleTask, taskDefinition, WorkflowExecutor } from "../../core"; -import { orkesConductorClient } from "../../orkes"; -import { TaskManager, ConductorWorker } from "../index"; -import { mockLogger } from "./mockLogger"; -import { TestUtil } from "../../core/__test__/utils/test-util"; +import { simpleTask, taskDefinition, WorkflowExecutor } from "../../src/core"; +import { orkesConductorClient } from "../../src/orkes"; +import { TaskManager, ConductorWorker } from "../../src/task/index"; +import { mockLogger } from "../utils/mockLogger"; +import { waitForWorkflowCompletion } from "../utils/waitForWorkflowCompletion"; -const BASE_TIME = 500; +const BASE_TIME = 1000; describe("TaskManager", () => { const clientPromise = orkesConductorClient(); - jest.setTimeout(15000); + jest.setTimeout(30000); test("Should run workflow with worker", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const taskName = `jsSdkTest-taskmanager-test-${Date.now()}`; + const workflowName = `jsSdkTest-taskmanager-test-wf-${Date.now()}`; const worker: ConductorWorker = { - taskDefName: "taskmanager-test", + taskDefName: taskName, execute: async () => { return { outputData: { @@ -34,22 +36,22 @@ describe("TaskManager", () => { manager.startPolling(); await executor.registerWorkflow(true, { - name: "TaskManagerTest", + name: workflowName, version: 1, ownerEmail: "developers@orkes.io", - tasks: [simpleTask("taskmanager-test", "taskmanager-test", {})], + tasks: [simpleTask(taskName, taskName, {})], inputParameters: [], outputParameters: {}, timeoutSeconds: 0, }); const executionId = await executor.startWorkflow({ - name: "TaskManagerTest", + name: workflowName, input: {}, version: 1, }); - const workflowStatus = await TestUtil.waitForWorkflowCompletion(executor, executionId, BASE_TIME * 4); + const workflowStatus = await waitForWorkflowCompletion(executor, executionId, BASE_TIME * 30); expect(workflowStatus.status).toEqual("COMPLETED"); @@ -59,18 +61,20 @@ describe("TaskManager", () => { test("On error it should call the errorHandler provided", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const taskName = `jsSdkTest-taskmanager-error-handler-test-${Date.now()}`; + const workflowName = `jsSdkTest-taskmanager-error-handler-test-wf-${Date.now()}`; const mockErrorHandler = jest.fn(); const worker: ConductorWorker = { - taskDefName: "taskmanager-error-handler-test-unique", + taskDefName: taskName, execute: async () => { throw new Error("This is a forced error for testing error handler"); }, }; await client.metadataResource.registerTaskDef([taskDefinition({ - name: "taskmanager-error-handler-test-unique", + name: taskName, timeoutSeconds: 0, retryCount: 0, })]); @@ -83,23 +87,23 @@ describe("TaskManager", () => { manager.startPolling(); await executor.registerWorkflow(true, { - name: "TaskManagerTestErrorHandlerUnique", + name: workflowName, version: 1, ownerEmail: "developers@orkes.io", - tasks: [simpleTask("taskmanager-error-handler-test-unique", "taskmanager-error-handler-test-unique", {})], + tasks: [simpleTask(taskName, taskName, {})], inputParameters: [], outputParameters: {}, timeoutSeconds: 0, }); const status = await executor.startWorkflow({ - name: "TaskManagerTestErrorHandlerUnique", + name: workflowName, input: {}, version: 1, - correlationId: "errorHandlerTestIdentifierUnique" + correlationId: `${workflowName}-id` }); - const workflowStatus = await TestUtil.waitForWorkflowCompletion(executor, status, BASE_TIME * 6); + const workflowStatus = await waitForWorkflowCompletion(executor, status, BASE_TIME * 30); expect(workflowStatus.status).toEqual("FAILED"); expect(mockErrorHandler).toHaveBeenCalledTimes(1); @@ -109,16 +113,18 @@ describe("TaskManager", () => { test("If no error handler provided. it should just update the task", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const taskName = `jsSdkTest-taskmanager-error-test-${Date.now()}`; + const workflowName = `jsSdkTest-taskmanager-error-test-wf-${Date.now()}`; const worker: ConductorWorker = { - taskDefName: "taskmanager-error-test", + taskDefName: taskName, execute: async () => { throw new Error("This is a forced error"); }, }; await client.metadataResource.registerTaskDef([taskDefinition({ - name: "taskmanager-error-test", + name: taskName, timeoutSeconds: 0, retryCount: 0, })]); @@ -130,23 +136,23 @@ describe("TaskManager", () => { manager.startPolling(); await executor.registerWorkflow(true, { - name: "TaskManagerTestE", + name: workflowName, version: 1, ownerEmail: "developers@orkes.io", - tasks: [simpleTask("taskmanager-error-test", "taskmanager-error-test", {})], + tasks: [simpleTask(taskName, taskName, {})], inputParameters: [], outputParameters: {}, timeoutSeconds: 0, }); const executionId = await executor.startWorkflow({ - name: "TaskManagerTestE", + name: workflowName, input: {}, version: 1, - correlationId: "noErrorHandlerProvidedIdentifier" + correlationId: `${workflowName}-id` }); - const workflowStatus = await TestUtil.waitForWorkflowCompletion(executor, executionId!, BASE_TIME * 10); + const workflowStatus = await waitForWorkflowCompletion(executor, executionId!, BASE_TIME * 30); expect(workflowStatus.status).toEqual("FAILED"); await manager.stopPolling(); }); @@ -158,7 +164,7 @@ describe("TaskManager", () => { // just create a bunch of worker names const workerNames: string[] = Array.from({ length: 3 }) .fill(0) - .map((_, i: number) => `taskman-multi-${1 + i}`); + .map((_, i: number) => `jsSdkTest-taskman-multi-${1 + i}-${Date.now()}`); // names to actual workers const workers: ConductorWorker[] = workerNames.map((name) => ({ @@ -183,7 +189,7 @@ describe("TaskManager", () => { expect(manager.isPolling).toBeTruthy(); - const workflowName = "TaskManagerTestMulti"; + const workflowName = `jsSdkTest-taskmanager-multi-test-wf-${Date.now()}`; // increase polling speed manager.updatePollingOptions({ concurrency: 4 }); @@ -203,7 +209,7 @@ describe("TaskManager", () => { const executionId = await executor.startWorkflow({ name: workflowName, version: 1, - correlationId: "identifierTaskManMulti" + correlationId: `${workflowName}-id` }); expect(executionId).toBeDefined(); @@ -211,7 +217,7 @@ describe("TaskManager", () => { // decrease speed again manager.updatePollingOptions({ pollInterval: BASE_TIME, concurrency: 1 }); - const workflowStatus = await TestUtil.waitForWorkflowCompletion(executor, executionId, BASE_TIME * 4); + const workflowStatus = await waitForWorkflowCompletion(executor, executionId, BASE_TIME * 30); expect(workflowStatus.status).toEqual("COMPLETED"); await manager.stopPolling(); @@ -233,10 +239,11 @@ describe("TaskManager", () => { test("Should not be able to startPolling if duplicate workers", async () => { const client = await clientPromise; + const workerName = `jsSdkTest-worker-name-${Date.now()}`; const workerNames: string[] = Array.from({ length: 3 }) .fill(0) - .map(() => `worker-name`); + .map(() => workerName); // names to actual workers const workers: ConductorWorker[] = workerNames.map((name) => ({ @@ -255,7 +262,7 @@ describe("TaskManager", () => { options: { pollInterval: BASE_TIME, concurrency: 2 }, }); expect(() => manager.startPolling()).toThrow( - "Duplicate worker taskDefName: worker-name" + `Duplicate worker taskDefName: ${workerName}` ); }); @@ -263,12 +270,13 @@ describe("TaskManager", () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const workerName = `jsSdkTest-taskman-single-worker-update-${Date.now()}`; // just create a bunch of worker names const workerNames: string[] = Array.from({ length: 3 }) .fill(0) - .map((_, i: number) => `taskman-single-worker-update${1 + i}`); + .map((_, i: number) => `${workerName}-${1 + i}`); - const candidateWorkerUpdate = "taskman-single-worker-update1"; + const candidateWorkerUpdate = `${workerName}-1`; const initialCandidateWorkflowOptions = { concurrency: 1, pollInterval: BASE_TIME * 3, @@ -300,7 +308,7 @@ describe("TaskManager", () => { expect(manager.isPolling).toBeTruthy(); - const workflowName = "TaskManagerTestMultiSingleWorkerUpdate"; + const workflowName = `jsSdkTest-taskmanager-multi-single-worker-update-wf-${Date.now()}`; const updatedWorkerOptions = { concurrency: 3, @@ -328,14 +336,14 @@ describe("TaskManager", () => { const executionId = await executor.startWorkflow({ name: workflowName, version: 1, - correlationId: "identifierTaskManMulti" + correlationId: `${workflowName}-id` }); expect(executionId).toBeDefined(); // decrease speed again manager.updatePollingOptions({ pollInterval: BASE_TIME, concurrency: 1 }); - const workflowStatus = await TestUtil.waitForWorkflowCompletion(executor, executionId, BASE_TIME * 10); + const workflowStatus = await waitForWorkflowCompletion(executor, executionId, BASE_TIME * 30); expect(workflowStatus.status).toEqual("COMPLETED"); await manager.stopPolling(); diff --git a/src/task/__tests__/TaskRunnerIntTest.test.ts b/integration-tests/common/TaskRunnerIntTest.test.ts similarity index 71% rename from src/task/__tests__/TaskRunnerIntTest.test.ts rename to integration-tests/common/TaskRunnerIntTest.test.ts index 7a42404d..60439722 100644 --- a/src/task/__tests__/TaskRunnerIntTest.test.ts +++ b/integration-tests/common/TaskRunnerIntTest.test.ts @@ -1,7 +1,8 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { TaskRunner } from "../TaskRunner"; -import { WorkflowExecutor, simpleTask } from "../../core"; -import { orkesConductorClient } from "../../orkes"; +import { TaskRunner } from "../../src/task/TaskRunner"; +import { WorkflowExecutor, simpleTask } from "../../src/core"; +import { orkesConductorClient } from "../../src/orkes"; +import { waitForWorkflowStatus } from "../utils/waitForWorkflowStatus"; describe("TaskManager", () => { const clientPromise = orkesConductorClient(); @@ -10,11 +11,13 @@ describe("TaskManager", () => { test("worker example ", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const taskName = `jsSdkTest-task-manager-int-test-${Date.now()}`; + const workflowName = `jsSdkTest-task-manager-int-test-wf-${Date.now()}`; const taskRunner = new TaskRunner({ taskResource: client.taskResource, worker: { - taskDefName: "task-manager-int-test", + taskDefName: taskName, execute: async () => { return { outputData: { @@ -34,12 +37,12 @@ describe("TaskManager", () => { taskRunner.startPolling(); expect(taskRunner.isPolling).toEqual(true); - const workflowName = "task-manager-int-test-wf"; + await executor.registerWorkflow(true, { name: workflowName, version: 1, ownerEmail: "developers@orkes.io", - tasks: [simpleTask("task-manager-int-test", "task-manager-int-test", {})], + tasks: [simpleTask(taskName, taskName, {})], inputParameters: [], outputParameters: {}, timeoutSeconds: 0, @@ -52,16 +55,16 @@ describe("TaskManager", () => { }, workflowName, 1, - "RunnerIdentifier" + `${workflowName}-id` ); expect(executionId).toBeDefined(); taskRunner.updateOptions({ concurrency: 1, pollInterval: 100 }); - const workflowStatus = await executor.getWorkflow(executionId!, true); + const workflowStatus = await waitForWorkflowStatus(executor, executionId!, "COMPLETED"); const [firstTask] = workflowStatus.tasks || []; - expect(firstTask?.taskType).toEqual("task-manager-int-test"); + expect(firstTask?.taskType).toEqual(taskName); expect(workflowStatus.status).toEqual("COMPLETED"); await taskRunner.stopPolling(); diff --git a/src/common/open-api/__test__/WorkflowResourceService.test.ts b/integration-tests/common/WorkflowResourceService.test.ts similarity index 74% rename from src/common/open-api/__test__/WorkflowResourceService.test.ts rename to integration-tests/common/WorkflowResourceService.test.ts index 54235d51..d0d28190 100644 --- a/src/common/open-api/__test__/WorkflowResourceService.test.ts +++ b/integration-tests/common/WorkflowResourceService.test.ts @@ -1,8 +1,8 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { MetadataClient } from "../../../core"; -import { simpleTask, workflow } from "../../../core/sdk"; -import { orkesConductorClient } from "../../../orkes"; -import { TaskDefTypes } from "../../types"; +import { MetadataClient } from "../../src/core"; +import { simpleTask, workflow } from "../../src/core/sdk"; +import { orkesConductorClient } from "../../src/orkes"; +import { TaskDefTypes } from "../../src/common/types"; describe("WorkflowResourceService", () => { jest.setTimeout(120000); @@ -14,7 +14,7 @@ describe("WorkflowResourceService", () => { simpleTask("simple_ref", "le_simple_task", {}), ]; - const wfDef = workflow("unit_test_wf", tasks); + const wfDef = workflow(`jsSdkTest-test_wf-${Date.now()}`, tasks); wfDef.outputParameters = { message: "${simple_ref.output.message}" }; metadataClient.registerWorkflowDef(wfDef, true); diff --git a/integration-tests/common/executor.test.ts b/integration-tests/common/executor.test.ts new file mode 100644 index 00000000..feabb593 --- /dev/null +++ b/integration-tests/common/executor.test.ts @@ -0,0 +1,172 @@ +import {expect, describe, test, jest} from "@jest/globals"; +import { SetVariableTaskDef, TaskType, WorkflowDef} from "../../src/common"; +import { orkesConductorClient } from "../../src/orkes"; +import { WorkflowExecutor } from "../../src/core/executor"; +import { v4 as uuidv4 } from "uuid"; +import { waitForWorkflowStatus } from "../utils/waitForWorkflowStatus"; +import { httpTask } from "../../src/core/sdk"; +import { TaskClient } from "../../src/core/taskClient"; + +describe("Executor", () => { + const clientPromise = orkesConductorClient(); + + jest.setTimeout(15000); + const name = `jsSdkTest-Workflow-${Date.now()}`; + const version = 1; + test("Should be able to register a workflow", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + + const workflowDefinition: WorkflowDef = { + name, + version, + tasks: [ + { + type: TaskType.SET_VARIABLE, + name: "setVariable", + taskReferenceName: "httpTaskRef", + inputParameters: { + hello: "world", + }, + }, + ], + inputParameters: [], + timeoutSeconds: 15, + }; + + await expect( + executor.registerWorkflow(true, workflowDefinition) + ).resolves.not.toThrow(); + const workflowDefinitionFromApi = await client.metadataResource.get( + name, + version + ); + expect(workflowDefinitionFromApi.name).toEqual(name); + expect(workflowDefinitionFromApi.version).toEqual(version); + expect(workflowDefinitionFromApi.tasks[0].name).toEqual( + workflowDefinition.tasks[0].name + ); + expect(workflowDefinitionFromApi.tasks[0].taskReferenceName).toEqual( + workflowDefinition.tasks[0].taskReferenceName + ); + expect(workflowDefinitionFromApi.tasks[0].inputParameters).toEqual( + (workflowDefinition.tasks[0] as SetVariableTaskDef).inputParameters + ); + }); + + let executionId: string | undefined = undefined; + test("Should be able to start a workflow", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + executionId = await executor.startWorkflow({ name, version }); + expect(executionId).toBeTruthy(); + }); + + test("Should be able to execute workflow synchronously", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + const workflowRun = await executor.executeWorkflow( + { + name: name, + version: version, + }, + name, + version, + uuidv4() + ); + expect(workflowRun.status).toEqual("COMPLETED"); + }); + + test("Should be able to get workflow execution status ", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + const workflowStatus = await executor.getWorkflowStatus( + executionId!, + true, + true + ); + expect(workflowStatus.status).toBeTruthy(); + }); + + test("Should return workflow status detail", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + const workflowStatus = await executor.getWorkflow(executionId!, true); + + expect(workflowStatus.status).toBeTruthy(); + expect(workflowStatus.tasks?.length).toBe(1); + }); + test("Should execute a workflow with indempotency key", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + const idempotencyKey = uuidv4(); + const executionId = await executor.startWorkflow({ + name: name, + version: version, + idempotencyKey, + idempotencyStrategy: "RETURN_EXISTING", + }); + + const executionDetails = await executor.getWorkflow(executionId!, true); + expect(executionDetails.idempotencyKey).toEqual(idempotencyKey); + }); + + test("Should run workflow with http task with asyncComplete true", async () => { + const client = await clientPromise; + const executor = new WorkflowExecutor(client); + const workflowName = `jsSdkTest-wf_with_asyncComplete_http_task-${Date.now()}`; + const taskName = `jsSdkTest-http_task_with_asyncComplete_true-${Date.now()}`; + + await executor.registerWorkflow(true, { + name: workflowName, + version: 1, + ownerEmail: "developers@orkes.io", + tasks: [httpTask(taskName, { uri: "http://www.yahoo.com", method: "GET" }, true)], + inputParameters: [], + outputParameters: {}, + timeoutSeconds: 300, + }); + + const executionId = await executor.startWorkflow({ + name: workflowName, + input: {}, + version: 1, + }); + + const workflowStatusBefore = await waitForWorkflowStatus(executor, executionId, "RUNNING"); + + expect(["IN_PROGRESS", "SCHEDULED"]).toContain(workflowStatusBefore.tasks?.[0]?.status); + + const taskClient = new TaskClient(client); + taskClient.updateTaskResult(executionId, taskName, "COMPLETED", { hello: "From manuall api call updating task result" }); + + const workflowStatusAfter = await waitForWorkflowStatus(executor, executionId, "COMPLETED"); + + expect(workflowStatusAfter.tasks?.[0]?.status).toEqual("COMPLETED"); + }); + + test("Should run workflow with an optional http task", async () => { + const executor = new WorkflowExecutor(await clientPromise); + const workflowName = `jsSdkTest-wf_with_optional_http_task-${Date.now()}`; + const taskName = `jsSdkTest-optional_http_task-${Date.now()}`; + + await executor.registerWorkflow(true, { + name: workflowName, + version: 1, + ownerEmail: "developers@orkes.io", + tasks: [httpTask(taskName, { uri: "uncorrect_uri", method: "GET" }, false, true)], + inputParameters: [], + outputParameters: {}, + timeoutSeconds: 300, + }); + + const executionId = await executor.startWorkflow({ + name: workflowName, + input: {}, + version: 1, + }); + + const workflowStatus = await waitForWorkflowStatus(executor, executionId, "COMPLETED"); + expect(["FAILED", "COMPLETED_WITH_ERRORS"]).toContain(workflowStatus.tasks?.[0]?.status); + }); +}); diff --git a/src/__test__/readme.test.ts b/integration-tests/common/readme.test.ts similarity index 76% rename from src/__test__/readme.test.ts rename to integration-tests/common/readme.test.ts index 613fab76..501f283f 100644 --- a/src/__test__/readme.test.ts +++ b/integration-tests/common/readme.test.ts @@ -1,8 +1,9 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { orkesConductorClient } from "../orkes"; -import { WorkflowExecutor, simpleTask, generate } from "../core"; -import { TaskType } from "../common"; -import { TaskRunner } from "../task"; +import { orkesConductorClient } from "../../src/orkes"; +import { WorkflowExecutor, simpleTask, generate } from "../../src/core"; +import { TaskType } from "../../src/common"; +import { TaskRunner } from "../../src/task"; +import { waitForWorkflowStatus } from "../utils/waitForWorkflowStatus"; describe("TaskManager", () => { const clientPromise = orkesConductorClient(); @@ -11,11 +12,13 @@ describe("TaskManager", () => { test("worker example ", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); + const workflowName = `jsSdkTest-my_first_js_wf-${Date.now()}`; + const taskName = `jsSdkTest-taskmanager-test-${Date.now()}`; const taskRunner = new TaskRunner({ taskResource: client.taskResource, worker: { - taskDefName: "taskmanager-test", + taskDefName: taskName, execute: async () => { return { outputData: { @@ -34,26 +37,27 @@ describe("TaskManager", () => { }); taskRunner.startPolling(); + await executor.registerWorkflow(true, { - name: "my_first_js_wf", + name: workflowName, version: 1, ownerEmail: "developers@orkes.io", - tasks: [simpleTask("taskmanager-test", "taskmanager-test", {})], + tasks: [simpleTask(taskName, taskName, {})], inputParameters: [], outputParameters: {}, timeoutSeconds: 0, }); const executionId = await executor.startWorkflow({ - name: "my_first_js_wf", + name: workflowName, input: {}, version: 1, }); - await new Promise((r) => setTimeout(() => r(true), 900)); - const workflowStatus = await executor.getWorkflow(executionId, true); + + const workflowStatus = await waitForWorkflowStatus(executor, executionId, "COMPLETED"); const [firstTask] = workflowStatus.tasks || []; - expect(firstTask?.taskType).toEqual("taskmanager-test"); + expect(firstTask?.taskType).toEqual(taskName); expect(workflowStatus.status).toEqual("COMPLETED"); taskRunner.stopPolling(); @@ -64,9 +68,9 @@ describe("TaskManager", () => { test("update task example ", async () => { const client = await clientPromise; const executor = new WorkflowExecutor(client); - const waitTaskReference = "wait_task_ref"; + const waitTaskReference = `jsSdkTest-wait_task_ref-${Date.now()}`; const workflowWithWaitTask = generate({ - name: "waitTaskWf", + name: `jsSdkTest-waitTaskWf-${Date.now()}`, tasks: [{ type: TaskType.WAIT, taskReferenceName: waitTaskReference }], }); await executor.registerWorkflow(true, workflowWithWaitTask); @@ -79,7 +83,7 @@ describe("TaskManager", () => { }, workflowWithWaitTask.name, 1, - "someId" + `${workflowWithWaitTask.name}-id` ); const workflowStatus = await executor.getWorkflow(executionId!, true); @@ -113,13 +117,15 @@ describe("TaskManager", () => { //Create new workflow executor const executor = new WorkflowExecutor(client); + const taskName = `jsSdkTest-sum_two_numbers-task-${Date.now()}`; + const workflowName = `jsSdkTest-sumTwoNumbersWf-${Date.now()}`; // Create a workflow const sumTwoNumbers = generate({ - name: "sumTwoNumbers", + name: workflowName, tasks: [ { - name: "sum_two_numbers", + name: taskName, inputParameters: { numberOne: "${workflow.input.numberOne}", numberTwo: "${workflow.input.numberTwo}", @@ -135,7 +141,7 @@ describe("TaskManager", () => { ], inputParameters: ["numberOne", "numberTwo"], outputParameters: { - result: "${sum_two_numbers_ref.output.result}", + result: `\${${taskName}_ref.output.result}`, }, }); @@ -153,10 +159,10 @@ describe("TaskManager", () => { }, sumTwoNumbers.name, 1, - "workflowSummTwoNumbers" + `workflow${sumTwoNumbers.name}` ); - const workflowStatus = await executor.getWorkflow(executionId!, true); + const workflowStatus = await waitForWorkflowStatus(executor, executionId!, "COMPLETED"); expect(workflowStatus.status).toEqual("COMPLETED"); expect(workflowStatus.output?.result).toEqual(3); diff --git a/src/core/__test__/schedulerExecutor.test.ts b/integration-tests/common/schedulerExecutor.test.ts similarity index 93% rename from src/core/__test__/schedulerExecutor.test.ts rename to integration-tests/common/schedulerExecutor.test.ts index 4cc5b444..ccf847d2 100644 --- a/src/core/__test__/schedulerExecutor.test.ts +++ b/integration-tests/common/schedulerExecutor.test.ts @@ -1,16 +1,17 @@ import { expect, describe, test, jest } from "@jest/globals"; -import { orkesConductorClient } from "../../orkes"; -import { SchedulerClient } from "../schedulerClient"; -import { SaveScheduleRequest, TaskType, WorkflowDef } from "../../common"; +import { orkesConductorClient } from "../../src/orkes"; +import { SchedulerClient } from "../../src/core/schedulerClient"; +import { SaveScheduleRequest, TaskType, WorkflowDef } from "../../src/common"; describe("ScheduleExecutor", () => { const clientPromise = orkesConductorClient(); jest.setTimeout(15000); - const name = `testSchedule_${Date.now()}`; + const now = Date.now(); + const name = `jsSdkTestSchedule_${now}`; const cronExpression = "0/5 * * ? * *"; //every 5 second - const workflowName = `testScheduleWf_${Date.now()}`; + const workflowName = `jsSdkTestScheduleWf_${now}`; const workflowVersion = 1; test("Should be able to register a workflow and retrieve it", async () => { diff --git a/src/task/__tests__/mockLogger.ts b/integration-tests/utils/mockLogger.ts similarity index 68% rename from src/task/__tests__/mockLogger.ts rename to integration-tests/utils/mockLogger.ts index e5d8b7d8..c5011ae2 100644 --- a/src/task/__tests__/mockLogger.ts +++ b/integration-tests/utils/mockLogger.ts @@ -1,5 +1,5 @@ import {jest} from "@jest/globals" -import {ConductorLogger} from "../../common/ConductorLogger" +import {ConductorLogger} from "../../src/common/ConductorLogger" export const mockLogger: ConductorLogger = { debug: jest.fn(), diff --git a/integration-tests/utils/waitForWorkflowCompletion.ts b/integration-tests/utils/waitForWorkflowCompletion.ts new file mode 100644 index 00000000..63a1e9b1 --- /dev/null +++ b/integration-tests/utils/waitForWorkflowCompletion.ts @@ -0,0 +1,44 @@ +import type { WorkflowExecutor } from "../../src/core/executor"; + +// Helper function to wait for workflow completion +export const waitForWorkflowCompletion = async ( + executor: WorkflowExecutor, + workflowId: string, + maxWaitMs: number = 300000, // 5 minutes default + pollIntervalMs: number = 100 // 100ms default +) => { + const startTime = Date.now(); + + while (Date.now() - startTime < maxWaitMs) { + try { + const workflowStatus = await executor.getWorkflow(workflowId, true); + + // Check if workflow is in a terminal state + if ( + ["COMPLETED", "FAILED", "TERMINATED", "TIMED_OUT"].includes( + workflowStatus.status! + ) + ) { + console.debug( + `Workflow ${workflowId} reached terminal state: ${workflowStatus.status}` + ); + return workflowStatus; + } + + console.debug( + `Workflow ${workflowId} status: ${workflowStatus.status}, waiting...` + ); + + // Wait before next poll + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); + } catch (error) { + console.warn(`Error checking workflow status for ${workflowId}:`, error); + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); + } + } + + throw new Error( + `Workflow ${workflowId} did not complete within ${maxWaitMs}ms` + ); +}; + diff --git a/integration-tests/utils/waitForWorkflowStatus.ts b/integration-tests/utils/waitForWorkflowStatus.ts new file mode 100644 index 00000000..9b65225c --- /dev/null +++ b/integration-tests/utils/waitForWorkflowStatus.ts @@ -0,0 +1,36 @@ +/** + * Wait for workflow to reach expected status + */ +export const waitForWorkflowStatus = async ( + workflowClient: any, + workflowId: string, + expectedStatus: string, + maxWaitTimeMs: number = 15000, + pollIntervalMs: number = 1000 +): Promise => { + const startTime = Date.now(); + + while (Date.now() - startTime < maxWaitTimeMs) { + try { + const workflow = await workflowClient.getWorkflow(workflowId, true); + + if (workflow.status === expectedStatus) { + return workflow; + } + + if (workflow.status === "FAILED" || workflow.status === "TERMINATED") { + throw new Error( + `Workflow ended in unexpected state: ${workflow.status}` + ); + } + + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); + } catch (error) { + throw new Error(`Failed to get workflow status: ${error}`); + } + } + + throw new Error( + `Workflow did not reach status ${expectedStatus} within ${maxWaitTimeMs}ms` + ); +}; diff --git a/src/core/__test__/ServiceRegistryClient.test.ts b/integration-tests/v5-only/ServiceRegistryClient.test.ts similarity index 94% rename from src/core/__test__/ServiceRegistryClient.test.ts rename to integration-tests/v5-only/ServiceRegistryClient.test.ts index d2827a2e..caab62fb 100644 --- a/src/core/__test__/ServiceRegistryClient.test.ts +++ b/integration-tests/v5-only/ServiceRegistryClient.test.ts @@ -1,7 +1,7 @@ import {beforeAll, afterEach, describe, expect, jest, test} from "@jest/globals"; -import {ServiceRegistryClient} from "../serviceRegistryClient"; -import {orkesConductorClient} from "../../orkes"; -import {ServiceType} from "../../common/open-api/models/ServiceRegistryModels"; +import {ServiceRegistryClient} from "../../src/core/serviceRegistryClient"; +import {orkesConductorClient} from "../../src/orkes"; +import {ServiceType} from "../../src/common/open-api/models/ServiceRegistryModels"; import * as fs from 'fs'; import * as path from 'path'; @@ -33,7 +33,7 @@ describe("ServiceRegistryClient", () => { test("Should add and retrieve a service registry", async () => { // Create a test service registry const testServiceRegistry = { - name: "test_service_registry", + name: `jsSdkTest-test_service_registry${Date.now()}`, type: ServiceType.HTTP, serviceURI: "http://httpbin:8081/api-docs", config: { @@ -87,7 +87,7 @@ describe("ServiceRegistryClient", () => { test("Should add and remove a service registry", async () => { // Create a test service registry const testServiceRegistry = { - name: "test_service_registry_to_remove", + name: `jsSdkTest-test_service_registry_to_remove-${Date.now()}`, type: ServiceType.HTTP, serviceURI: "http://httpbin:8081/api-docs" }; @@ -119,7 +119,7 @@ describe("ServiceRegistryClient", () => { test("Should add a service method to a registry", async () => { // Create a test service registry const testServiceRegistry = { - name: "test_service_registry_with_method", + name: `jsSdkTest-test_service_registry_with_method-${Date.now()}`, type: ServiceType.HTTP, serviceURI: "http://httpbin:8081/api-docs" }; @@ -173,7 +173,7 @@ describe("ServiceRegistryClient", () => { test("Should discover methods from a http service", async () => { // Create a test service registry for discovery const testServiceRegistry = { - name: "test_service_registry_discovery", + name: `jsSdkTest-test_service_registry_discovery-${Date.now()}`, type: ServiceType.HTTP, serviceURI: "http://httpbin:8081/api-docs" }; @@ -206,7 +206,7 @@ describe("ServiceRegistryClient", () => { test("Should discover methods from a gRPC service", async () => { // Create a test service registry for discovery const testServiceRegistry = { - name: "test_gRPC_service_registry_discovery", + name: `jsSdkTest-test_gRPC_service_registry_discovery-${Date.now()}`, type: ServiceType.gRPC, serviceURI: "grpcbin:50051" }; diff --git a/src/core/__test__/executor.test.ts b/integration-tests/v5-only/executor.test.ts similarity index 64% rename from src/core/__test__/executor.test.ts rename to integration-tests/v5-only/executor.test.ts index 2d256353..32116b96 100644 --- a/src/core/__test__/executor.test.ts +++ b/integration-tests/v5-only/executor.test.ts @@ -1,182 +1,25 @@ import {expect, describe, test, jest, beforeAll, afterEach, afterAll} from "@jest/globals"; -import {Consistency, ReturnStrategy, SetVariableTaskDef, TaskType, WorkflowDef} from "../../common"; -import { orkesConductorClient } from "../../orkes"; -import { WorkflowExecutor } from "../executor"; +import {Consistency, ReturnStrategy} from "../../src/common"; +import { orkesConductorClient } from "../../src/orkes"; +import { WorkflowExecutor } from "../../src/core/executor"; import { v4 as uuidv4 } from "uuid"; -import {MetadataClient} from "../metadataClient"; -import {TestUtil} from "./utils/test-util"; -import {TaskResultStatusEnum} from "../../common/open-api/models/TaskResultStatusEnum"; -import {SignalResponse} from "../../common/open-api/models/SignalResponse"; -import { httpTask } from "../sdk"; -import { TaskClient } from "../taskClient"; - -describe("Executor", () => { - const clientPromise = orkesConductorClient(); - - jest.setTimeout(15000); - const name = `testWorkflow-${Date.now()}`; - const version = 1; - test("Should be able to register a workflow", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - - const workflowDefinition: WorkflowDef = { - name, - version, - tasks: [ - { - type: TaskType.SET_VARIABLE, - name: "setVariable", - taskReferenceName: "httpTaskRef", - inputParameters: { - hello: "world", - }, - }, - ], - inputParameters: [], - timeoutSeconds: 15, - }; - - await expect( - executor.registerWorkflow(true, workflowDefinition) - ).resolves.not.toThrow(); - const workflowDefinitionFromApi = await client.metadataResource.get( - name, - version - ); - expect(workflowDefinitionFromApi.name).toEqual(name); - expect(workflowDefinitionFromApi.version).toEqual(version); - expect(workflowDefinitionFromApi.tasks[0].name).toEqual( - workflowDefinition.tasks[0].name - ); - expect(workflowDefinitionFromApi.tasks[0].taskReferenceName).toEqual( - workflowDefinition.tasks[0].taskReferenceName - ); - expect(workflowDefinitionFromApi.tasks[0].inputParameters).toEqual( - (workflowDefinition.tasks[0] as SetVariableTaskDef).inputParameters - ); - }); - - let executionId: string | undefined = undefined; - test("Should be able to start a workflow", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - executionId = await executor.startWorkflow({ name, version }); - expect(executionId).toBeTruthy(); - }); - - test("Should be able to execute workflow synchronously", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - const workflowRun = await executor.executeWorkflow( - { - name: name, - version: version, - }, - name, - version, - uuidv4() - ); - expect(workflowRun.status).toEqual("COMPLETED"); - }); - - test("Should be able to get workflow execution status ", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - const workflowStatus = await executor.getWorkflowStatus( - executionId!, - true, - true - ); - expect(workflowStatus.status).toBeTruthy(); - }); - - test("Should return workflow status detail", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - const workflowStatus = await executor.getWorkflow(executionId!, true); - - expect(workflowStatus.status).toBeTruthy(); - expect(workflowStatus.tasks?.length).toBe(1); - }); - test("Should execute a workflow with indempotency key", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - const idempotencyKey = uuidv4(); - const executionId = await executor.startWorkflow({ - name: name, - version: version, - idempotencyKey, - idempotencyStrategy: "RETURN_EXISTING", - }); - - const executionDetails = await executor.getWorkflow(executionId!, true); - expect(executionDetails.idempotencyKey).toEqual(idempotencyKey); - }); - - test("Should run workflow with http task with asyncComplete true", async () => { - const client = await clientPromise; - const executor = new WorkflowExecutor(client); - - await executor.registerWorkflow(true, { - name: "test_jssdk_workflow_with_http_task_with_asyncComplete_true", - version: 1, - ownerEmail: "developers@orkes.io", - tasks: [httpTask("test_jssdk_http_task_with_asyncComplete_true", { uri: "http://www.yahoo.com", method: "GET" }, true)], - inputParameters: [], - outputParameters: {}, - timeoutSeconds: 300, - }); - - const executionId = await executor.startWorkflow({ - name: "test_jssdk_workflow_with_http_task_with_asyncComplete_true", - input: {}, - version: 1, - }); - - const workflowStatusBefore = await TestUtil.waitForWorkflowStatus(executor, executionId, "RUNNING"); - - expect(["IN_PROGRESS", "SCHEDULED"]).toContain(workflowStatusBefore.tasks?.[0]?.status); - - const taskClient = new TaskClient(client); - taskClient.updateTaskResult(executionId, "test_jssdk_http_task_with_asyncComplete_true", "COMPLETED", { hello: "From manuall api call updating task result" }); - - const workflowStatusAfter = await TestUtil.waitForWorkflowStatus(executor, executionId, "COMPLETED"); - - expect(workflowStatusAfter.tasks?.[0]?.status).toEqual("COMPLETED"); - }); - - test("Should run workflow with an optional http task", async () => { - const executor = new WorkflowExecutor(await clientPromise); - - await executor.registerWorkflow(true, { - name: "test_jssdk_workflow_with_optional_http_task", - version: 1, - ownerEmail: "developers@orkes.io", - tasks: [httpTask("test_jssdk_optional_http_task", { uri: "uncorrect_uri", method: "GET" }, false, true)], - inputParameters: [], - outputParameters: {}, - timeoutSeconds: 300, - }); - - const executionId = await executor.startWorkflow({ - name: "test_jssdk_workflow_with_optional_http_task", - input: {}, - version: 1, - }); - - const workflowStatus = await TestUtil.waitForWorkflowStatus(executor, executionId, "COMPLETED"); - expect(["FAILED", "COMPLETED_WITH_ERRORS"]).toContain(workflowStatus.tasks?.[0]?.status); - }); -}); +import {MetadataClient} from "../../src/core/metadataClient"; +import {waitForWorkflowStatus} from "../utils/waitForWorkflowStatus"; +import {TaskResultStatusEnum} from "../../src/common/open-api/models/TaskResultStatusEnum"; +import {SignalResponse} from "../../src/common/open-api/models/SignalResponse"; +import { getComplexSignalTestWfDef } from "./metadata/complex_wf_signal_test"; +import { getComplexSignalTestSubWf1Def } from "./metadata/complex_wf_signal_test_subworkflow_1"; +import { getComplexSignalTestSubWf2Def } from "./metadata/complex_wf_signal_test_subworkflow_2"; +import { getWaitSignalTestWfDef } from "./metadata/wait_signal_test"; describe("Execute with Return Strategy and Consistency", () => { // Constants specific to this test suite - const WORKFLOW_NAMES = { - COMPLEX_WF: 'complex_wf_signal_test', - SUB_WF_1: 'complex_wf_signal_test_subworkflow_1', - SUB_WF_2: 'complex_wf_signal_test_subworkflow_2', - WAIT_SIGNAL_TEST: 'wait_signal_test' + const now = Date.now(); + const WORKFLOWS = { + COMPLEX_WF: getComplexSignalTestWfDef(now), + SUB_WF_1: getComplexSignalTestSubWf1Def(now), + SUB_WF_2: getComplexSignalTestSubWf2Def(now), + WAIT_SIGNAL_TEST: getWaitSignalTestWfDef(now) }; const clientPromise = orkesConductorClient(); @@ -192,7 +35,6 @@ describe("Execute with Return Strategy and Consistency", () => { client = await clientPromise; executor = new WorkflowExecutor(client); metadataClient = new MetadataClient(client); - TestUtil.setMetadataClient(metadataClient); // Register all test workflows await registerAllWorkflows(); @@ -225,15 +67,15 @@ describe("Execute with Return Strategy and Consistency", () => { async function registerAllWorkflows(): Promise { try { await Promise.all([ - TestUtil.registerWorkflow(WORKFLOW_NAMES.COMPLEX_WF), - TestUtil.registerWorkflow(WORKFLOW_NAMES.SUB_WF_1), - TestUtil.registerWorkflow(WORKFLOW_NAMES.SUB_WF_2), - TestUtil.registerWorkflow(WORKFLOW_NAMES.WAIT_SIGNAL_TEST) + metadataClient.registerWorkflowDef(WORKFLOWS.COMPLEX_WF, true), + metadataClient.registerWorkflowDef(WORKFLOWS.SUB_WF_1, true), + metadataClient.registerWorkflowDef(WORKFLOWS.SUB_WF_2, true), + metadataClient.registerWorkflowDef(WORKFLOWS.WAIT_SIGNAL_TEST, true) ]); // Add to cleanup list - Object.values(WORKFLOW_NAMES).forEach(name => { - workflowsToCleanup.push({name, version: 1}); + Object.values(WORKFLOWS).forEach(workflow => { + workflowsToCleanup.push({name: workflow.name, version: 1}); }); console.log('✓ All workflows registered successfully'); @@ -244,7 +86,7 @@ describe("Execute with Return Strategy and Consistency", () => { async function cleanupAllWorkflows(): Promise { const cleanupPromises = workflowsToCleanup.map(({name, version}) => - TestUtil.unregisterWorkflow(name, version) + metadataClient.unregisterWorkflow(name, version) ); const results = await Promise.allSettled(cleanupPromises); @@ -327,8 +169,8 @@ describe("Execute with Return Strategy and Consistency", () => { // 1. Execute workflow with return strategy const rawResult = await executor.executeWorkflow( - { name: WORKFLOW_NAMES.COMPLEX_WF, version: 1 }, - WORKFLOW_NAMES.COMPLEX_WF, + { name: WORKFLOWS.COMPLEX_WF.name, version: 1 }, + WORKFLOWS.COMPLEX_WF.name, 1, uuidv4(), "", // waitUntilTaskRef @@ -454,7 +296,7 @@ describe("Execute with Return Strategy and Consistency", () => { ); // Wait for workflow completion - const finalWorkflow = await TestUtil.waitForWorkflowStatus( + const finalWorkflow = await waitForWorkflowStatus( executor, workflowId, 'COMPLETED', @@ -473,8 +315,8 @@ describe("Execute with Return Strategy and Consistency", () => { // Execute workflow const rawResult = await executor.executeWorkflow( - { name: WORKFLOW_NAMES.COMPLEX_WF, version: 1 }, - WORKFLOW_NAMES.COMPLEX_WF, + { name: WORKFLOWS.COMPLEX_WF.name, version: 1 }, + WORKFLOWS.COMPLEX_WF.name, 1, uuidv4(), "", @@ -532,7 +374,7 @@ describe("Execute with Return Strategy and Consistency", () => { await executor.signal(workflowId, TaskResultStatusEnum.COMPLETED, { result: "signal1" }); await executor.signal(workflowId, TaskResultStatusEnum.COMPLETED, { result: "signal2" }); - await TestUtil.waitForWorkflowStatus(executor, workflowId, 'COMPLETED', 300000, 200); + await waitForWorkflowStatus(executor, workflowId, 'COMPLETED', 300000, 200); console.log(`✓ ${testCase.name} test completed successfully`); }); }); diff --git a/src/core/__test__/metadata/compiled.bin b/integration-tests/v5-only/metadata/compiled.bin similarity index 100% rename from src/core/__test__/metadata/compiled.bin rename to integration-tests/v5-only/metadata/compiled.bin diff --git a/integration-tests/v5-only/metadata/complex_wf_signal_test.ts b/integration-tests/v5-only/metadata/complex_wf_signal_test.ts new file mode 100644 index 00000000..954cfee8 --- /dev/null +++ b/integration-tests/v5-only/metadata/complex_wf_signal_test.ts @@ -0,0 +1,67 @@ +export const getComplexSignalTestWfDef = (date: number) => { + return { + createTime: 1744299182957, + updateTime: 1744299435683, + name: `complex_wf_signal_test_${date}`, + description: "http_yield_signal_test", + version: 1, + tasks: [ + { + name: "http", + taskReferenceName: "http_ref", + inputParameters: { + uri: "http://httpbin:8081/api/hello?name=test1", + method: "GET", + accept: "application/json", + contentType: "application/json", + encode: true, + }, + type: "HTTP", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + { + name: "sub_workflow", + taskReferenceName: "sub_workflow_ref", + inputParameters: {}, + type: "SUB_WORKFLOW", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + subWorkflowParam: { + name: `complex_wf_signal_test_subworkflow_1_${date}`, + version: 1, + }, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + ], + inputParameters: [], + outputParameters: {}, + failureWorkflow: "", + schemaVersion: 2, + restartable: true, + workflowStatusListenerEnabled: false, + ownerEmail: "shailesh.padave@orkes.io", + timeoutPolicy: "ALERT_ONLY" as const, + timeoutSeconds: 0, + variables: {}, + inputTemplate: {}, + enforceSchema: true, + }; +}; diff --git a/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_1.ts b/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_1.ts new file mode 100644 index 00000000..b7e4cc2b --- /dev/null +++ b/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_1.ts @@ -0,0 +1,84 @@ +export const getComplexSignalTestSubWf1Def = (date: number) => { + return { + createTime: 1744299356718, + updateTime: 1744287643769, + name: `complex_wf_signal_test_subworkflow_1_${date}`, + description: `complex_wf_signal_test_subworkflow_${date}`, + version: 1, + tasks: [ + { + name: "http", + taskReferenceName: "http_ref", + inputParameters: { + uri: "http://httpbin:8081/api/hello?name=test1", + method: "GET", + accept: "application/json", + contentType: "application/json", + encode: true, + }, + type: "HTTP", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + { + name: "yield", + taskReferenceName: "simple_ref_1", + inputParameters: {}, + type: "YIELD", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + { + name: "sub_workflow", + taskReferenceName: "sub_workflow_ref", + inputParameters: {}, + type: "SUB_WORKFLOW", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + subWorkflowParam: { + name: `complex_wf_signal_test_subworkflow_2_${date}`, + version: 1, + }, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + ], + inputParameters: [], + outputParameters: {}, + failureWorkflow: "", + schemaVersion: 2, + restartable: true, + workflowStatusListenerEnabled: false, + ownerEmail: "shailesh.padave@orkes.io", + timeoutPolicy: "ALERT_ONLY" as const, + timeoutSeconds: 0, + variables: {}, + inputTemplate: {}, + enforceSchema: true, + }; +}; diff --git a/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_2.ts b/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_2.ts new file mode 100644 index 00000000..56c5d8b2 --- /dev/null +++ b/integration-tests/v5-only/metadata/complex_wf_signal_test_subworkflow_2.ts @@ -0,0 +1,63 @@ +export const getComplexSignalTestSubWf2Def = (date: number) => { + return { + createTime: 1744299371396, + updateTime: 0, + name: `complex_wf_signal_test_subworkflow_2_${date}`, + description: `complex_wf_signal_test_subworkflow_${date}`, + version: 1, + tasks: [ + { + name: "http", + taskReferenceName: "http_ref", + inputParameters: { + uri: "http://httpbin:8081/api/hello?name=test1", + method: "GET", + accept: "application/json", + contentType: "application/json", + encode: true, + }, + type: "HTTP", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + { + name: "yield", + taskReferenceName: "simple_ref_1", + inputParameters: {}, + type: "YIELD", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + ], + inputParameters: [], + outputParameters: {}, + failureWorkflow: "", + schemaVersion: 2, + restartable: true, + workflowStatusListenerEnabled: false, + ownerEmail: "shailesh.padave@orkes.io", + timeoutPolicy: "ALERT_ONLY" as const, + timeoutSeconds: 0, + variables: {}, + inputTemplate: {}, + enforceSchema: true, + }; +}; diff --git a/integration-tests/v5-only/metadata/wait_signal_test.ts b/integration-tests/v5-only/metadata/wait_signal_test.ts new file mode 100644 index 00000000..6e17026f --- /dev/null +++ b/integration-tests/v5-only/metadata/wait_signal_test.ts @@ -0,0 +1,73 @@ +export const getWaitSignalTestWfDef = (date: number) => { + return { + createTime: 1744183953775, + updateTime: 0, + name: `wait_signal_test_${date}`, + description: "wait_signal_test", + version: 1, + tasks: [ + { + name: "wait", + taskReferenceName: "wait_ref", + inputParameters: {}, + type: "WAIT", + decisionCases: {}, + defaultCase: [], + forkTasks: [], + startDelay: 0, + joinOn: [], + optional: false, + defaultExclusiveJoinTask: [], + asyncComplete: false, + loopOver: [], + onStateChange: {}, + permissive: false, + }, + { + name: "json_transform", + taskReferenceName: "json_transform_ref", + type: "JSON_JQ_TRANSFORM", + inputParameters: { + persons: [ + { + name: "some", + last: "name", + email: "mail@mail.com", + id: 1, + }, + { + name: "some2", + last: "name2", + email: "mail2@mail.com", + id: 2, + }, + ], + queryExpression: ".persons | map({user:{email,id}})", + }, + }, + { + name: "inline", + taskReferenceName: "inline_ref", + type: "INLINE", + inputParameters: { + expression: "(function () {\n return $.value1 + $.value2;\n})();", + evaluatorType: "graaljs", + value1: 1, + value2: 2, + }, + }, + ], + inputParameters: [], + outputParameters: {}, + failureWorkflow: "", + schemaVersion: 2, + restartable: true, + workflowStatusListenerEnabled: false, + ownerEmail: "test.user@orkes.io", + timeoutPolicy: "ALERT_ONLY" as const, + timeoutSeconds: 0, + variables: {}, + inputTemplate: {}, + enforceSchema: true, + }; +}; diff --git a/jest.config.mjs b/jest.config.mjs index efcc0ce1..cd5d205b 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -4,9 +4,15 @@ export default { preset: "ts-jest", clearMocks: true, coverageProvider: "v8", - testMatch: [ - "**/__tests__/**/*.test.[jt]s?(x)", - "**/?(*.)+(spec|test).[tj]s?(x)", - ], transformIgnorePatterns: ["/node_modules/", "\\.pnp\\.[^\\/]+$"], + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + tsconfig: { + module: "commonjs", + }, + }, + ], + }, }; diff --git a/package-lock.json b/package-lock.json index 5262815a..b14a6260 100644 --- a/package-lock.json +++ b/package-lock.json @@ -562,9 +562,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", "cpu": [ "ppc64" ], @@ -579,9 +579,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", "cpu": [ "arm" ], @@ -596,9 +596,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", "cpu": [ "arm64" ], @@ -613,9 +613,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", "cpu": [ "x64" ], @@ -630,9 +630,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", "cpu": [ "arm64" ], @@ -647,9 +647,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", "cpu": [ "x64" ], @@ -664,9 +664,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", "cpu": [ "arm64" ], @@ -681,9 +681,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", "cpu": [ "x64" ], @@ -698,9 +698,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", "cpu": [ "arm" ], @@ -715,9 +715,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", "cpu": [ "arm64" ], @@ -732,9 +732,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", "cpu": [ "ia32" ], @@ -749,9 +749,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", "cpu": [ "loong64" ], @@ -766,9 +766,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", "cpu": [ "mips64el" ], @@ -783,9 +783,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", "cpu": [ "ppc64" ], @@ -800,9 +800,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", "cpu": [ "riscv64" ], @@ -817,9 +817,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", "cpu": [ "s390x" ], @@ -834,9 +834,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", "cpu": [ "x64" ], @@ -851,9 +851,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", "cpu": [ "arm64" ], @@ -868,9 +868,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", "cpu": [ "x64" ], @@ -885,9 +885,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", "cpu": [ "arm64" ], @@ -902,9 +902,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", "cpu": [ "x64" ], @@ -919,9 +919,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", "cpu": [ "arm64" ], @@ -936,9 +936,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", "cpu": [ "x64" ], @@ -953,9 +953,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", "cpu": [ "arm64" ], @@ -970,9 +970,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", "cpu": [ "ia32" ], @@ -987,9 +987,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", "cpu": [ "x64" ], @@ -1108,9 +1108,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", "dev": true, "license": "MIT", "engines": { @@ -1145,16 +1145,16 @@ } }, "node_modules/@gerrit0/mini-shiki": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.12.2.tgz", - "integrity": "sha512-HKZPmO8OSSAAo20H2B3xgJdxZaLTwtlMwxg0967scnrDlPwe6j5+ULGHyIqwgTbFCn9yv/ff8CmfWZLE9YKBzA==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.13.0.tgz", + "integrity": "sha512-mCrNvZNYNrwKer5PWLF6cOc0OEe2eKzgy976x+IT2tynwJYl+7UpHTSeXQJGijgTcoOf+f359L946unWlYRnsg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/engine-oniguruma": "^3.12.2", - "@shikijs/langs": "^3.12.2", - "@shikijs/themes": "^3.12.2", - "@shikijs/types": "^3.12.2", + "@shikijs/engine-oniguruma": "^3.13.0", + "@shikijs/langs": "^3.13.0", + "@shikijs/themes": "^3.13.0", + "@shikijs/types": "^3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, @@ -1228,91 +1228,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1898,9 +1813,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz", - "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.0.tgz", + "integrity": "sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A==", "cpu": [ "arm" ], @@ -1912,9 +1827,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz", - "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.0.tgz", + "integrity": "sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ==", "cpu": [ "arm64" ], @@ -1926,9 +1841,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", - "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.0.tgz", + "integrity": "sha512-YCdWlY/8ltN6H78HnMsRHYlPiKvqKagBP1r+D7SSylxX+HnsgXGCmLiV3Y4nSyY9hW8qr8U9LDUx/Lo7M6MfmQ==", "cpu": [ "arm64" ], @@ -1940,9 +1855,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz", - "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.0.tgz", + "integrity": "sha512-z4nw6y1j+OOSGzuVbSWdIp1IUks9qNw4dc7z7lWuWDKojY38VMWBlEN7F9jk5UXOkUcp97vA1N213DF+Lz8BRg==", "cpu": [ "x64" ], @@ -1954,9 +1869,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz", - "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.0.tgz", + "integrity": "sha512-Q/dv9Yvyr5rKlK8WQJZVrp5g2SOYeZUs9u/t2f9cQ2E0gJjYB/BWoedXfUT0EcDJefi2zzVfhcOj8drWCzTviw==", "cpu": [ "arm64" ], @@ -1968,9 +1883,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz", - "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.0.tgz", + "integrity": "sha512-kdBsLs4Uile/fbjZVvCRcKB4q64R+1mUq0Yd7oU1CMm1Av336ajIFqNFovByipciuUQjBCPMxwJhCgfG2re3rg==", "cpu": [ "x64" ], @@ -1982,9 +1897,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz", - "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.0.tgz", + "integrity": "sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==", "cpu": [ "arm" ], @@ -1996,9 +1911,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz", - "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.0.tgz", + "integrity": "sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==", "cpu": [ "arm" ], @@ -2010,9 +1925,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz", - "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.0.tgz", + "integrity": "sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==", "cpu": [ "arm64" ], @@ -2024,9 +1939,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz", - "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.0.tgz", + "integrity": "sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==", "cpu": [ "arm64" ], @@ -2038,9 +1953,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz", - "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.0.tgz", + "integrity": "sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==", "cpu": [ "loong64" ], @@ -2052,9 +1967,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz", - "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.0.tgz", + "integrity": "sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==", "cpu": [ "ppc64" ], @@ -2066,9 +1981,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz", - "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.0.tgz", + "integrity": "sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==", "cpu": [ "riscv64" ], @@ -2080,9 +1995,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz", - "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.0.tgz", + "integrity": "sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==", "cpu": [ "riscv64" ], @@ -2094,9 +2009,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz", - "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.0.tgz", + "integrity": "sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==", "cpu": [ "s390x" ], @@ -2108,9 +2023,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz", - "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.0.tgz", + "integrity": "sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==", "cpu": [ "x64" ], @@ -2122,9 +2037,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz", - "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.0.tgz", + "integrity": "sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==", "cpu": [ "x64" ], @@ -2136,9 +2051,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz", - "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.0.tgz", + "integrity": "sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==", "cpu": [ "arm64" ], @@ -2150,9 +2065,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz", - "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.0.tgz", + "integrity": "sha512-YQugafP/rH0eOOHGjmNgDURrpYHrIX0yuojOI8bwCyXwxC9ZdTd3vYkmddPX0oHONLXu9Rb1dDmT0VNpjkzGGw==", "cpu": [ "arm64" ], @@ -2164,9 +2079,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz", - "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.0.tgz", + "integrity": "sha512-zYdUYhi3Qe2fndujBqL5FjAFzvNeLxtIqfzNEVKD1I7C37/chv1VxhscWSQHTNfjPCrBFQMnynwA3kpZpZ8w4A==", "cpu": [ "ia32" ], @@ -2177,10 +2092,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.0.tgz", + "integrity": "sha512-fGk03kQylNaCOQ96HDMeT7E2n91EqvCDd3RwvT5k+xNdFCeMGnj5b5hEgTGrQuyidqSsD3zJDQ21QIaxXqTBJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz", - "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.0.tgz", + "integrity": "sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ==", "cpu": [ "x64" ], @@ -2192,40 +2121,40 @@ ] }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.12.2.tgz", - "integrity": "sha512-hozwnFHsLvujK4/CPVHNo3Bcg2EsnG8krI/ZQ2FlBlCRpPZW4XAEQmEwqegJsypsTAN9ehu2tEYe30lYKSZW/w==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.13.0.tgz", + "integrity": "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.12.2", + "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.12.2.tgz", - "integrity": "sha512-bVx5PfuZHDSHoBal+KzJZGheFuyH4qwwcwG/n+MsWno5cTlKmaNtTsGzJpHYQ8YPbB5BdEdKU1rga5/6JGY8ww==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.13.0.tgz", + "integrity": "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.12.2" + "@shikijs/types": "3.13.0" } }, "node_modules/@shikijs/themes": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.12.2.tgz", - "integrity": "sha512-fTR3QAgnwYpfGczpIbzPjlRnxyONJOerguQv1iwpyQZ9QXX4qy/XFQqXlf17XTsorxnHoJGbH/LXBvwtqDsF5A==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.13.0.tgz", + "integrity": "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.12.2" + "@shikijs/types": "3.13.0" } }, "node_modules/@shikijs/types": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.12.2.tgz", - "integrity": "sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.13.0.tgz", + "integrity": "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==", "dev": true, "license": "MIT", "dependencies": { @@ -2382,9 +2311,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.18.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.5.tgz", - "integrity": "sha512-g9BpPfJvxYBXUWI9bV37j6d6LTMNQ88hPwdWWUeYZnMhlo66FIg9gCc1/DZb15QylJSKwOZjwrckvOTWpOiChg==", + "version": "22.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", + "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3033,13 +2962,16 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -3195,9 +3127,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz", - "integrity": "sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz", + "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3440,6 +3372,69 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3615,9 +3610,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.220", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.220.tgz", - "integrity": "sha512-TWXijEwR1ggr4BdAKrb1nMNqYLTx1/4aD1fkeZU+FVJGTKu53/T7UyHKXlqEX3Ub02csyHePbHmkvnrjcaYzMA==", + "version": "1.5.222", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz", + "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==", "dev": true, "license": "ISC" }, @@ -3635,9 +3630,9 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, @@ -3665,9 +3660,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3678,32 +3673,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" } }, "node_modules/escalade": { @@ -3730,9 +3725,9 @@ } }, "node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3742,7 +3737,7 @@ "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", + "@eslint/js": "9.36.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -3922,6 +3917,13 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/exit-x": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", @@ -4114,19 +4116,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4849,6 +4838,29 @@ "node": ">=10.12.0" } }, + "node_modules/jest-junit/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-junit/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-junit/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -6217,9 +6229,9 @@ } }, "node_modules/rollup": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", - "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.0.tgz", + "integrity": "sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g==", "dev": true, "license": "MIT", "dependencies": { @@ -6233,27 +6245,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.2", - "@rollup/rollup-android-arm64": "4.50.2", - "@rollup/rollup-darwin-arm64": "4.50.2", - "@rollup/rollup-darwin-x64": "4.50.2", - "@rollup/rollup-freebsd-arm64": "4.50.2", - "@rollup/rollup-freebsd-x64": "4.50.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", - "@rollup/rollup-linux-arm-musleabihf": "4.50.2", - "@rollup/rollup-linux-arm64-gnu": "4.50.2", - "@rollup/rollup-linux-arm64-musl": "4.50.2", - "@rollup/rollup-linux-loong64-gnu": "4.50.2", - "@rollup/rollup-linux-ppc64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-musl": "4.50.2", - "@rollup/rollup-linux-s390x-gnu": "4.50.2", - "@rollup/rollup-linux-x64-gnu": "4.50.2", - "@rollup/rollup-linux-x64-musl": "4.50.2", - "@rollup/rollup-openharmony-arm64": "4.50.2", - "@rollup/rollup-win32-arm64-msvc": "4.50.2", - "@rollup/rollup-win32-ia32-msvc": "4.50.2", - "@rollup/rollup-win32-x64-msvc": "4.50.2", + "@rollup/rollup-android-arm-eabi": "4.52.0", + "@rollup/rollup-android-arm64": "4.52.0", + "@rollup/rollup-darwin-arm64": "4.52.0", + "@rollup/rollup-darwin-x64": "4.52.0", + "@rollup/rollup-freebsd-arm64": "4.52.0", + "@rollup/rollup-freebsd-x64": "4.52.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.0", + "@rollup/rollup-linux-arm-musleabihf": "4.52.0", + "@rollup/rollup-linux-arm64-gnu": "4.52.0", + "@rollup/rollup-linux-arm64-musl": "4.52.0", + "@rollup/rollup-linux-loong64-gnu": "4.52.0", + "@rollup/rollup-linux-ppc64-gnu": "4.52.0", + "@rollup/rollup-linux-riscv64-gnu": "4.52.0", + "@rollup/rollup-linux-riscv64-musl": "4.52.0", + "@rollup/rollup-linux-s390x-gnu": "4.52.0", + "@rollup/rollup-linux-x64-gnu": "4.52.0", + "@rollup/rollup-linux-x64-musl": "4.52.0", + "@rollup/rollup-openharmony-arm64": "4.52.0", + "@rollup/rollup-win32-arm64-msvc": "4.52.0", + "@rollup/rollup-win32-ia32-msvc": "4.52.0", + "@rollup/rollup-win32-x64-gnu": "4.52.0", + "@rollup/rollup-win32-x64-msvc": "4.52.0", "fsevents": "~2.3.2" } }, @@ -6315,11 +6328,17 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/slash": { "version": "3.0.0", @@ -6396,21 +6415,47 @@ "node": ">=10" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", @@ -6427,7 +6472,24 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -6440,6 +6502,22 @@ "node": ">=8" } }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", @@ -6454,6 +6532,16 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -6715,9 +6803,9 @@ "license": "Apache-2.0" }, "node_modules/ts-jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.2.tgz", - "integrity": "sha512-pBNOkn4HtuLpNrXTMVRC9b642CBaDnKqWXny4OzuoULT9S7Kf8MMlaRe2veKax12rjf5WcpMBhVPbQurlWGNxA==", + "version": "29.4.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.4.tgz", + "integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==", "dev": true, "license": "MIT", "dependencies": { @@ -7215,18 +7303,18 @@ "license": "MIT" }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -7251,6 +7339,64 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7272,19 +7418,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -7351,6 +7484,51 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 7f0f7bb1..1536f9c5 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,9 @@ "lint": "npx eslint .", "lint-fix": "npx eslint . --fix", "test": "jest --force-exit --detectOpenHandles", + "test:unit": "npm test -- --testMatch='**/src/**/__tests__/**/*.test.[jt]s?(x)'", + "test:integration:v5": "npm test -- --testMatch='**/integration-tests/{common,v5-only}/**/*.test.[jt]s?(x)'", + "test:integration:v4": "npm test -- --testMatch='**/integration-tests/common/**/*.test.[jt]s?(x)'", "ci": "npm run lint && npm run test", "build": "tsup index.ts", "generateClient:models": "npx openapi-typescript-codegen --input http://localhost:8080/api-docs --output src/common/open-api --client node --indent 2 --name ConductorClient --useUnionTypes --exportCore false", diff --git a/src/common/index.ts b/src/common/index.ts index cdaf9d0c..f6b42c46 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -4,14 +4,25 @@ export * from "./types"; export { ConductorClient, - ApiRequestOptions, - ApiResult, - OpenAPIConfig, - OnCancel, ApiError, BaseHttpRequest, CancelablePromise, CancelError, + EventResourceService, + HealthCheckResourceService, + MetadataResourceService, + SchedulerResourceService, + TaskResourceService, + TokenResourceService, + WorkflowBulkResourceService, + WorkflowResourceService, +} from "./open-api"; + +export type { + ApiRequestOptions, + ApiResult, + OpenAPIConfig, + OnCancel, Action, EventHandler, ExternalStorageLocation, @@ -42,14 +53,6 @@ export { WorkflowStatus, WorkflowSummary, WorkflowTask, - EventResourceService, - HealthCheckResourceService, - MetadataResourceService, - SchedulerResourceService, - TaskResourceService, - TokenResourceService, - WorkflowBulkResourceService, - WorkflowResourceService, HTScrollableSearchResultHumanTaskEntry, Terminate, TimeoutPolicy, @@ -61,5 +64,5 @@ export { HumanTaskTemplate, HumanTaskSearchResult, HumanTaskSearch, - HumanTaskEntry + HumanTaskEntry, } from "./open-api"; diff --git a/src/core/__test__/metadata/complex_wf_signal_test.json b/src/core/__test__/metadata/complex_wf_signal_test.json deleted file mode 100644 index ecf3d55f..00000000 --- a/src/core/__test__/metadata/complex_wf_signal_test.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "createTime": 1744299182957, - "updateTime": 1744299435683, - "name": "complex_wf_signal_test", - "description": "http_yield_signal_test", - "version": 1, - "tasks": [ - { - "name": "http", - "taskReferenceName": "http_ref", - "inputParameters": { - "uri": "http://httpbin:8081/api/hello?name=test1", - "method": "GET", - "accept": "application/json", - "contentType": "application/json", - "encode": true - }, - "type": "HTTP", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - }, - { - "name": "sub_workflow", - "taskReferenceName": "sub_workflow_ref", - "inputParameters": {}, - "type": "SUB_WORKFLOW", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "subWorkflowParam": { - "name": "complex_wf_signal_test_subworkflow_1", - "version": 1 - }, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - } - ], - "inputParameters": [], - "outputParameters": {}, - "failureWorkflow": "", - "schemaVersion": 2, - "restartable": true, - "workflowStatusListenerEnabled": false, - "ownerEmail": "shailesh.padave@orkes.io", - "timeoutPolicy": "ALERT_ONLY", - "timeoutSeconds": 0, - "variables": {}, - "inputTemplate": {}, - "enforceSchema": true -} \ No newline at end of file diff --git a/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_1.json b/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_1.json deleted file mode 100644 index f26a7dbb..00000000 --- a/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_1.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "createTime": 1744299356718, - "updateTime": 1744287643769, - "name": "complex_wf_signal_test_subworkflow_1", - "description": "complex_wf_signal_test_subworkflow_1", - "version": 1, - "tasks": [ - { - "name": "http", - "taskReferenceName": "http_ref", - "inputParameters": { - "uri": "http://httpbin:8081/api/hello?name=test1", - "method": "GET", - "accept": "application/json", - "contentType": "application/json", - "encode": true - }, - "type": "HTTP", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - }, - { - "name": "yield", - "taskReferenceName": "simple_ref_1", - "inputParameters": {}, - "type": "YIELD", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - }, - { - "name": "sub_workflow", - "taskReferenceName": "sub_workflow_ref", - "inputParameters": {}, - "type": "SUB_WORKFLOW", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "subWorkflowParam": { - "name": "complex_wf_signal_test_subworkflow_2", - "version": 1 - }, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - } - ], - "inputParameters": [], - "outputParameters": {}, - "failureWorkflow": "", - "schemaVersion": 2, - "restartable": true, - "workflowStatusListenerEnabled": false, - "ownerEmail": "shailesh.padave@orkes.io", - "timeoutPolicy": "ALERT_ONLY", - "timeoutSeconds": 0, - "variables": {}, - "inputTemplate": {}, - "enforceSchema": true -} \ No newline at end of file diff --git a/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_2.json b/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_2.json deleted file mode 100644 index 1bc32297..00000000 --- a/src/core/__test__/metadata/complex_wf_signal_test_subworkflow_2.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "createTime": 1744299371396, - "updateTime": 0, - "name": "complex_wf_signal_test_subworkflow_2", - "description": "complex_wf_signal_test_subworkflow_2", - "version": 1, - "tasks": [ - { - "name": "http", - "taskReferenceName": "http_ref", - "inputParameters": { - "uri": "http://httpbin:8081/api/hello?name=test1", - "method": "GET", - "accept": "application/json", - "contentType": "application/json", - "encode": true - }, - "type": "HTTP", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - }, - { - "name": "yield", - "taskReferenceName": "simple_ref_1", - "inputParameters": {}, - "type": "YIELD", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - } - ], - "inputParameters": [], - "outputParameters": {}, - "failureWorkflow": "", - "schemaVersion": 2, - "restartable": true, - "workflowStatusListenerEnabled": false, - "ownerEmail": "shailesh.padave@orkes.io", - "timeoutPolicy": "ALERT_ONLY", - "timeoutSeconds": 0, - "variables": {}, - "inputTemplate": {}, - "enforceSchema": true -} \ No newline at end of file diff --git a/src/core/__test__/metadata/wait_signal_test.json b/src/core/__test__/metadata/wait_signal_test.json deleted file mode 100644 index f3208552..00000000 --- a/src/core/__test__/metadata/wait_signal_test.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "createTime": 1744183953775, - "updateTime": 0, - "name": "wait_signal_test", - "description": "wait_signal_test", - "version": 1, - "tasks": [ - { - "name": "wait", - "taskReferenceName": "wait_ref", - "inputParameters": {}, - "type": "WAIT", - "decisionCases": {}, - "defaultCase": [], - "forkTasks": [], - "startDelay": 0, - "joinOn": [], - "optional": false, - "defaultExclusiveJoinTask": [], - "asyncComplete": false, - "loopOver": [], - "onStateChange": {}, - "permissive": false - }, - { - "name": "json_transform", - "taskReferenceName": "json_transform_ref", - "type": "JSON_JQ_TRANSFORM", - "inputParameters": { - "persons": [ - { - "name": "some", - "last": "name", - "email": "mail@mail.com", - "id": 1 - }, - { - "name": "some2", - "last": "name2", - "email": "mail2@mail.com", - "id": 2 - } - ], - "queryExpression": ".persons | map({user:{email,id}})" - } - }, - { - "name": "inline", - "taskReferenceName": "inline_ref", - "type": "INLINE", - "inputParameters": { - "expression": "(function () {\n return $.value1 + $.value2;\n})();", - "evaluatorType": "graaljs", - "value1": 1, - "value2": 2 - } - } - ], - "inputParameters": [], - "outputParameters": {}, - "failureWorkflow": "", - "schemaVersion": 2, - "restartable": true, - "workflowStatusListenerEnabled": false, - "ownerEmail": "test.user@orkes.io", - "timeoutPolicy": "ALERT_ONLY", - "timeoutSeconds": 0, - "variables": {}, - "inputTemplate": {}, - "enforceSchema": true -} \ No newline at end of file diff --git a/src/core/__test__/utils/test-util.ts b/src/core/__test__/utils/test-util.ts deleted file mode 100644 index d0d903a4..00000000 --- a/src/core/__test__/utils/test-util.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import {WorkflowDef} from "../../../common"; -import {MetadataClient} from "../../metadataClient"; -import {WorkflowExecutor} from "../../executor"; - -export class TestUtil { - private static metadataClient: MetadataClient; - - public static setMetadataClient(metadataClient: MetadataClient): void { - this.metadataClient = metadataClient; - } - /** - * Read and parse workflow definition from JSON file - */ - public static getWorkflowDef(filePath: string): WorkflowDef { - try { - const fullPath = path.join(__dirname, filePath); - const fileContent = fs.readFileSync(fullPath, 'utf8'); - return JSON.parse(fileContent) as WorkflowDef; - } catch (error) { - throw new Error(`Failed to read workflow definition from ${filePath}: ${error}`); - } - } - - /** - * Register a single workflow from JSON file - */ - public static async registerWorkflow(workflowName: string): Promise { - try { - const workflowDef = this.getWorkflowDef(`../metadata/${workflowName}.json`); - await this.metadataClient.registerWorkflowDef(workflowDef, true); - console.log(`✓ Registered workflow: ${workflowName}`); - } catch (error) { - throw new Error(`Failed to register workflow ${workflowName}: ${error}`); - } - } - - // Helper function to wait for workflow completion - public static async waitForWorkflowCompletion( - executor: WorkflowExecutor, - workflowId: string, - maxWaitMs: number = 300000, // 5 minutes default - pollIntervalMs: number = 100 // 100ms default - ) { - const startTime = Date.now(); - - while (Date.now() - startTime < maxWaitMs) { - try { - const workflowStatus = await executor.getWorkflow(workflowId, true); - - // Check if workflow is in a terminal state - if (['COMPLETED', 'FAILED', 'TERMINATED', 'TIMED_OUT'].includes(workflowStatus.status!)) { - console.debug(`Workflow ${workflowId} reached terminal state: ${workflowStatus.status}`); - return workflowStatus; - } - - console.debug(`Workflow ${workflowId} status: ${workflowStatus.status}, waiting...`); - - // Wait before next poll - await new Promise(resolve => setTimeout(resolve, pollIntervalMs)); - - } catch (error) { - console.warn(`Error checking workflow status for ${workflowId}:`, error); - await new Promise(resolve => setTimeout(resolve, pollIntervalMs)); - } - } - - throw new Error(`Workflow ${workflowId} did not complete within ${maxWaitMs}ms`); - } - - /** - * Unregister a workflow - */ - public static async unregisterWorkflow(workflowName: string, version: number = 1): Promise { - try { - await this.metadataClient.unregisterWorkflow(workflowName, version); - console.log(`✓ Unregistered workflow: ${workflowName} ${version}`); - } catch (error) { - console.warn(`Failed to unregister workflow ${workflowName}: ${error}`); - } - } - - /** - * Wait for workflow to reach expected status - */ - public static async waitForWorkflowStatus( - workflowClient: any, - workflowId: string, - expectedStatus: string, - maxWaitTimeMs: number = 5000, - pollIntervalMs: number = 100 - ): Promise { - const startTime = Date.now(); - - while (Date.now() - startTime < maxWaitTimeMs) { - try { - const workflow = await workflowClient.getWorkflow(workflowId, true); - - if (workflow.status === expectedStatus) { - return workflow; - } - - if (workflow.status === 'FAILED' || workflow.status === 'TERMINATED') { - throw new Error(`Workflow ended in unexpected state: ${workflow.status}`); - } - - await this.sleep(pollIntervalMs); - } catch (error) { - throw new Error(`Failed to get workflow status: ${error}`); - } - } - - throw new Error(`Workflow did not reach status ${expectedStatus} within ${maxWaitTimeMs}ms`); - } - - /** - * Sleep utility - */ - private static sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); - } -} \ No newline at end of file diff --git a/src/core/generators/__test__/generators.test.ts b/src/core/generators/__tests__/generators.test.ts similarity index 100% rename from src/core/generators/__test__/generators.test.ts rename to src/core/generators/__tests__/generators.test.ts diff --git a/src/core/sdk/__test__/factory.test.ts b/src/core/sdk/__tests__/factory.test.ts similarity index 100% rename from src/core/sdk/__test__/factory.test.ts rename to src/core/sdk/__tests__/factory.test.ts diff --git a/src/orkes/OrkesConductorClient.ts b/src/orkes/OrkesConductorClient.ts index 4d80a901..1e9145c7 100644 --- a/src/orkes/OrkesConductorClient.ts +++ b/src/orkes/OrkesConductorClient.ts @@ -16,13 +16,16 @@ export const orkesConductorClient = async ( config?: Partial, customFetch?: FetchFn ) => { - const { serverUrl, keyId, keySecret } = resolveOrkesConfig(config); + const { serverUrl, keyId, keySecret, maxHttp2Connections } = + resolveOrkesConfig(config); if (!serverUrl) throw new Error("Conductor server URL is not set"); const conductorClientWithAuth = new ConductorClientWithAuth( { ...config, BASE: serverUrl }, - createOrkesHttpRequest(await resolveFetchFn(customFetch)) + createOrkesHttpRequest( + await resolveFetchFn(customFetch, maxHttp2Connections) + ) ); if (keyId && keySecret) { diff --git a/src/orkes/helpers/resolveFetchFn.ts b/src/orkes/helpers/resolveFetchFn.ts index 5052aa55..8ed08896 100644 --- a/src/orkes/helpers/resolveFetchFn.ts +++ b/src/orkes/helpers/resolveFetchFn.ts @@ -1,18 +1,26 @@ import { FetchFn } from "../types"; -import type { ResponseInit, RequestInfo } from "undici"; +// eslint-disable-next-line +// @ts-ignore since undici is an optional dependency and could be missing +import type { + RequestInfo as UndiciRequestInfo, + RequestInit as UndiciRequestInit, +} from "undici"; export const resolveFetchFn = async ( - customFetch?: FetchFn + customFetch?: FetchFn, + maxHttpConnections: number = 1 ): Promise => { if (customFetch) return customFetch; if (process?.release?.name !== "node") return fetch; try { - const undici = await import("undici"); - const agent = new undici.Agent({ allowH2: true }); + // eslint-disable-next-line + // @ts-ignore since undici is an optional dependency and could be missing + const { fetch: undiciFetch, Agent } = await import("undici"); + const undiciAgent = new Agent({ allowH2: true, connections: maxHttpConnections }); - return ((input: RequestInfo, init: ResponseInit) => - undici.fetch(input, { ...init, dispatcher: agent })) as FetchFn; + return ((input: UndiciRequestInfo, init?: UndiciRequestInit) => + undiciFetch(input, { ...init, dispatcher: undiciAgent })) as FetchFn; } catch { return fetch; } diff --git a/src/orkes/helpers/resolveOrkesConfig.ts b/src/orkes/helpers/resolveOrkesConfig.ts index 7f841244..bb652a59 100644 --- a/src/orkes/helpers/resolveOrkesConfig.ts +++ b/src/orkes/helpers/resolveOrkesConfig.ts @@ -5,5 +5,7 @@ export const resolveOrkesConfig = (config?: Partial) => { serverUrl: process.env.CONDUCTOR_SERVER_URL || config?.serverUrl, keyId: process.env.CONDUCTOR_AUTH_KEY || config?.keyId, keySecret: process.env.CONDUCTOR_AUTH_SECRET || config?.keySecret, + maxHttp2Connections: + Number(process.env.CONDUCTOR_MAX_HTTP2_CONNECTIONS) || config?.maxHttp2Connections, }; }; diff --git a/src/orkes/request/fetchCatchDns/__test__/DnsCache.test.ts b/src/orkes/request/fetchCatchDns/__tests__/DnsCache.test.ts similarity index 100% rename from src/orkes/request/fetchCatchDns/__test__/DnsCache.test.ts rename to src/orkes/request/fetchCatchDns/__tests__/DnsCache.test.ts diff --git a/src/orkes/request/fetchCatchDns/__test__/DnsResolver.test.ts b/src/orkes/request/fetchCatchDns/__tests__/DnsResolver.test.ts similarity index 100% rename from src/orkes/request/fetchCatchDns/__test__/DnsResolver.test.ts rename to src/orkes/request/fetchCatchDns/__tests__/DnsResolver.test.ts diff --git a/src/orkes/request/fetchCatchDns/__test__/FetchCatchDns.test.ts b/src/orkes/request/fetchCatchDns/__tests__/FetchCatchDns.test.ts similarity index 100% rename from src/orkes/request/fetchCatchDns/__test__/FetchCatchDns.test.ts rename to src/orkes/request/fetchCatchDns/__tests__/FetchCatchDns.test.ts diff --git a/src/orkes/request/request.ts b/src/orkes/request/request.ts index 3288df82..998fdddd 100644 --- a/src/orkes/request/request.ts +++ b/src/orkes/request/request.ts @@ -207,6 +207,21 @@ const getRequestBody = (options: ApiRequestOptions): any => { return undefined; }; +const fetchWithRetry = async ( + url: string, + request: RequestInit, + fetchFn: FetchFn, + retries: number = 5, + delay: number = 1000 +): Promise => { + const response = await fetchFn(url, request); + if (response.status == 429 && retries > 0) { + await new Promise((resolve) => setTimeout(resolve, delay)); + return fetchWithRetry(url, request, fetchFn, retries - 1, delay * 2); + } + return response; +}; + const sendRequest = async ( options: ApiRequestOptions, url: string, @@ -227,7 +242,7 @@ const sendRequest = async ( onCancel(() => controller.abort()); - return await fetchFn(url, request); + return await fetchWithRetry(url, request, fetchFn); }; const getResponseHeader = ( diff --git a/src/orkes/types.ts b/src/orkes/types.ts index 48b438ab..ff0089b7 100644 --- a/src/orkes/types.ts +++ b/src/orkes/types.ts @@ -9,4 +9,5 @@ export interface OrkesApiConfig extends GenerateTokenRequest, OpenAPIConfig { serverUrl: string; refreshTokenInterval: number; useEnvVars?: boolean; // DEPRECATED, has no effect + maxHttp2Connections?: number; // max number of simultaneous http connections to the conductor server, defaults to 1 (since we use http2) } diff --git a/src/task/__tests__/Poller.test.ts b/src/task/__tests__/Poller.test.ts index d34b2403..f42a98c5 100644 --- a/src/task/__tests__/Poller.test.ts +++ b/src/task/__tests__/Poller.test.ts @@ -1,6 +1,6 @@ import { Poller } from "../Poller"; import { expect, describe, test, jest } from "@jest/globals"; -import { mockLogger } from "./mockLogger"; +import { mockLogger } from "../../../integration-tests/utils/mockLogger"; type Task = { description: string; id: number }; diff --git a/src/task/__tests__/TaskRunner.test.ts b/src/task/__tests__/TaskRunner.test.ts index 29e45cd7..79aecc4e 100644 --- a/src/task/__tests__/TaskRunner.test.ts +++ b/src/task/__tests__/TaskRunner.test.ts @@ -3,7 +3,7 @@ import type { Mocked } from "jest-mock"; import { TaskRunner } from "../TaskRunner"; import { RunnerArgs } from "../types"; -import { mockLogger } from "./mockLogger"; +import { mockLogger } from "../../../integration-tests/utils/mockLogger"; import { TaskResourceService } from "../../common/open-api"; import { TaskResultStatusEnum } from "../../common/open-api/models/TaskResultStatusEnum"; diff --git a/tsconfig.json b/tsconfig.json index 2bf5ba0a..ad39ceaf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,5 +6,6 @@ "dom" ], "noEmit": true, + "isolatedModules": true } } \ No newline at end of file