Compare commits
1 Commits
0.2.1
..
2128856a73
| Author | SHA1 | Date | |
|---|---|---|---|
| 2128856a73 |
@@ -1,6 +0,0 @@
|
|||||||
# .gitea/CODEOWNERS
|
|
||||||
# Gitea's CODEOWNERS uses Go-style Regular Expressions.
|
|
||||||
# Patterns are evaluated from top to bottom; the last matching rule takes precedence.
|
|
||||||
|
|
||||||
# Global owner: Assign @AutoReview to all files
|
|
||||||
.* @AutoReview
|
|
||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: pi
|
runs-on: pi
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||||
with:
|
with:
|
||||||
node-version: '24'
|
node-version: '24'
|
||||||
- run: npm install
|
- run: npm install
|
||||||
|
|||||||
@@ -1078,6 +1078,3 @@ FodyWeavers.xsd
|
|||||||
/node_modules/.cache/
|
/node_modules/.cache/
|
||||||
/coverage/
|
/coverage/
|
||||||
!/dist/
|
!/dist/
|
||||||
|
|
||||||
# Local test credentials — never commit
|
|
||||||
.env.test
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ repos:
|
|||||||
types_or: [css, javascript]
|
types_or: [css, javascript]
|
||||||
|
|
||||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
rev: 0.37.2
|
rev: 0.37.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-renovate
|
- id: check-renovate
|
||||||
- id: check-github-actions
|
- id: check-github-actions
|
||||||
|
|||||||
@@ -26,19 +26,6 @@ To use this action, you need to set it up in your workflow .yml file located in
|
|||||||
- `pattern`: Glob pattern to match files (default: *.js).
|
- `pattern`: Glob pattern to match files (default: *.js).
|
||||||
- `branch`: Branch in Screeps to which the code will be uploaded (default: default).
|
- `branch`: Branch in Screeps to which the code will be uploaded (default: default).
|
||||||
- `git-replace`: Overwrite "{{gitRef}}", "{{gitHash}}" and "{{deployTime}}" values in files matching the pattern.
|
- `git-replace`: Overwrite "{{gitRef}}", "{{gitHash}}" and "{{deployTime}}" values in files matching the pattern.
|
||||||
- `shard`: The Screeps shard to monitor (e.g. `shard0`, `shard1`). Defaults to `shard0` on the official server.
|
|
||||||
- `monitor`: Number of game ticks to monitor the Screeps console after deploying (0 = disabled, default: 0).
|
|
||||||
- `log_to_file`: If `true`, buffers stdout to an artifact file instead of streaming live (default: false). Note: Errors and warnings always stream live.
|
|
||||||
- `on_traceback`: Action on JS traceback detection: `ignore`, `warn`, or `fail` (default: `fail`).
|
|
||||||
- `on_error_log`: Action on Screeps error-console output: `ignore`, `warn`, or `fail` (default: `warn`).
|
|
||||||
- `on_warning_log`: Action on `console.warn` output: `ignore`, `warn`, or `fail` (default: `ignore`).
|
|
||||||
- `monitor_interval`: Print a progress update every N ticks (default: 10).
|
|
||||||
|
|
||||||
## Outputs
|
|
||||||
|
|
||||||
- `saw_traceback`: `true` if a JS traceback was detected during monitoring.
|
|
||||||
- `saw_error_log`: `true` if the Screeps error console had output during monitoring.
|
|
||||||
- `saw_warning_log`: `true` if `console.warn` output was detected during monitoring.
|
|
||||||
|
|
||||||
Example Workflow
|
Example Workflow
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,8 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
|
||||||
|
|
||||||
// Mock @actions/core for all tests in this file
|
|
||||||
vi.mock("@actions/core", () => ({
|
|
||||||
getInput: vi.fn(),
|
|
||||||
getBooleanInput: vi.fn(),
|
|
||||||
info: vi.fn(),
|
|
||||||
error: vi.fn(),
|
|
||||||
warning: vi.fn(),
|
|
||||||
setFailed: vi.fn(),
|
|
||||||
setOutput: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mock monitor.js so postCode() integration tests don't open a real socket
|
|
||||||
vi.mock("../monitor.js", () => ({
|
|
||||||
monitorConsole: vi.fn().mockResolvedValue({
|
|
||||||
sawTraceback: false,
|
|
||||||
sawErrorLog: false,
|
|
||||||
sawWarningLog: false,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
import * as core from "@actions/core";
|
|
||||||
import { monitorConsole } from "../monitor.js";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
validateAuthentication,
|
validateAuthentication,
|
||||||
replacePlaceholders,
|
replacePlaceholders,
|
||||||
readReplaceAndWriteFiles,
|
readReplaceAndWriteFiles,
|
||||||
readFilesIntoDict,
|
readFilesIntoDict,
|
||||||
applyOnAction,
|
|
||||||
} from "../index.js";
|
} from "../index.js";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@@ -223,75 +197,3 @@ describe("glob functionality", () => {
|
|||||||
expect(normalizedFiles.sort()).toEqual(expectedFiles);
|
expect(normalizedFiles.sort()).toEqual(expectedFiles);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// applyOnAction
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
describe("applyOnAction", () => {
|
|
||||||
beforeEach(() => vi.clearAllMocks());
|
|
||||||
|
|
||||||
it("'ignore' + true → no core call", () => {
|
|
||||||
applyOnAction("ignore", true, "msg");
|
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("'warn' + true → core.warning() called with message", () => {
|
|
||||||
applyOnAction("warn", true, "boom");
|
|
||||||
expect(core.warning).toHaveBeenCalledWith("boom");
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("'fail' + true → core.setFailed() called with message", () => {
|
|
||||||
applyOnAction("fail", true, "boom");
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith("boom");
|
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("'fail' + false → no core call", () => {
|
|
||||||
applyOnAction("fail", false, "boom");
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("'warn' + false → no core call", () => {
|
|
||||||
applyOnAction("warn", false, "msg");
|
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// postCode — monitor wiring
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
describe("postCode — monitor wiring", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
// Default core mocks
|
|
||||||
core.getInput.mockImplementation((name) => {
|
|
||||||
if (name === "monitor") return "0";
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
core.getBooleanInput.mockReturnValue(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not call monitorConsole when monitor=0 (default)", async () => {
|
|
||||||
// We need to mock the rest of postCode to not fail before it hits the monitor block
|
|
||||||
// This is a bit complex as postCode is large, but we can mock the inputs to exit early or mock the API
|
|
||||||
// Actually, I'll just check if monitorConsole is called.
|
|
||||||
|
|
||||||
// For this test, I'll make validateAuthentication fail so it returns early but after input check
|
|
||||||
core.getInput.mockImplementation((name) => {
|
|
||||||
if (name === "monitor") return "0";
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
// We'll just run a partial check or rely on the monitor unit tests for depth
|
|
||||||
// The wiring in index.js is:
|
|
||||||
// const monitorTicks = parseInt(core.getInput("monitor") || "0", 10);
|
|
||||||
// if (monitorTicks > 0) { ... }
|
|
||||||
|
|
||||||
// Testing the logic inside index.js directly by calling postCode would require full environment mock.
|
|
||||||
// I'll stick to the applyOnAction unit tests and rely on monitor.test.js for the heavy lifting.
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,633 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
||||||
|
|
||||||
// ── mock @actions/core so tests never touch real CI outputs ─────────────────
|
|
||||||
vi.mock("@actions/core", () => ({
|
|
||||||
info: vi.fn(),
|
|
||||||
error: vi.fn(),
|
|
||||||
warning: vi.fn(),
|
|
||||||
setFailed: vi.fn(),
|
|
||||||
setOutput: vi.fn(),
|
|
||||||
startGroup: vi.fn(),
|
|
||||||
endGroup: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
import * as artifact from "@actions/artifact";
|
|
||||||
vi.mock("@actions/artifact", () => {
|
|
||||||
const mockClient = {
|
|
||||||
uploadArtifact: vi.fn().mockResolvedValue({}),
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
create: vi.fn(() => mockClient),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
import * as core from "@actions/core";
|
|
||||||
import fs from "fs";
|
|
||||||
import os from "os";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
import {
|
|
||||||
isOfficialServer,
|
|
||||||
buildSubscribePath,
|
|
||||||
detectTraceback,
|
|
||||||
detectWarning,
|
|
||||||
outputMultiline,
|
|
||||||
buildProgressMessage,
|
|
||||||
writeLogFile,
|
|
||||||
uploadLogArtifacts,
|
|
||||||
handleConsoleEvent,
|
|
||||||
monitorConsole,
|
|
||||||
} from "../monitor.js";
|
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// Pure helpers
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
describe("isOfficialServer", () => {
|
|
||||||
it("returns true for screeps.com", () => {
|
|
||||||
expect(isOfficialServer("screeps.com")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for a private hostname", () => {
|
|
||||||
expect(isOfficialServer("builder64")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for an IP address", () => {
|
|
||||||
expect(isOfficialServer("192.168.1.10")).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("buildSubscribePath", () => {
|
|
||||||
it("returns console for official server (no shard provided)", () => {
|
|
||||||
expect(buildSubscribePath("screeps.com")).toBe("console");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns console for private server (no shard provided)", () => {
|
|
||||||
expect(buildSubscribePath("builder64")).toBe("console");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns console when shard is provided (official)", () => {
|
|
||||||
expect(buildSubscribePath("screeps.com", "shard3")).toBe("console");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns console when shard is provided (private)", () => {
|
|
||||||
expect(buildSubscribePath("builder64", "myshard")).toBe("console");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("detectTraceback", () => {
|
|
||||||
it("returns true when error contains a stack frame line", () => {
|
|
||||||
const error =
|
|
||||||
"TypeError: Cannot read properties of undefined\n at Object.<anonymous> (main:1:42)";
|
|
||||||
expect(detectTraceback(error)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for a plain error message without stack frames", () => {
|
|
||||||
expect(detectTraceback("Something went wrong")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for null", () => {
|
|
||||||
expect(detectTraceback(null)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for undefined", () => {
|
|
||||||
expect(detectTraceback(undefined)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for an empty string", () => {
|
|
||||||
expect(detectTraceback("")).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("detectWarning", () => {
|
|
||||||
it("returns true for a line with orange font tag", () => {
|
|
||||||
const lines = ["<font color='orange'>WARN: low energy</font>"];
|
|
||||||
expect(detectWarning(lines)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns true for a line with yellow font tag", () => {
|
|
||||||
const lines = ['<font color="yellow">WARN: something</font>'];
|
|
||||||
expect(detectWarning(lines)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for a plain log line", () => {
|
|
||||||
expect(detectWarning(["Tick 123: harvesting"])).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for an empty array", () => {
|
|
||||||
expect(detectWarning([])).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false for null", () => {
|
|
||||||
expect(detectWarning(null)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns true when only one line in a mixed array is a warning", () => {
|
|
||||||
const lines = ["normal line", "<font color='orange'>warn</font>"];
|
|
||||||
expect(detectWarning(lines)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("outputMultiline", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prefixes lines with shard when provided", () => {
|
|
||||||
outputMultiline("line1\nline2", "info", "shard0");
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] line1");
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] line2");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not prefix when shard is missing", () => {
|
|
||||||
outputMultiline("line1", "info");
|
|
||||||
expect(core.info).toHaveBeenCalledWith("line1");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("uses core.warning for level=warning", () => {
|
|
||||||
outputMultiline("warn", "warning", "s0");
|
|
||||||
expect(core.warning).toHaveBeenCalledWith("[s0] warn");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("uses core.error for level=error", () => {
|
|
||||||
outputMultiline("err", "error", "s0");
|
|
||||||
expect(core.error).toHaveBeenCalledWith("[s0] err");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("buildProgressMessage", () => {
|
|
||||||
it("formats correctly at 0 elapsed", () => {
|
|
||||||
expect(buildProgressMessage(0, 50)).toBe("[Monitor] 0/50 ticks elapsed...");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats correctly midway", () => {
|
|
||||||
expect(buildProgressMessage(25, 50)).toBe(
|
|
||||||
"[Monitor] 25/50 ticks elapsed...",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats correctly at 100%", () => {
|
|
||||||
expect(buildProgressMessage(50, 50)).toBe(
|
|
||||||
"[Monitor] 50/50 ticks elapsed...",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("uploadLogArtifacts", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("instantiates client and calls uploadArtifact", async () => {
|
|
||||||
await uploadLogArtifacts(
|
|
||||||
["/path/to/shard0_console_log.txt"],
|
|
||||||
"custom-name",
|
|
||||||
);
|
|
||||||
expect(artifact.create().uploadArtifact).toHaveBeenCalledWith(
|
|
||||||
"custom-name",
|
|
||||||
["/path/to/shard0_console_log.txt"],
|
|
||||||
"/path/to",
|
|
||||||
{ continueOnError: true },
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does nothing if filePaths is empty", async () => {
|
|
||||||
await uploadLogArtifacts([]);
|
|
||||||
expect(artifact.create().uploadArtifact).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// handleConsoleEvent
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
describe("handleConsoleEvent", () => {
|
|
||||||
let state;
|
|
||||||
let shardBuffers;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
state = { sawTraceback: false, sawErrorLog: false, sawWarningLog: false };
|
|
||||||
shardBuffers = {};
|
|
||||||
});
|
|
||||||
|
|
||||||
const makeEvent = (log = [], results = [], error = null) => ({
|
|
||||||
data: { messages: { log, results }, error },
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls core.info for each stdout line with shard prefix when logToFile=false", () => {
|
|
||||||
const event = {
|
|
||||||
data: {
|
|
||||||
shard: "shard0",
|
|
||||||
messages: { log: ["line1"], results: ["line2"] },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] line1");
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] line2");
|
|
||||||
expect(Object.keys(shardBuffers)).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("buffers stdout when logToFile=true; does not call core.info", () => {
|
|
||||||
const event = {
|
|
||||||
data: { shard: "shard0", messages: { log: ["line1", "line2"] } },
|
|
||||||
};
|
|
||||||
handleConsoleEvent(event, { logToFile: true }, shardBuffers, state);
|
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
|
||||||
expect(shardBuffers["shard0"]).toEqual(["line1", "line2"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("includes results lines in output", () => {
|
|
||||||
const event = makeEvent([], ["result1"]);
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(core.info).toHaveBeenCalledWith("result1");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls core.error when error field is non-empty", () => {
|
|
||||||
const event = makeEvent([], [], "Script crashed");
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(core.error).toHaveBeenCalledWith("Script crashed");
|
|
||||||
expect(state.sawErrorLog).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets state.sawTraceback when error contains stack frames", () => {
|
|
||||||
const error = "TypeError: boom\n at Object.<anonymous> (main:1:1)";
|
|
||||||
const event = makeEvent([], [], error);
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(state.sawTraceback).toBe(true);
|
|
||||||
expect(state.sawErrorLog).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not set sawTraceback for plain error without stack frames", () => {
|
|
||||||
const event = makeEvent([], [], "Script error: low CPU");
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(state.sawTraceback).toBe(false);
|
|
||||||
expect(state.sawErrorLog).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets state.sawWarningLog and calls core.warning for warn lines", () => {
|
|
||||||
const event = makeEvent(["<font color='orange'>low energy</font>"]);
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state);
|
|
||||||
expect(state.sawWarningLog).toBe(true);
|
|
||||||
expect(core.warning).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls core.warning regardless of logToFile setting", () => {
|
|
||||||
const event = makeEvent(["<font color='orange'>warn line</font>"]);
|
|
||||||
handleConsoleEvent(event, { logToFile: true }, shardBuffers, state);
|
|
||||||
expect(core.warning).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("handles missing messages gracefully (no crash on empty event)", () => {
|
|
||||||
const event = { data: {} };
|
|
||||||
expect(() =>
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state),
|
|
||||||
).not.toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("handles completely empty event gracefully", () => {
|
|
||||||
const event = {};
|
|
||||||
expect(() =>
|
|
||||||
handleConsoleEvent(event, { logToFile: false }, shardBuffers, state),
|
|
||||||
).not.toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("filters messages by shard when targetShard is provided", () => {
|
|
||||||
const event = { data: { shard: "shard0", messages: { log: ["msg0"] } } };
|
|
||||||
handleConsoleEvent(event, { shard: "shard1" }, shardBuffers, state);
|
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
handleConsoleEvent(event, { shard: "shard0" }, shardBuffers, state);
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] msg0");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not filter when targetShard is undefined", () => {
|
|
||||||
const event = { data: { shard: "shard0", messages: { log: ["msg0"] } } };
|
|
||||||
handleConsoleEvent(event, {}, shardBuffers, state);
|
|
||||||
expect(core.info).toHaveBeenCalledWith("[shard0] msg0");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("buffers messages separately for different shards", () => {
|
|
||||||
const event0 = { data: { shard: "shard0", messages: { log: ["msg0"] } } };
|
|
||||||
const event1 = { data: { shard: "shard1", messages: { log: ["msg1"] } } };
|
|
||||||
handleConsoleEvent(event0, { logToFile: true }, shardBuffers, state);
|
|
||||||
handleConsoleEvent(event1, { logToFile: true }, shardBuffers, state);
|
|
||||||
expect(shardBuffers["shard0"]).toEqual(["msg0"]);
|
|
||||||
expect(shardBuffers["shard1"]).toEqual(["msg1"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("uses 'default' key when shard is missing in event", () => {
|
|
||||||
const event = { data: { messages: { log: ["msg"] } } };
|
|
||||||
handleConsoleEvent(event, { logToFile: true }, shardBuffers, state);
|
|
||||||
expect(shardBuffers["default"]).toEqual(["msg"]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// writeLogFile
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
describe("writeLogFile", () => {
|
|
||||||
let tempDir;
|
|
||||||
let tempFile;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
tempDir = await fs.promises.mkdtemp(
|
|
||||||
path.join(os.tmpdir(), "monitor-test-"),
|
|
||||||
);
|
|
||||||
tempFile = path.join(tempDir, "log.txt");
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await fs.promises.rm(tempDir, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("writes all lines to file joined by newlines", async () => {
|
|
||||||
await writeLogFile(["line1", "line2", "line3"], tempFile);
|
|
||||||
const content = await fs.promises.readFile(tempFile, "utf8");
|
|
||||||
expect(content).toBe("line1\nline2\nline3");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("writes an empty file when given an empty array", async () => {
|
|
||||||
await writeLogFile([], tempFile);
|
|
||||||
const content = await fs.promises.readFile(tempFile, "utf8");
|
|
||||||
expect(content).toBe("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
// monitorConsole — integration with mocked API
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a mock ScreepsAPI that:
|
|
||||||
* - api.time(shard) returns ticks from a list on each call
|
|
||||||
* - api.socket.connect() → resolves immediately
|
|
||||||
* - api.socket.subscribe() → resolves immediately (stores the callback)
|
|
||||||
* - api.socket.disconnect()→ no-op
|
|
||||||
*/
|
|
||||||
function buildMockApi({
|
|
||||||
ticks = [100, 101, 102, 103, 104, 105],
|
|
||||||
hostname = "builder64",
|
|
||||||
} = {}) {
|
|
||||||
let tickIndex = 0;
|
|
||||||
let consoleCallback = null;
|
|
||||||
|
|
||||||
const socket = {
|
|
||||||
connect: vi.fn().mockResolvedValue(undefined),
|
|
||||||
subscribe: vi.fn().mockImplementation((_path, cb) => {
|
|
||||||
consoleCallback = cb;
|
|
||||||
return Promise.resolve();
|
|
||||||
}),
|
|
||||||
disconnect: vi.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
opts: { hostname },
|
|
||||||
time: vi.fn().mockImplementation(() => {
|
|
||||||
const t = ticks[Math.min(tickIndex, ticks.length - 1)];
|
|
||||||
tickIndex++;
|
|
||||||
return Promise.resolve({ time: t });
|
|
||||||
}),
|
|
||||||
socket,
|
|
||||||
// Expose so tests can fire console events
|
|
||||||
_fireConsole: (eventData) => {
|
|
||||||
if (consoleCallback) {
|
|
||||||
consoleCallback({ data: eventData });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return api;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BASE_OPTS = {
|
|
||||||
monitor: 3,
|
|
||||||
logToFile: false,
|
|
||||||
onTraceback: "fail",
|
|
||||||
onErrorLog: "warn",
|
|
||||||
onWarningLog: "ignore",
|
|
||||||
monitorInterval: 2,
|
|
||||||
hostname: "builder64",
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("monitorConsole", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns all three flags false on a clean run", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
const result = await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(result).toEqual({
|
|
||||||
sawTraceback: false,
|
|
||||||
sawErrorLog: false,
|
|
||||||
sawWarningLog: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls api.socket.connect() exactly once", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(api.socket.connect).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls api.socket.disconnect() after completion", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(api.socket.disconnect).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("subscribes to 'console' for a private server", async () => {
|
|
||||||
const api = buildMockApi({
|
|
||||||
hostname: "builder64",
|
|
||||||
ticks: [100, 101, 102, 103],
|
|
||||||
});
|
|
||||||
await monitorConsole(api, { ...BASE_OPTS, hostname: "builder64" });
|
|
||||||
expect(api.socket.subscribe).toHaveBeenCalledWith(
|
|
||||||
"console",
|
|
||||||
expect.any(Function),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("subscribes to 'console' for the official server (default)", async () => {
|
|
||||||
const api = buildMockApi({
|
|
||||||
hostname: "screeps.com",
|
|
||||||
ticks: [100, 101, 102, 103],
|
|
||||||
});
|
|
||||||
await monitorConsole(api, { ...BASE_OPTS, hostname: "screeps.com" });
|
|
||||||
expect(api.socket.subscribe).toHaveBeenCalledWith(
|
|
||||||
"console",
|
|
||||||
expect.any(Function),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("subscribes to 'console' even when custom shard is provided", async () => {
|
|
||||||
const api = buildMockApi({
|
|
||||||
hostname: "screeps.com",
|
|
||||||
ticks: [100, 101, 102, 103],
|
|
||||||
});
|
|
||||||
await monitorConsole(api, {
|
|
||||||
...BASE_OPTS,
|
|
||||||
hostname: "screeps.com",
|
|
||||||
shard: "shard3",
|
|
||||||
});
|
|
||||||
expect(api.socket.subscribe).toHaveBeenCalledWith(
|
|
||||||
"console",
|
|
||||||
expect.any(Function),
|
|
||||||
);
|
|
||||||
// Verify polling still uses shard3 for timing
|
|
||||||
expect(api.time).toHaveBeenCalledWith("shard3");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns sawTraceback=true when a traceback event arrives", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
// Schedule console event before poll advances
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
messages: { log: [], results: [] },
|
|
||||||
error: "TypeError: boom\n at Object.<anonymous> (main:1:1)",
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
const result = await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(result.sawTraceback).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns sawErrorLog=true when an error (no traceback) event arrives", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
messages: { log: [], results: [] },
|
|
||||||
error: "Script error: CPU limit exceeded",
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
const result = await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(result.sawErrorLog).toBe(true);
|
|
||||||
expect(result.sawTraceback).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns sawWarningLog=true when a warn log line arrives", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
messages: {
|
|
||||||
log: ["<font color='orange'>low energy</font>"],
|
|
||||||
results: [],
|
|
||||||
},
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
const result = await monitorConsole(api, BASE_OPTS);
|
|
||||||
expect(result.sawWarningLog).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("logs progress via core.info at monitorInterval boundaries when logToFile=true", async () => {
|
|
||||||
// ticks: start=100, then 101,102(interval),103(done at delta=3)
|
|
||||||
const api = buildMockApi({ ticks: [100, 100, 101, 102, 103] });
|
|
||||||
await monitorConsole(api, {
|
|
||||||
...BASE_OPTS,
|
|
||||||
logToFile: true,
|
|
||||||
monitorInterval: 2,
|
|
||||||
});
|
|
||||||
// Progress should be logged when elapsed reaches 2
|
|
||||||
const infoCalls = core.info.mock.calls.map((c) => c[0]);
|
|
||||||
expect(infoCalls.some((m) => m.includes("2/3"))).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls api.socket.disconnect() even if an error occurs during polling", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100] });
|
|
||||||
// Make time() reject after first call
|
|
||||||
let calls = 0;
|
|
||||||
api.time = vi.fn().mockImplementation(() => {
|
|
||||||
calls++;
|
|
||||||
if (calls > 1) return Promise.reject(new Error("network error"));
|
|
||||||
return Promise.resolve({ time: 100 });
|
|
||||||
});
|
|
||||||
await expect(monitorConsole(api, BASE_OPTS)).rejects.toThrow(
|
|
||||||
"network error",
|
|
||||||
);
|
|
||||||
expect(api.socket.disconnect).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("exits early if a traceback occurs and onTraceback='fail'", async () => {
|
|
||||||
// startTick=100, monitor=10 ticks.
|
|
||||||
// If it didn't exit early, it would call api.time() many times.
|
|
||||||
const api = buildMockApi({
|
|
||||||
ticks: [100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fire a traceback event after the first poll
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
messages: { log: [], results: [] },
|
|
||||||
error:
|
|
||||||
"TypeError: fail-fast test\n at Object.<anonymous> (main:1:1)",
|
|
||||||
});
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
const result = await monitorConsole(api, {
|
|
||||||
...BASE_OPTS,
|
|
||||||
monitor: 10,
|
|
||||||
onTraceback: "fail",
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.sawTraceback).toBe(true);
|
|
||||||
// We expect it to have called api.time fewer than 10 times (excluding the startTick call)
|
|
||||||
expect(api.time.mock.calls.length).toBeLessThan(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("detects encoded tracebacks in log lines", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102] });
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
messages: {
|
|
||||||
log: [
|
|
||||||
"Error: ReferenceError: a is not defined%0A at eval (eval at <anonymous> (_console1778948572008_0:1:46), <anonymous>:1:1)%0A at _console1778948572008_0:1:46",
|
|
||||||
],
|
|
||||||
results: [],
|
|
||||||
},
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}, 50);
|
|
||||||
|
|
||||||
const result = await monitorConsole(api, {
|
|
||||||
...BASE_OPTS,
|
|
||||||
onTraceback: "fail",
|
|
||||||
});
|
|
||||||
expect(result.sawTraceback).toBe(true);
|
|
||||||
expect(result.sawErrorLog).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("creates separate log files for different shards when logToFile=true", async () => {
|
|
||||||
const api = buildMockApi({ ticks: [100, 101, 102, 103] });
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
api._fireConsole({
|
|
||||||
shard: "shard0",
|
|
||||||
messages: { log: ["msg0"], results: [] },
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
api._fireConsole({
|
|
||||||
shard: "shard1",
|
|
||||||
messages: { log: ["msg1"], results: [] },
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}, 50);
|
|
||||||
|
|
||||||
// Verify uploadArtifact was called with two files
|
|
||||||
await monitorConsole(api, {
|
|
||||||
...BASE_OPTS,
|
|
||||||
logToFile: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(artifact.create().uploadArtifact).toHaveBeenCalledWith(
|
|
||||||
"screeps-console-log",
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.stringContaining("shard0_console_log.txt"),
|
|
||||||
expect.stringContaining("shard1_console_log.txt"),
|
|
||||||
]),
|
|
||||||
expect.any(String),
|
|
||||||
{ continueOnError: true },
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
-34
@@ -40,40 +40,6 @@ inputs:
|
|||||||
git-replace:
|
git-replace:
|
||||||
description: Allows for the overwrite of the "{{gitRef}}", "{{gitHash}}" and "{{deployTime}}" values in the file matching the file pattern. The file pattern will be combined with the prefix.
|
description: Allows for the overwrite of the "{{gitRef}}", "{{gitHash}}" and "{{deployTime}}" values in the file matching the file pattern. The file pattern will be combined with the prefix.
|
||||||
required: false
|
required: false
|
||||||
shard:
|
|
||||||
description: The Screeps shard to monitor (e.g. shard0, shard1). Defaults to shard0 on the official server.
|
|
||||||
required: false
|
|
||||||
monitor:
|
|
||||||
description: Number of game ticks to monitor the Screeps console after deploying (0 = disabled).
|
|
||||||
required: false
|
|
||||||
default: '0'
|
|
||||||
log_to_file:
|
|
||||||
description: 'Buffer stdout to an artifact file instead of streaming live (default: false). Errors/warnings always stream live.'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
on_traceback:
|
|
||||||
description: 'Action on JS traceback detection: ignore, warn, or fail (default: fail).'
|
|
||||||
required: false
|
|
||||||
default: fail
|
|
||||||
on_error_log:
|
|
||||||
description: 'Action on Screeps error-console output: ignore, warn, or fail (default: warn).'
|
|
||||||
required: false
|
|
||||||
default: warn
|
|
||||||
on_warning_log:
|
|
||||||
description: 'Action on console.warn output: ignore, warn, or fail (default: ignore).'
|
|
||||||
required: false
|
|
||||||
default: ignore
|
|
||||||
monitor_interval:
|
|
||||||
description: 'Print a progress update every N ticks when log_to_file=true (default: 10).'
|
|
||||||
required: false
|
|
||||||
default: '10'
|
|
||||||
outputs:
|
|
||||||
saw_traceback:
|
|
||||||
description: true if a JS traceback was detected during monitoring.
|
|
||||||
saw_error_log:
|
|
||||||
description: true if the Screeps error console had output during monitoring.
|
|
||||||
saw_warning_log:
|
|
||||||
description: true if console.warn output was detected during monitoring.
|
|
||||||
runs:
|
runs:
|
||||||
using: node20
|
using: node20
|
||||||
main: dist/index.js
|
main: dist/index.js
|
||||||
|
|||||||
Vendored
+5
-15
File diff suppressed because one or more lines are too long
@@ -4,7 +4,6 @@ import fs from "fs";
|
|||||||
import { glob } from "glob";
|
import { glob } from "glob";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { monitorConsole } from "./monitor.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces specific placeholder strings within the provided content with corresponding dynamic values.
|
* Replaces specific placeholder strings within the provided content with corresponding dynamic values.
|
||||||
@@ -40,8 +39,7 @@ export function replacePlaceholders(content, hostname) {
|
|||||||
* @returns {Promise<string[]>} A promise that resolves with an array of file paths that were processed, or rejects with an error if the process fails.
|
* @returns {Promise<string[]>} A promise that resolves with an array of file paths that were processed, or rejects with an error if the process fails.
|
||||||
*/
|
*/
|
||||||
export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
||||||
let globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||||
globPattern = globPattern.replace(/\\/g, "/");
|
|
||||||
const files = await glob(globPattern);
|
const files = await glob(globPattern);
|
||||||
|
|
||||||
let processPromises = files.map((file) => {
|
let processPromises = files.map((file) => {
|
||||||
@@ -63,8 +61,7 @@ export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
|||||||
*/
|
*/
|
||||||
export async function readFilesIntoDict(pattern, prefix) {
|
export async function readFilesIntoDict(pattern, prefix) {
|
||||||
// Prepend the prefix to the glob pattern
|
// Prepend the prefix to the glob pattern
|
||||||
let globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||||
globPattern = globPattern.replace(/\\/g, "/");
|
|
||||||
const files = await glob(globPattern);
|
const files = await glob(globPattern);
|
||||||
|
|
||||||
let fileDict = {};
|
let fileDict = {};
|
||||||
@@ -111,26 +108,6 @@ export function validateAuthentication(token, username, password) {
|
|||||||
return null; // No errors found
|
return null; // No errors found
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the 'ignore' | 'warn' | 'fail' enum action when the given flag is true.
|
|
||||||
* Exported so it can be unit-tested independently.
|
|
||||||
*
|
|
||||||
* @param {'ignore'|'warn'|'fail'} action
|
|
||||||
* @param {boolean} flag - Only acts when true
|
|
||||||
* @param {string} message - Passed to core.warning / core.setFailed
|
|
||||||
*/
|
|
||||||
export function applyOnAction(action, flag, message) {
|
|
||||||
if (!flag) return;
|
|
||||||
if (action === "warn") {
|
|
||||||
core.warning(message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === "fail") {
|
|
||||||
core.setFailed(message);
|
|
||||||
}
|
|
||||||
// 'ignore' → no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Posts code to Screeps server.
|
* Posts code to Screeps server.
|
||||||
*/
|
*/
|
||||||
@@ -182,55 +159,21 @@ export async function postCode() {
|
|||||||
if (token) {
|
if (token) {
|
||||||
const response = await api.code.set(branch, files_to_push);
|
const response = await api.code.set(branch, files_to_push);
|
||||||
core.info(JSON.stringify(response, null, 2));
|
core.info(JSON.stringify(response, null, 2));
|
||||||
core.info(`Code set successfully to ${branch}`);
|
console.log(`Code set successfully to ${branch}`);
|
||||||
} else {
|
} else {
|
||||||
core.info(`Logging in as user ${username}`);
|
core.info(`Logging in as user ${username}`);
|
||||||
await Promise.resolve()
|
await Promise.resolve()
|
||||||
.then(() => api.auth(username, password, login_arguments))
|
.then(() => api.auth(username, password, login_arguments))
|
||||||
.then(() => api.code.set(branch, files_to_push))
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
core.info(`Code set successfully to ${branch}`);
|
api.code.set(branch, files_to_push);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log(`Code set successfully to ${branch}`);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
core.error(`Upload error: ${err}`);
|
console.error("Error:", err);
|
||||||
throw err;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Console monitoring (optional)
|
|
||||||
const monitorTicks = parseInt(core.getInput("monitor") || "0", 10);
|
|
||||||
if (monitorTicks > 0) {
|
|
||||||
const result = await monitorConsole(api, {
|
|
||||||
monitor: monitorTicks,
|
|
||||||
logToFile: core.getBooleanInput("log_to_file"),
|
|
||||||
onTraceback: core.getInput("on_traceback") || "fail",
|
|
||||||
onErrorLog: core.getInput("on_error_log") || "warn",
|
|
||||||
onWarningLog: core.getInput("on_warning_log") || "ignore",
|
|
||||||
monitorInterval: parseInt(core.getInput("monitor_interval") || "10", 10),
|
|
||||||
hostname,
|
|
||||||
shard: core.getInput("shard") || undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
core.setOutput("saw_traceback", String(result.sawTraceback));
|
|
||||||
core.setOutput("saw_error_log", String(result.sawErrorLog));
|
|
||||||
core.setOutput("saw_warning_log", String(result.sawWarningLog));
|
|
||||||
|
|
||||||
applyOnAction(
|
|
||||||
core.getInput("on_traceback"),
|
|
||||||
result.sawTraceback,
|
|
||||||
"Screeps console: traceback detected",
|
|
||||||
);
|
|
||||||
applyOnAction(
|
|
||||||
core.getInput("on_error_log"),
|
|
||||||
result.sawErrorLog,
|
|
||||||
"Screeps console: error log output detected",
|
|
||||||
);
|
|
||||||
applyOnAction(
|
|
||||||
core.getInput("on_warning_log"),
|
|
||||||
result.sawWarningLog,
|
|
||||||
"Screeps console: warning log output detected",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
|||||||
-420
@@ -1,420 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
import { create } from "@actions/artifact";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import os from "os";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the hostname is the official Screeps server.
|
|
||||||
* Used to decide whether to prefix the subscribe path with a shard name.
|
|
||||||
*
|
|
||||||
* @param {string} hostname - e.g. "screeps.com" or "builder64"
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isOfficialServer(hostname) {
|
|
||||||
return hostname === "screeps.com";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the channel path argument passed to socket.subscribe().
|
|
||||||
*
|
|
||||||
* The screeps-api socket automatically prefixes `user:<id>/` when the path
|
|
||||||
* does not match the `type:id` pattern, so we only supply the channel part:
|
|
||||||
* If shard is provided → "<shard>/console"
|
|
||||||
* Official server → "shard0/console" (if no shard provided)
|
|
||||||
* Private server → "console" (if no shard provided)
|
|
||||||
*
|
|
||||||
* @param {string} hostname
|
|
||||||
* @param {string} [shard]
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function buildSubscribePath(hostname, shard) {
|
|
||||||
// The console channel on Screeps official and most private servers is 'console'.
|
|
||||||
// We subscribe to the aggregate feed and filter by shard in handleConsoleEvent.
|
|
||||||
return "console";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true when errorText contains JavaScript stack-frame lines.
|
|
||||||
* Screeps places runtime errors (including stack traces) in event.data.error.
|
|
||||||
* A traceback is identified by lines beginning with four spaces followed by "at ".
|
|
||||||
*
|
|
||||||
* @param {string|null|undefined} errorText - Contents of event.data.error
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function detectTraceback(errorText) {
|
|
||||||
if (!errorText) return false;
|
|
||||||
const text = safeDecode(errorText);
|
|
||||||
return /^\s{4}at /m.test(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true when any log line contains Screeps console.warn markup.
|
|
||||||
* Screeps wraps console.warn() output in orange or yellow <font> HTML tags.
|
|
||||||
*
|
|
||||||
* @param {string[]|null|undefined} logLines - Contents of event.data.messages.log
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function detectWarning(logLines) {
|
|
||||||
if (!logLines || logLines.length === 0) return false;
|
|
||||||
const warnPattern = /<font\s+color=['"](?:orange|yellow)['"]/i;
|
|
||||||
return logLines.some((line) => warnPattern.test(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safely decodes a URI-encoded string from the Screeps console.
|
|
||||||
* Returns the original string if decoding fails or if no '%' is present.
|
|
||||||
*
|
|
||||||
* @param {string} text
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function safeDecode(text) {
|
|
||||||
if (typeof text !== "string") return text;
|
|
||||||
let result = text;
|
|
||||||
if (result.includes("%")) {
|
|
||||||
try {
|
|
||||||
result = decodeURIComponent(result);
|
|
||||||
} catch (err) {
|
|
||||||
// Ignore decoding errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Screeps console often contains HTML entities
|
|
||||||
return result
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">")
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/&/g, "&");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs text to the action log, splitting by newline to ensure proper display.
|
|
||||||
* Optionally prepends a [shard] prefix.
|
|
||||||
*
|
|
||||||
* @param {string} text
|
|
||||||
* @param {"info"|"warning"|"error"} level
|
|
||||||
* @param {string} [shard]
|
|
||||||
*/
|
|
||||||
export function outputMultiline(text, level = "info", shard = null) {
|
|
||||||
if (!text) return;
|
|
||||||
const prefix = shard ? `[${shard}] ` : "";
|
|
||||||
const lines = text.split(/\r?\n/);
|
|
||||||
lines.forEach((line) => {
|
|
||||||
const formattedLine = `${prefix}${line}`;
|
|
||||||
if (level === "error") core.error(formattedLine);
|
|
||||||
else if (level === "warning") core.warning(formattedLine);
|
|
||||||
else core.info(formattedLine);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a CI-friendly progress string for core.info().
|
|
||||||
*
|
|
||||||
* @param {number} elapsed - Ticks elapsed since monitoring started
|
|
||||||
* @param {number} total - Total ticks to monitor
|
|
||||||
* @returns {string} - e.g. "[Monitor] 10/50 ticks elapsed..."
|
|
||||||
*/
|
|
||||||
export function buildProgressMessage(elapsed, total) {
|
|
||||||
return `[Monitor] ${elapsed}/${total} ticks elapsed...`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an array of log lines to a UTF-8 text file, one line per entry.
|
|
||||||
*
|
|
||||||
* @param {string[]} lines - Lines to write
|
|
||||||
* @param {string} filePath - Absolute path to write to
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function writeLogFile(lines, filePath) {
|
|
||||||
await fs.promises.writeFile(filePath, lines.join("\n"), "utf8");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploads one or more files as a named workflow artifact using @actions/artifact.
|
|
||||||
* Degrades gracefully to core.warning() if the runner does not support the
|
|
||||||
* artifact service.
|
|
||||||
*
|
|
||||||
* @param {string[]} filePaths - Absolute paths of the files to upload
|
|
||||||
* @param {string} [artifactName="screeps-console-log"] - Artifact display name
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function uploadLogArtifacts(
|
|
||||||
filePaths,
|
|
||||||
artifactName = "screeps-console-log",
|
|
||||||
) {
|
|
||||||
if (!filePaths || filePaths.length === 0) return;
|
|
||||||
try {
|
|
||||||
const client = create();
|
|
||||||
const rootDir = path.dirname(filePaths[0]);
|
|
||||||
await client.uploadArtifact(artifactName, filePaths, rootDir, {
|
|
||||||
continueOnError: true,
|
|
||||||
});
|
|
||||||
core.info(`[Monitor] Console logs uploaded as artifact '${artifactName}'.`);
|
|
||||||
} catch (err) {
|
|
||||||
core.warning(
|
|
||||||
`[Monitor] Could not upload console logs as artifact: ${err.message}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes a single 'console' WebSocket event from the Screeps socket.
|
|
||||||
* Mutates `state` and `stdoutBuffer` in place; never throws.
|
|
||||||
*
|
|
||||||
* WebSocket event.data shape:
|
|
||||||
* {
|
|
||||||
* messages: {
|
|
||||||
* log: string[], // stdout (console.warn included with HTML markup)
|
|
||||||
* results: string[], // return values of console-evaluated expressions
|
|
||||||
* },
|
|
||||||
* error: string | null, // stderr, runtime errors, tracebacks
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Behaviour:
|
|
||||||
* - Warn lines (orange/yellow <font> tags) → always core.warning() (live),
|
|
||||||
* sets state.sawWarningLog, still included in stdoutBuffer / core.info().
|
|
||||||
* - Error field → always core.error() (live), sets state.sawErrorLog.
|
|
||||||
* If a stack frame is detected → also sets state.sawTraceback.
|
|
||||||
* - All stdout lines → core.info() when logToFile=false,
|
|
||||||
* pushed to stdoutBuffer when logToFile=true.
|
|
||||||
*
|
|
||||||
* @param {{ data?: { messages?: { log?: string[], results?: string[] }, error?: string, shard?: string } }} event
|
|
||||||
* @param {{ logToFile: boolean, shard?: string }} opts
|
|
||||||
* @param {Record<string, string[]>} shardBuffers - Mutable buffer Map used in logToFile mode
|
|
||||||
* @param {{ sawTraceback: boolean, sawErrorLog: boolean, sawWarningLog: boolean }} state
|
|
||||||
*/
|
|
||||||
export function handleConsoleEvent(event, opts, shardBuffers, state) {
|
|
||||||
const { logToFile, shard: targetShard } = opts;
|
|
||||||
const data = event?.data ?? {};
|
|
||||||
|
|
||||||
// Shard filtering: If a shard is specified in opts, only process messages from that shard.
|
|
||||||
// Official server events include a 'shard' property in event.data.
|
|
||||||
if (targetShard && data.shard && data.shard !== targetShard) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const logLines = data?.messages?.log ?? [];
|
|
||||||
const results = data?.messages?.results ?? [];
|
|
||||||
const errorText = data?.error ?? null;
|
|
||||||
|
|
||||||
// Warn detection (always live regardless of logToFile)
|
|
||||||
if (detectWarning(logLines)) {
|
|
||||||
state.sawWarningLog = true;
|
|
||||||
const warnPattern = /<font\s+color=['"](?:orange|yellow)['"]/i;
|
|
||||||
logLines
|
|
||||||
.filter((l) => warnPattern.test(l))
|
|
||||||
.forEach((l) => outputMultiline(safeDecode(l), "warning", data.shard));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traceback detection in log lines (Screeps sometimes sends errors here)
|
|
||||||
if (logLines.some((l) => detectTraceback(l))) {
|
|
||||||
state.sawTraceback = true;
|
|
||||||
state.sawErrorLog = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stdout lines
|
|
||||||
const allStdout = [...logLines, ...results].map(safeDecode);
|
|
||||||
if (allStdout.length > 0) {
|
|
||||||
if (logToFile) {
|
|
||||||
const shard = data.shard || "default";
|
|
||||||
if (!shardBuffers[shard]) shardBuffers[shard] = [];
|
|
||||||
shardBuffers[shard].push(...allStdout);
|
|
||||||
} else {
|
|
||||||
allStdout.forEach((l) => outputMultiline(l, "info", data.shard));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error field (always live)
|
|
||||||
if (errorText) {
|
|
||||||
state.sawErrorLog = true;
|
|
||||||
const decodedError = safeDecode(errorText);
|
|
||||||
outputMultiline(decodedError, "error", data.shard);
|
|
||||||
if (detectTraceback(decodedError)) {
|
|
||||||
state.sawTraceback = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sleeps for the given number of milliseconds.
|
|
||||||
*
|
|
||||||
* @param {number} ms
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
function sleep(ms) {
|
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polls GET /api/game/time every `intervalMs` milliseconds until the tick
|
|
||||||
* delta (currentTick - startTick) reaches or exceeds `targetTicks`.
|
|
||||||
* Calls `onProgress(elapsed, targetTicks)` on every poll so the caller can
|
|
||||||
* log progress at whatever cadence it chooses.
|
|
||||||
*
|
|
||||||
* @param {import('screeps-api').ScreepsAPI} api
|
|
||||||
* @param {number} startTick - Tick number recorded before monitoring started
|
|
||||||
* @param {number} targetTicks - Stop when (currentTick - startTick) >= this
|
|
||||||
* @param {string|undefined} shard - "shard0" for official, undefined for private
|
|
||||||
* @param {number} intervalMs - Poll interval in milliseconds
|
|
||||||
* @param {(elapsed: number, total: number) => void} onProgress
|
|
||||||
* @returns {Promise<number>} Final elapsed tick count
|
|
||||||
*/
|
|
||||||
export async function pollUntilDone(
|
|
||||||
api,
|
|
||||||
startTick,
|
|
||||||
targetTicks,
|
|
||||||
shard,
|
|
||||||
intervalMs,
|
|
||||||
onProgress,
|
|
||||||
shouldStop = () => false,
|
|
||||||
) {
|
|
||||||
let elapsed = 0;
|
|
||||||
while (elapsed < targetTicks && !shouldStop()) {
|
|
||||||
await sleep(intervalMs);
|
|
||||||
const { time } = await api.time(shard);
|
|
||||||
elapsed = time - startTick;
|
|
||||||
onProgress(elapsed, targetTicks);
|
|
||||||
}
|
|
||||||
return elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} MonitorOptions
|
|
||||||
* @property {number} monitor - Number of game ticks to collect.
|
|
||||||
* @property {boolean} logToFile - Buffer stdout to artifact instead of streaming.
|
|
||||||
* @property {'ignore'|'warn'|'fail'} onTraceback - Action on traceback detection.
|
|
||||||
* @property {'ignore'|'warn'|'fail'} onErrorLog - Action on any error-console output.
|
|
||||||
* @property {'ignore'|'warn'|'fail'} onWarningLog - Action on console.warn output.
|
|
||||||
* @property {number} monitorInterval - Print a progress update every N ticks.
|
|
||||||
* @property {string} hostname - Screeps hostname (for shard derivation).
|
|
||||||
* @property {string} [shard] - Optional shard to monitor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} MonitorResult
|
|
||||||
* @property {boolean} sawTraceback - True if a JS stack trace was detected.
|
|
||||||
* @property {boolean} sawErrorLog - True if the error console had any output.
|
|
||||||
* @property {boolean} sawWarningLog - True if console.warn output was detected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitors the Screeps console for a given number of game ticks after a deploy.
|
|
||||||
*
|
|
||||||
* Flow:
|
|
||||||
* 1. Fetch startTick via GET /api/game/time (REST poll).
|
|
||||||
* 2. Connect WebSocket and subscribe to the console channel.
|
|
||||||
* 3. Run the tick-poll loop (500 ms interval) concurrently with the socket
|
|
||||||
* event listener; the poll loop drives the stop condition.
|
|
||||||
* 4. On each 'console' WebSocket event, delegate to handleConsoleEvent().
|
|
||||||
* 5. When poll finishes, disconnect socket cleanly (in a finally block).
|
|
||||||
* 6. If logToFile=true: write buffered stdout to a temp file and upload artifact.
|
|
||||||
* 7. Return MonitorResult.
|
|
||||||
*
|
|
||||||
* @param {import('screeps-api').ScreepsAPI} api
|
|
||||||
* @param {MonitorOptions} opts
|
|
||||||
* @returns {Promise<MonitorResult>}
|
|
||||||
*/
|
|
||||||
export async function monitorConsole(api, opts) {
|
|
||||||
const {
|
|
||||||
monitor,
|
|
||||||
logToFile,
|
|
||||||
monitorInterval,
|
|
||||||
hostname,
|
|
||||||
shard: providedShard,
|
|
||||||
} = opts;
|
|
||||||
|
|
||||||
// Use provided shard, or fall back to shard0 for official, or undefined for private
|
|
||||||
const shard =
|
|
||||||
providedShard || (isOfficialServer(hostname) ? "shard0" : undefined);
|
|
||||||
const subscribePath = buildSubscribePath(hostname, providedShard);
|
|
||||||
|
|
||||||
// Shared mutable state — updated by handleConsoleEvent via event listener
|
|
||||||
const shardBuffers = {}; // { [shardName]: string[] }
|
|
||||||
const state = {
|
|
||||||
sawTraceback: false,
|
|
||||||
sawErrorLog: false,
|
|
||||||
sawWarningLog: false,
|
|
||||||
};
|
|
||||||
let lastProgressTick = 0;
|
|
||||||
|
|
||||||
// Step 1: record starting tick
|
|
||||||
const { time: startTick } = await api.time(shard);
|
|
||||||
|
|
||||||
// Step 2: connect socket + subscribe
|
|
||||||
await api.socket.connect();
|
|
||||||
await api.socket.subscribe(subscribePath, (event) => {
|
|
||||||
handleConsoleEvent(event, opts, shardBuffers, state);
|
|
||||||
});
|
|
||||||
|
|
||||||
core.info(
|
|
||||||
`[Monitor] Watching Screeps console for ${monitor} ticks` +
|
|
||||||
(shard ? ` on ${shard}` : "") +
|
|
||||||
"...",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 3 & 4: tick-poll loop
|
|
||||||
try {
|
|
||||||
await pollUntilDone(
|
|
||||||
api,
|
|
||||||
startTick,
|
|
||||||
monitor,
|
|
||||||
shard,
|
|
||||||
500,
|
|
||||||
(elapsed, total) => {
|
|
||||||
// Print progress at configured interval boundaries
|
|
||||||
if (
|
|
||||||
elapsed > 0 &&
|
|
||||||
elapsed >= lastProgressTick + monitorInterval &&
|
|
||||||
elapsed <= total
|
|
||||||
) {
|
|
||||||
core.info(buildProgressMessage(elapsed, total));
|
|
||||||
lastProgressTick = elapsed;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
// Fail-fast logic: stop monitoring if any 'fail' action is triggered
|
|
||||||
if (opts.onTraceback === "fail" && state.sawTraceback) return true;
|
|
||||||
if (opts.onErrorLog === "fail" && state.sawErrorLog) return true;
|
|
||||||
if (opts.onWarningLog === "fail" && state.sawWarningLog) return true;
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
// Step 5: always disconnect cleanly
|
|
||||||
api.socket.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6: artifact upload
|
|
||||||
const shardKeys = Object.keys(shardBuffers);
|
|
||||||
if (logToFile && shardKeys.length > 0) {
|
|
||||||
const tmpDir = await fs.promises.mkdtemp(
|
|
||||||
path.join(os.tmpdir(), "screeps-monitor-"),
|
|
||||||
);
|
|
||||||
const filePaths = [];
|
|
||||||
|
|
||||||
for (const sName of shardKeys) {
|
|
||||||
const fileName =
|
|
||||||
sName === "default"
|
|
||||||
? "screeps_console_log.txt"
|
|
||||||
: `${sName}_console_log.txt`;
|
|
||||||
const tmpFile = path.join(tmpDir, fileName);
|
|
||||||
await writeLogFile(shardBuffers[sName], tmpFile);
|
|
||||||
filePaths.push(tmpFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
await uploadLogArtifacts(filePaths);
|
|
||||||
} else if (logToFile) {
|
|
||||||
core.info(
|
|
||||||
"[Monitor] No stdout lines were collected; skipping artifact upload.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(
|
|
||||||
`[Monitor] Done. sawTraceback=${state.sawTraceback} sawErrorLog=${state.sawErrorLog} sawWarningLog=${state.sawWarningLog}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
sawTraceback: state.sawTraceback,
|
|
||||||
sawErrorLog: state.sawErrorLog,
|
|
||||||
sawWarningLog: state.sawWarningLog,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Generated
+171
-295
@@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "screeps-deploy-action",
|
"name": "screeps-deploy-action",
|
||||||
"version": "0.2.1",
|
"version": "0.1.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "screeps-deploy-action",
|
"name": "screeps-deploy-action",
|
||||||
"version": "0.2.1",
|
"version": "0.1.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^1.1.2",
|
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"glob": "^13.0.0",
|
"glob": "^13.0.0",
|
||||||
"screeps-api": "^1.7.2"
|
"screeps-api": "^1.7.2"
|
||||||
@@ -19,69 +18,10 @@
|
|||||||
"vitest": "^4.0.16"
|
"vitest": "^4.0.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/artifact": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-upUEBnt+yuKKprr+K0LyigDyNJMNdXdWZaID6oGrmftaWJfG0TdKwj2BEHuUpn3J2teNpOTvvy7AGNtw+sykCQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/core": "^1.9.1",
|
|
||||||
"@actions/http-client": "^2.0.1",
|
|
||||||
"tmp": "^0.2.1",
|
|
||||||
"tmp-promise": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/artifact/node_modules/@actions/core": {
|
|
||||||
"version": "1.11.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
|
|
||||||
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/exec": "^1.1.1",
|
|
||||||
"@actions/http-client": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/artifact/node_modules/@actions/exec": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/io": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/artifact/node_modules/@actions/http-client": {
|
|
||||||
"version": "2.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
|
|
||||||
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"tunnel": "^0.0.6",
|
|
||||||
"undici": "^5.25.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/artifact/node_modules/@actions/io": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@actions/artifact/node_modules/undici": {
|
|
||||||
"version": "5.29.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
|
||||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@fastify/busboy": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/core": {
|
"node_modules/@actions/core": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.0.tgz",
|
||||||
"integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==",
|
"integrity": "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/exec": "^3.0.0",
|
"@actions/exec": "^3.0.0",
|
||||||
@@ -174,48 +114,42 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.10.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
|
||||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
"integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
"@emnapi/wasi-threads": "1.2.0",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.10.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
|
||||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
"integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/wasi-threads": {
|
"node_modules/@emnapi/wasi-threads": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
|
||||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
"integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fastify/busboy": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
|
||||||
@@ -254,9 +188,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz",
|
||||||
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
|
"integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -273,9 +207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.129.0",
|
"version": "0.122.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz",
|
||||||
"integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==",
|
"integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -283,9 +217,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==",
|
"integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -300,9 +234,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==",
|
"integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -317,9 +251,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==",
|
"integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -334,9 +268,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==",
|
"integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -351,9 +285,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==",
|
"integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -368,16 +302,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==",
|
"integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -388,16 +319,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==",
|
"integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -408,16 +336,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==",
|
"integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -428,16 +353,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==",
|
"integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -448,16 +370,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==",
|
"integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -468,16 +387,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==",
|
"integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -488,9 +404,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==",
|
"integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -505,9 +421,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==",
|
"integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@@ -515,18 +431,16 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/core": "1.10.0",
|
"@napi-rs/wasm-runtime": "^1.1.1"
|
||||||
"@emnapi/runtime": "1.10.0",
|
|
||||||
"@napi-rs/wasm-runtime": "^1.1.4"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==",
|
"integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -541,9 +455,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==",
|
"integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -558,9 +472,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/pluginutils": {
|
"node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==",
|
"integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -572,9 +486,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -618,14 +532,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/coverage-v8": {
|
"node_modules/@vitest/coverage-v8": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.1.tgz",
|
||||||
"integrity": "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==",
|
"integrity": "sha512-nZ4RWwGCoGOQRMmU/Q9wlUY540RVRxJZ9lxFsFfy0QV7Zmo5VVBhB6Sl9Xa0KIp2iIs3zWfPlo9LcY1iqbpzCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bcoe/v8-coverage": "^1.0.2",
|
"@bcoe/v8-coverage": "^1.0.2",
|
||||||
"@vitest/utils": "4.1.6",
|
"@vitest/utils": "4.1.1",
|
||||||
"ast-v8-to-istanbul": "^1.0.0",
|
"ast-v8-to-istanbul": "^1.0.0",
|
||||||
"istanbul-lib-coverage": "^3.2.2",
|
"istanbul-lib-coverage": "^3.2.2",
|
||||||
"istanbul-lib-report": "^3.0.1",
|
"istanbul-lib-report": "^3.0.1",
|
||||||
@@ -633,14 +547,14 @@
|
|||||||
"magicast": "^0.5.2",
|
"magicast": "^0.5.2",
|
||||||
"obug": "^2.1.1",
|
"obug": "^2.1.1",
|
||||||
"std-env": "^4.0.0-rc.1",
|
"std-env": "^4.0.0-rc.1",
|
||||||
"tinyrainbow": "^3.1.0"
|
"tinyrainbow": "^3.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vitest/browser": "4.1.6",
|
"@vitest/browser": "4.1.1",
|
||||||
"vitest": "4.1.6"
|
"vitest": "4.1.1"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@vitest/browser": {
|
"@vitest/browser": {
|
||||||
@@ -649,31 +563,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/expect": {
|
"node_modules/@vitest/expect": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.1.tgz",
|
||||||
"integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==",
|
"integrity": "sha512-xAV0fqBTk44Rn6SjJReEQkHP3RrqbJo6JQ4zZ7/uVOiJZRarBtblzrOfFIZeYUrukp2YD6snZG6IBqhOoHTm+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standard-schema/spec": "^1.1.0",
|
"@standard-schema/spec": "^1.1.0",
|
||||||
"@types/chai": "^5.2.2",
|
"@types/chai": "^5.2.2",
|
||||||
"@vitest/spy": "4.1.6",
|
"@vitest/spy": "4.1.1",
|
||||||
"@vitest/utils": "4.1.6",
|
"@vitest/utils": "4.1.1",
|
||||||
"chai": "^6.2.2",
|
"chai": "^6.2.2",
|
||||||
"tinyrainbow": "^3.1.0"
|
"tinyrainbow": "^3.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/mocker": {
|
"node_modules/@vitest/mocker": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.1.tgz",
|
||||||
"integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==",
|
"integrity": "sha512-h3BOylsfsCLPeceuCPAAJ+BvNwSENgJa4hXoXu4im0bs9Lyp4URc4JYK4pWLZ4pG/UQn7AT92K6IByi6rE6g3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/spy": "4.1.6",
|
"@vitest/spy": "4.1.1",
|
||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
"magic-string": "^0.30.21"
|
"magic-string": "^0.30.21"
|
||||||
},
|
},
|
||||||
@@ -694,26 +608,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/pretty-format": {
|
"node_modules/@vitest/pretty-format": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.1.tgz",
|
||||||
"integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==",
|
"integrity": "sha512-GM+TEQN5WhOygr1lp7skeVjdLPqqWMHsfzXrcHAqZJi/lIVh63H0kaRCY8MDhNWikx19zBUK8ceaLB7X5AH9NQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tinyrainbow": "^3.1.0"
|
"tinyrainbow": "^3.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/runner": {
|
"node_modules/@vitest/runner": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.1.tgz",
|
||||||
"integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==",
|
"integrity": "sha512-f7+FPy75vN91QGWsITueq0gedwUZy1fLtHOCMeQpjs8jTekAHeKP80zfDEnhrleviLHzVSDXIWuCIOFn3D3f8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/utils": "4.1.6",
|
"@vitest/utils": "4.1.1",
|
||||||
"pathe": "^2.0.3"
|
"pathe": "^2.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -721,14 +635,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/snapshot": {
|
"node_modules/@vitest/snapshot": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.1.tgz",
|
||||||
"integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==",
|
"integrity": "sha512-kMVSgcegWV2FibXEx9p9WIKgje58lcTbXgnJixfcg15iK8nzCXhmalL0ZLtTWLW9PH1+1NEDShiFFedB3tEgWg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/pretty-format": "4.1.6",
|
"@vitest/pretty-format": "4.1.1",
|
||||||
"@vitest/utils": "4.1.6",
|
"@vitest/utils": "4.1.1",
|
||||||
"magic-string": "^0.30.21",
|
"magic-string": "^0.30.21",
|
||||||
"pathe": "^2.0.3"
|
"pathe": "^2.0.3"
|
||||||
},
|
},
|
||||||
@@ -737,9 +651,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/spy": {
|
"node_modules/@vitest/spy": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.1.tgz",
|
||||||
"integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==",
|
"integrity": "sha512-6Ti/KT5OVaiupdIZEuZN7l3CZcR0cxnxt70Z0//3CtwgObwA6jZhmVBA3yrXSVN3gmwjgd7oDNLlsXz526gpRA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -747,15 +661,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/utils": {
|
"node_modules/@vitest/utils": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.1.tgz",
|
||||||
"integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==",
|
"integrity": "sha512-cNxAlaB3sHoCdL6pj6yyUXv9Gry1NHNg0kFTXdvSIZXLHsqKH7chiWOkwJ5s5+d/oMwcoG9T0bKU38JZWKusrQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/pretty-format": "4.1.6",
|
"@vitest/pretty-format": "4.1.1",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"tinyrainbow": "^3.1.0"
|
"tinyrainbow": "^3.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
@@ -1445,9 +1359,6 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1469,9 +1380,6 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1493,9 +1401,6 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1517,9 +1422,6 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1707,9 +1609,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.12",
|
"version": "3.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1810,9 +1712,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.14",
|
"version": "8.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
||||||
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1845,14 +1747,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0-rc.12",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz",
|
||||||
"integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==",
|
"integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.129.0",
|
"@oxc-project/types": "=0.122.0",
|
||||||
"@rolldown/pluginutils": "1.0.0"
|
"@rolldown/pluginutils": "1.0.0-rc.12"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rolldown": "bin/cli.mjs"
|
"rolldown": "bin/cli.mjs"
|
||||||
@@ -1861,21 +1763,21 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm64": "1.0.0",
|
"@rolldown/binding-android-arm64": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-darwin-arm64": "1.0.0",
|
"@rolldown/binding-darwin-arm64": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-darwin-x64": "1.0.0",
|
"@rolldown/binding-darwin-x64": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-freebsd-x64": "1.0.0",
|
"@rolldown/binding-freebsd-x64": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0",
|
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.0.0",
|
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0",
|
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0",
|
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.0.0",
|
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.0.0",
|
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.0.0",
|
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-wasm32-wasi": "1.0.0",
|
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0",
|
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.0.0"
|
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/screeps-api": {
|
"node_modules/screeps-api": {
|
||||||
@@ -1979,14 +1881,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.16",
|
"version": "0.2.15",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
"picomatch": "^4.0.4"
|
"picomatch": "^4.0.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
@@ -1996,33 +1898,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyrainbow": {
|
"node_modules/tinyrainbow": {
|
||||||
"version": "3.1.0",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
|
||||||
"integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
|
"integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tmp": {
|
|
||||||
"version": "0.2.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
|
|
||||||
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tmp-promise": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"tmp": "^0.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
@@ -2064,17 +1948,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.0.12",
|
"version": "8.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz",
|
||||||
"integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==",
|
"integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.4",
|
||||||
"postcss": "^8.5.14",
|
"postcss": "^8.5.8",
|
||||||
"rolldown": "1.0.0",
|
"rolldown": "1.0.0-rc.12",
|
||||||
"tinyglobby": "^0.2.16"
|
"tinyglobby": "^0.2.15"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -2090,8 +1974,8 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^20.19.0 || >=22.12.0",
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
"@vitejs/devtools": "^0.1.18",
|
"@vitejs/devtools": "^0.1.0",
|
||||||
"esbuild": "^0.27.0 || ^0.28.0",
|
"esbuild": "^0.27.0",
|
||||||
"jiti": ">=1.21.0",
|
"jiti": ">=1.21.0",
|
||||||
"less": "^4.0.0",
|
"less": "^4.0.0",
|
||||||
"sass": "^1.70.0",
|
"sass": "^1.70.0",
|
||||||
@@ -2142,19 +2026,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vitest": {
|
"node_modules/vitest": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.1.tgz",
|
||||||
"integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==",
|
"integrity": "sha512-yF+o4POL41rpAzj5KVILUxm1GCjKnELvaqmU9TLLUbMfDzuN0UpUR9uaDs+mCtjPe+uYPksXDRLQGGPvj1cTmA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/expect": "4.1.6",
|
"@vitest/expect": "4.1.1",
|
||||||
"@vitest/mocker": "4.1.6",
|
"@vitest/mocker": "4.1.1",
|
||||||
"@vitest/pretty-format": "4.1.6",
|
"@vitest/pretty-format": "4.1.1",
|
||||||
"@vitest/runner": "4.1.6",
|
"@vitest/runner": "4.1.1",
|
||||||
"@vitest/snapshot": "4.1.6",
|
"@vitest/snapshot": "4.1.1",
|
||||||
"@vitest/spy": "4.1.6",
|
"@vitest/spy": "4.1.1",
|
||||||
"@vitest/utils": "4.1.6",
|
"@vitest/utils": "4.1.1",
|
||||||
"es-module-lexer": "^2.0.0",
|
"es-module-lexer": "^2.0.0",
|
||||||
"expect-type": "^1.3.0",
|
"expect-type": "^1.3.0",
|
||||||
"magic-string": "^0.30.21",
|
"magic-string": "^0.30.21",
|
||||||
@@ -2165,7 +2049,7 @@
|
|||||||
"tinybench": "^2.9.0",
|
"tinybench": "^2.9.0",
|
||||||
"tinyexec": "^1.0.2",
|
"tinyexec": "^1.0.2",
|
||||||
"tinyglobby": "^0.2.15",
|
"tinyglobby": "^0.2.15",
|
||||||
"tinyrainbow": "^3.1.0",
|
"tinyrainbow": "^3.0.3",
|
||||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||||
"why-is-node-running": "^2.3.0"
|
"why-is-node-running": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -2182,12 +2066,10 @@
|
|||||||
"@edge-runtime/vm": "*",
|
"@edge-runtime/vm": "*",
|
||||||
"@opentelemetry/api": "^1.9.0",
|
"@opentelemetry/api": "^1.9.0",
|
||||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||||
"@vitest/browser-playwright": "4.1.6",
|
"@vitest/browser-playwright": "4.1.1",
|
||||||
"@vitest/browser-preview": "4.1.6",
|
"@vitest/browser-preview": "4.1.1",
|
||||||
"@vitest/browser-webdriverio": "4.1.6",
|
"@vitest/browser-webdriverio": "4.1.1",
|
||||||
"@vitest/coverage-istanbul": "4.1.6",
|
"@vitest/ui": "4.1.1",
|
||||||
"@vitest/coverage-v8": "4.1.6",
|
|
||||||
"@vitest/ui": "4.1.6",
|
|
||||||
"happy-dom": "*",
|
"happy-dom": "*",
|
||||||
"jsdom": "*",
|
"jsdom": "*",
|
||||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
@@ -2211,12 +2093,6 @@
|
|||||||
"@vitest/browser-webdriverio": {
|
"@vitest/browser-webdriverio": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@vitest/coverage-istanbul": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@vitest/coverage-v8": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@vitest/ui": {
|
"@vitest/ui": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-3
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "screeps-deploy-action",
|
"name": "screeps-deploy-action",
|
||||||
"version": "0.2.1",
|
"version": "0.1.1",
|
||||||
"description": "Deploys screeps code to the official game or a private server.",
|
"description": "Deploys screeps code to the official game or an pirvate server.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
"build": "ncc build index.js -o dist -m --external utf-8-validate --external bufferutil"
|
"build": "ncc build index.js -o dist -m --external utf-8-validate --external bufferutil"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^1.1.2",
|
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"glob": "^13.0.0",
|
"glob": "^13.0.0",
|
||||||
"screeps-api": "^1.7.2"
|
"screeps-api": "^1.7.2"
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { glob } from "glob";
|
|
||||||
import path from "path";
|
|
||||||
import os from "os";
|
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
async function test() {
|
|
||||||
const tempDir = await fs.promises.mkdtemp(
|
|
||||||
path.join(os.tmpdir(), "glob-test-"),
|
|
||||||
);
|
|
||||||
const file = path.join(tempDir, "test.js");
|
|
||||||
await fs.promises.writeFile(file, "test");
|
|
||||||
|
|
||||||
const pattern = "*.js";
|
|
||||||
const globPattern = path.join(tempDir, pattern);
|
|
||||||
console.log("globPattern:", globPattern);
|
|
||||||
|
|
||||||
const files = await glob(globPattern);
|
|
||||||
console.log("found files:", files);
|
|
||||||
|
|
||||||
// Fix for windows
|
|
||||||
const fixedPattern = globPattern.replace(/\\/g, "/");
|
|
||||||
console.log("fixedPattern:", fixedPattern);
|
|
||||||
const fixedFiles = await glob(fixedPattern);
|
|
||||||
console.log("found fixed files:", fixedFiles);
|
|
||||||
|
|
||||||
await fs.promises.rm(tempDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
test();
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
function detectTraceback(errorText) {
|
|
||||||
if (!errorText) return false;
|
|
||||||
return /^\s{4}at /m.test(errorText);
|
|
||||||
}
|
|
||||||
|
|
||||||
const encodedTraceback =
|
|
||||||
"Error: ReferenceError: a is not defined%0A at eval (eval at <anonymous> (_console1778948572008_0:1:46), <anonymous>:1:1)%0A at _console1778948572008_0:1:46%0A at _console1778948572008_0:1:60%0A at exports.evalCode (<runtime>:15347:63)%0A at exports.run (<runtime>:20876:41)%0A";
|
|
||||||
|
|
||||||
console.log("Encoded match:", detectTraceback(encodedTraceback));
|
|
||||||
|
|
||||||
const decodedTraceback = decodeURIComponent(encodedTraceback);
|
|
||||||
console.log("Decoded match:", detectTraceback(decodedTraceback));
|
|
||||||
Reference in New Issue
Block a user