Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4adb6ad9b | ||
|
|
9dcad628d4 | ||
|
|
c9b5d215f6 | ||
|
|
e8534d7fae | ||
|
|
873de41ead | ||
|
|
36e34e99c5 | ||
|
|
2292b914ad | ||
|
|
bdd0fbfd7e | ||
|
|
df5d81df5c | ||
|
|
0b930f5645 | ||
|
|
67f3f15c2b | ||
|
|
d0a08da728 | ||
|
|
076e96f3de | ||
|
|
bf52580bf3 | ||
|
|
be3c8ac7d2 |
No files matched your search
@@ -0,0 +1,6 @@
|
||||
# .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
|
||||
@@ -9,8 +9,8 @@ jobs:
|
||||
name: pre-commit Linting
|
||||
runs-on: pi
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
- run: pip install pre-commit
|
||||
shell: bash
|
||||
- name: Pre Commit
|
||||
|
||||
@@ -9,8 +9,8 @@ jobs:
|
||||
name: Run Tests
|
||||
runs-on: pi
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
||||
with:
|
||||
node-version: '24'
|
||||
- run: npm install
|
||||
|
||||
@@ -1078,3 +1078,6 @@ FodyWeavers.xsd
|
||||
/node_modules/.cache/
|
||||
/coverage/
|
||||
!/dist/
|
||||
|
||||
# Local test credentials — never commit
|
||||
.env.test
|
||||
@@ -29,7 +29,7 @@ repos:
|
||||
types_or: [css, javascript]
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.37.2
|
||||
rev: 0.37.4
|
||||
hooks:
|
||||
- id: check-renovate
|
||||
- id: check-github-actions
|
||||
|
||||
@@ -6,6 +6,7 @@ This repository is maintained by Gemini.
|
||||
|
||||
* **Test-Driven Development (TDD):** Wherever possible, Test-Driven Development principles should be followed. Write tests before writing the code they are intended to validate.
|
||||
* **Pre-commit Hooks:** Ensure that `pre-commit` hooks are installed and active before making any commits. This can be done by running `pre-commit install` in your local repository.
|
||||
* **Note for Gemini:** Git commits trigger pre-commit hooks, which can take several seconds (or minutes) to complete. Checking the command status for git commit is only appropriate every 120s.
|
||||
|
||||
## Repository Comparison
|
||||
|
||||
|
||||
@@ -26,6 +26,19 @@ 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).
|
||||
- `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.
|
||||
- `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
|
||||
|
||||
|
||||
@@ -1,9 +1,54 @@
|
||||
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,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock screeps-api
|
||||
vi.mock("screeps-api", () => {
|
||||
const mockApi = {
|
||||
auth: vi.fn().mockResolvedValue(),
|
||||
code: {
|
||||
get: vi.fn().mockResolvedValue({ ok: 1, modules: { main: "old_code" } }),
|
||||
set: vi.fn().mockResolvedValue({ ok: 1 }),
|
||||
},
|
||||
};
|
||||
// Use a regular function so it can be called with `new`
|
||||
return {
|
||||
ScreepsAPI: vi.fn(function () {
|
||||
return mockApi;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import { monitorConsole } from "../monitor.js";
|
||||
|
||||
import {
|
||||
validateAuthentication,
|
||||
replacePlaceholders,
|
||||
readReplaceAndWriteFiles,
|
||||
readFilesIntoDict,
|
||||
applyOnAction,
|
||||
postCode,
|
||||
} from "../index.js";
|
||||
import { ScreepsAPI } from "screeps-api";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
@@ -197,3 +242,107 @@ describe("glob functionality", () => {
|
||||
expect(normalizedFiles.sort()).toEqual(expectedFiles);
|
||||
});
|
||||
});
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// applyOnAction
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("applyOnAction", () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it("'ignore' + true → no core call, returns false", () => {
|
||||
expect(applyOnAction("ignore", true, "msg")).toBe(false);
|
||||
expect(core.warning).not.toHaveBeenCalled();
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("'warn' + true → core.warning() called with message, returns false", () => {
|
||||
expect(applyOnAction("warn", true, "boom")).toBe(false);
|
||||
expect(core.warning).toHaveBeenCalledWith("boom");
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("'fail' + true → core.setFailed() called with message, returns true", () => {
|
||||
expect(applyOnAction("fail", true, "boom")).toBe(true);
|
||||
expect(core.setFailed).toHaveBeenCalledWith("boom");
|
||||
expect(core.warning).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("'fail' + false → no core call, returns false", () => {
|
||||
expect(applyOnAction("fail", false, "boom")).toBe(false);
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("'warn' + false → no core call, returns false", () => {
|
||||
expect(applyOnAction("warn", false, "msg")).toBe(false);
|
||||
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";
|
||||
if (name === "token") return "test-token";
|
||||
if (name === "branch") return "default";
|
||||
if (name === "on_traceback") return "fail";
|
||||
return "";
|
||||
});
|
||||
core.getBooleanInput.mockImplementation((name) => {
|
||||
if (name === "rollback_on_failure") return false;
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call monitorConsole when monitor=0 (default)", async () => {
|
||||
// We just run postCode with monitor=0 and verify monitorConsole is not called.
|
||||
await postCode();
|
||||
expect(monitorConsole).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rolls back to previous code when monitor detects a failure and rollback_on_failure is true", async () => {
|
||||
// Setup inputs for monitor and rollback
|
||||
core.getInput.mockImplementation((name) => {
|
||||
if (name === "monitor") return "10";
|
||||
if (name === "token") return "test-token";
|
||||
if (name === "branch") return "default";
|
||||
if (name === "on_traceback") return "fail";
|
||||
return "";
|
||||
});
|
||||
core.getBooleanInput.mockImplementation((name) => {
|
||||
if (name === "rollback_on_failure") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
// Simulate a failure in monitorConsole
|
||||
monitorConsole.mockResolvedValueOnce({
|
||||
sawTraceback: true, // Should trigger "fail" due to on_traceback=fail
|
||||
sawErrorLog: false,
|
||||
sawWarningLog: false,
|
||||
});
|
||||
|
||||
await postCode();
|
||||
|
||||
// Verify rollback was performed
|
||||
const mockApiInstance = new ScreepsAPI();
|
||||
|
||||
// `code.set` should be called twice:
|
||||
// 1st time: uploading the new files
|
||||
// 2nd time: rolling back to oldCode
|
||||
expect(mockApiInstance.code.set).toHaveBeenCalledTimes(2);
|
||||
expect(mockApiInstance.code.set).toHaveBeenNthCalledWith(2, "default", {
|
||||
main: "old_code",
|
||||
});
|
||||
|
||||
// Verify it called core.setFailed due to traceback
|
||||
expect(core.setFailed).toHaveBeenCalledWith(
|
||||
"Screeps console: traceback detected",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,633 @@
|
||||
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 },
|
||||
);
|
||||
});
|
||||
});
|
||||
+38
@@ -40,6 +40,44 @@ inputs:
|
||||
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.
|
||||
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'
|
||||
rollback_on_failure:
|
||||
description: 'Automatically rollback to previous code if the monitor detects failures. Requires monitor > 0. (default: false)'
|
||||
required: false
|
||||
default: 'false'
|
||||
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:
|
||||
using: node20
|
||||
main: dist/index.js
|
||||
Vendored
+15
-5
@@ -1,17 +1,27 @@
|
||||
import{createRequire as i}from"module";var A={1324:(i,A,p)=>{i.exports={parallel:p(3857),serial:p(1054),serialOrdered:p(3961)}},4818:i=>{i.exports=abort;function abort(i){Object.keys(i.jobs).forEach(clean.bind(i));i.jobs={}}function clean(i){if(typeof this.jobs[i]=="function"){this.jobs[i]()}}},8452:(i,A,p)=>{var g=p(9200);i.exports=async;function async(i){var A=false;g((function(){A=true}));return function async_callback(p,f){if(A){i(p,f)}else{g((function nextTick_callback(){i(p,f)}))}}}},9200:i=>{i.exports=defer;function defer(i){var A=typeof setImmediate=="function"?setImmediate:typeof process=="object"&&typeof process.nextTick=="function"?process.nextTick:null;if(A){A(i)}else{setTimeout(i,0)}}},4902:(i,A,p)=>{var g=p(8452),f=p(4818);i.exports=iterate;function iterate(i,A,p,g){var E=p["keyedList"]?p["keyedList"][p.index]:p.index;p.jobs[E]=runJob(A,E,i[E],(function(i,A){if(!(E in p.jobs)){return}delete p.jobs[E];if(i){f(p)}else{p.results[E]=A}g(i,p.results)}))}function runJob(i,A,p,f){var E;if(i.length==2){E=i(p,g(f))}else{E=i(p,A,g(f))}return E}},1721:i=>{i.exports=state;function state(i,A){var p=!Array.isArray(i),g={index:0,keyedList:p||A?Object.keys(i):null,jobs:{},results:p?{}:[],size:p?Object.keys(i).length:i.length};if(A){g.keyedList.sort(p?A:function(p,g){return A(i[p],i[g])})}return g}},3351:(i,A,p)=>{var g=p(4818),f=p(8452);i.exports=terminator;function terminator(i){if(!Object.keys(this.jobs).length){return}this.index=this.size;g(this);f(i)(null,this.results)}},3857:(i,A,p)=>{var g=p(4902),f=p(1721),E=p(3351);i.exports=parallel;function parallel(i,A,p){var C=f(i);while(C.index<(C["keyedList"]||i).length){g(i,A,C,(function(i,A){if(i){p(i,A);return}if(Object.keys(C.jobs).length===0){p(null,C.results);return}}));C.index++}return E.bind(C,p)}},1054:(i,A,p)=>{var g=p(3961);i.exports=serial;function serial(i,A,p){return g(i,A,null,p)}},3961:(i,A,p)=>{var g=p(4902),f=p(1721),E=p(3351);i.exports=serialOrdered;i.exports.ascending=ascending;i.exports.descending=descending;function serialOrdered(i,A,p,C){var Q=f(i,p);g(i,A,Q,(function iteratorHandler(p,f){if(p){C(p,f);return}Q.index++;if(Q.index<(Q["keyedList"]||i).length){g(i,A,Q,iteratorHandler);return}C(null,Q.results)}));return E.bind(Q,C)}function ascending(i,A){return i<A?-1:i>A?1:0}function descending(i,A){return-1*ascending(i,A)}},4922:(i,A,p)=>{i.exports=p(3732)},127:(i,A,p)=>{var g=p(9743);var f=p(5529);var E=p(3250);var C=p(4267);var Q=p(7777).T;var B=p(8611);var I=p(5692);var y=p(5665);var b=p(4852);var v=p(7016);var x=p(3106);var k=p(1428).version;var R=p(4491);var S=p(1914);var D=p(9862);var F=p(5896);var T=p(3566);var U=p(2203);var M=/https:?/;var L=F.protocols.map((function(i){return i+":"}));function dispatchBeforeRedirect(i){if(i.beforeRedirects.proxy){i.beforeRedirects.proxy(i)}if(i.beforeRedirects.config){i.beforeRedirects.config(i)}}function setProxy(i,A,p){var g=A;if(!g&&g!==false){var f=Q(p);if(f){g=v.parse(f);g.host=g.hostname}}if(g){if(g.auth){if(g.auth.username||g.auth.password){g.auth=(g.auth.username||"")+":"+(g.auth.password||"")}var E=Buffer.from(g.auth,"utf8").toString("base64");i.headers["Proxy-Authorization"]="Basic "+E}i.headers.host=i.hostname+(i.port?":"+i.port:"");i.hostname=g.host;i.host=g.host;i.port=g.port;i.path=p;if(g.protocol){i.protocol=g.protocol}}i.beforeRedirects.proxy=function beforeRedirect(i){setProxy(i,A,i.href)}}i.exports=function httpAdapter(i){return new Promise((function dispatchHttpRequest(A,p){var Q;function done(){if(i.cancelToken){i.cancelToken.unsubscribe(Q)}if(i.signal){i.signal.removeEventListener("abort",Q)}}var F=function resolve(i){done();A(i)};var _=false;var G=function reject(i){done();_=true;p(i)};var H=i.data;var Y=i.responseType;var P=i.responseEncoding;var J=i.method.toUpperCase();var V=E(i.baseURL,i.url);var j=v.parse(V);var z=j.protocol||L[0];if(z==="data:"){var Z;if(J!=="GET"){return f(F,G,{status:405,statusText:"method not allowed",headers:{},config:i})}try{Z=T(i.url,Y==="blob",{Blob:i.env&&i.env.Blob})}catch(A){throw S.from(A,S.ERR_BAD_REQUEST,i)}if(Y==="text"){Z=Z.toString(P);if(!P||P==="utf8"){H=g.stripBOM(Z)}}else if(Y==="stream"){Z=U.Readable.from(Z)}return f(F,G,{data:Z,status:200,statusText:"OK",headers:{},config:i})}if(L.indexOf(z)===-1){return G(new S("Unsupported protocol "+z,S.ERR_BAD_REQUEST,i))}var K=i.headers;var X={};Object.keys(K).forEach((function storeLowerName(i){X[i.toLowerCase()]=i}));if("user-agent"in X){if(!K[X["user-agent"]]){delete K[X["user-agent"]]}}else{K["User-Agent"]="axios/"+k}if(g.isFormData(H)&&g.isFunction(H.getHeaders)){Object.assign(K,H.getHeaders())}else if(H&&!g.isStream(H)){if(Buffer.isBuffer(H)){}else if(g.isArrayBuffer(H)){H=Buffer.from(new Uint8Array(H))}else if(g.isString(H)){H=Buffer.from(H,"utf-8")}else{return G(new S("Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream",S.ERR_BAD_REQUEST,i))}if(i.maxBodyLength>-1&&H.length>i.maxBodyLength){return G(new S("Request body larger than maxBodyLength limit",S.ERR_Line truncated
|
||||
import{createRequire as A}from"module";var i={7884:(A,i,g)=>{var E;E={value:true};i.v=void 0;const p=g(6856);function create(){return p.DefaultArtifactClient.create()}i.v=create},6856:function(A,i,g){var E=this&&this.__createBinding||(Object.create?function(A,i,g,E){if(E===undefined)E=g;var p=Object.getOwnPropertyDescriptor(i,g);if(!p||("get"in p?!i.__esModule:p.writable||p.configurable)){p={enumerable:true,get:function(){return i[g]}}}Object.defineProperty(A,E,p)}:function(A,i,g,E){if(E===undefined)E=g;A[E]=i[g]});var p=this&&this.__setModuleDefault||(Object.create?function(A,i){Object.defineProperty(A,"default",{enumerable:true,value:i})}:function(A,i){A["default"]=i});var C=this&&this.__importStar||function(A){if(A&&A.__esModule)return A;var i={};if(A!=null)for(var g in A)if(g!=="default"&&Object.prototype.hasOwnProperty.call(A,g))E(i,A,g);p(i,A);return i};var f=this&&this.__awaiter||function(A,i,g,E){function adopt(A){return A instanceof g?A:new g((function(i){i(A)}))}return new(g||(g=Promise))((function(g,p){function fulfilled(A){try{step(E.next(A))}catch(A){p(A)}}function rejected(A){try{step(E["throw"](A))}catch(A){p(A)}}function step(A){A.done?g(A.value):adopt(A.value).then(fulfilled,rejected)}step((E=E.apply(A,i||[])).next())}))};Object.defineProperty(i,"__esModule",{value:true});i.DefaultArtifactClient=void 0;const Q=C(g(4086));const B=g(5973);const I=g(6036);const y=g(1631);const b=g(1774);const D=g(809);const R=g(1280);const k=g(9562);const S=g(6928);class DefaultArtifactClient{static create(){return new DefaultArtifactClient}uploadArtifact(A,i,g,E){return f(this,void 0,void 0,(function*(){Q.info(`Starting artifact upload\nFor more detailed logs during the artifact upload process, enable step-debugging: https://docs.github.com/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging`);(0,b.checkArtifactName)(A);const p=(0,B.getUploadSpecification)(A,g,i);const C={artifactName:A,artifactItems:[],size:0,failedItems:[]};const f=new I.UploadHttpClient;if(p.length===0){Q.warning(`No files found that can be uploaded`)}else{const i=yield f.createArtifactInFileContainer(A,E);if(!i.fileContainerResourceUrl){Q.debug(i.toString());throw new Error("No URL provided by the Artifact Service to upload an artifact to")}Q.debug(`Upload Resource URL: ${i.fileContainerResourceUrl}`);Q.info(`Container for artifact "${A}" successfully created. Starting upload of file(s)`);const g=yield f.uploadArtifactToFileContainer(i.fileContainerResourceUrl,p,E);Q.info(`File upload process has finished. Finalizing the artifact upload`);yield f.patchArtifactSize(g.totalSize,A);if(g.failedItems.length>0){Q.info(`Upload finished. There were ${g.failedItems.length} items that failed to upload`)}else{Q.info(`Artifact has been finalized. All files have been successfully uploaded!`)}Q.info(`\nThe raw size of all the files that were specified for upload is ${g.totalSize} bytes\nThe size of all the files that were uploaded is ${g.uploadSize} bytes. This takes into account any gzip compression used to reduce the upload size, time and storage\n\nNote: The size of downloaded zips can differ significantly from the reported size. For more information see: https://github.com/actions/upload-artifact#zipped-artifact-downloads \r\n`);C.artifactItems=p.map((A=>A.absoluteFilePath));C.size=g.uploadSize;C.failedItems=g.failedItems}return C}))}downloadArtifact(A,i,g){return f(this,void 0,void 0,(function*(){const E=new D.DownloadHttpClient;const p=yield E.listArtifacts();if(p.count===0){throw new Error(`Unable to find any artifacts for the associated workflow`)}const C=p.value.find((i=>i.name===A));if(!C){throw new Error(`Unable to find an artifact with the name: ${A}`)}const f=yield E.getContainerItems(C.name,C.fileContainerResourceUrl);if(!i){i=(0,k.getWorkSpaceDirectory)()}i=(0,S.normalize)(i);i=(0,S.resolve)(i);const B=(0,R.getDownloadSpecification)(A,f.value,i,(g===null||g===void 0?void 0:g.createArtifactFolder)||false);if(B.filesToDownload.length===0){Q.info(`No downloadable files were found for the artifact: ${C.name}`)}else{yield(0,y.createDirectoriesForArtifact)(B.directoryStructure);Q.info("Directory structure has been set up for the artifact");yield(0,y.createEmptyFilesForArtifact)(B.emptyFilesToCreate);yield E.downloadSingleArtifact(B.filesToDownload)}return{artifactName:A,downloadPath:B.rootDownloadLocation}}))}downloadAllArtifacts(A){return f(this,void 0,void 0,(function*(){const i=new D.DownloadHttpClient;const g=[];const E=yield i.listArtifacts();if(E.count===0){Q.info("Unable to find any artifacts for the associated workflow");return g}if(!A){A=(0,k.getWorkSpaceDirectory)()}A=(0,S.normalize)(A);A=(0,S.resolve)(A);let p=0;while(p<E.count){const C=E.value[p];p+=1;Q.info(`starting download of artifact ${C.name} : ${p}/${E.count}`);const f=yield i.getContainerItems(C.name,C.fileContainerResourceUrl);const B=(0,R.getDownloadSpecification)(C.name,f.value,A,true);if(B.filesToDownload.length===0){Q.inLine truncated
|
||||
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */;const escape=A=>A.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22");const normalizeLinefeeds=A=>A.replace(/\r?\n|\r/g,"\r\n");const E=[];const p=new Uint8Array([13,10]);b=0;let C=false;for(const[i,f]of A){if(typeof f==="string"){const A=P.encode(g+`; name="${escape(normalizeLinefeeds(i))}"`+`\r\n\r\n${normalizeLinefeeds(f)}\r\n`);E.push(A);b+=A.byteLength}else{const A=P.encode(`${g}; name="${escape(normalizeLinefeeds(i))}"`+(f.name?`; filename="${escape(f.name)}"`:"")+"\r\n"+`Content-Type: ${f.type||"application/octet-stream"}\r\n\r\n`);E.push(A,f,p);if(typeof f.size==="number"){b+=A.byteLength+f.size+p.byteLength}else{C=true}}}const f=P.encode(`--${i}--`);E.push(f);b+=f.byteLength;if(C){b=null}y=A;I=async function*(){for(const A of E){if(A.stream){yield*A.stream()}else{yield A}}};D="multipart/form-data; boundary="+i}else if(f(A)){y=A;b=A.size;if(A.type){D=A.type}}else if(typeof A[Symbol.asyncIterator]==="function"){if(i){throw new TypeError("keepalive")}if(p.isDisturbed(A)||A.locked){throw new TypeError("Response body object should not be disturbed or locked")}E=A instanceof _?A:C(A)}if(typeof y==="string"||p.isBuffer(y)){b=Buffer.byteLength(y)}if(I!=null){let i;E=new _({async start(){i=I(A)[Symbol.asyncIterator]()},async pull(A){const{value:g,done:p}=await i.next();if(p){queueMicrotask((()=>{A.close()}))}else{if(!L(E)){A.enqueue(new Uint8Array(g))}}return A.desiredSize>0},async cancel(A){await i.return()},type:undefined})}const R={stream:E,source:y,length:b};return[R,D]}function safelyExtractBody(A,i=false){if(!_){_=g(3774).ReadableStream}if(A instanceof _){U(!p.isDisturbed(A),"The body has already been consumed.");U(!A.locked,"The stream is locked.")}return extractBody(A,i)}function cloneBody(A){const[i,g]=A.stream.tee();const E=S(g,{transfer:[g]});const[,p]=E.tee();A.stream=i;return{stream:p,length:A.length,source:A.source}}async function*consumeBody(A){if(A){if(M(A)){yield A}else{const i=A.stream;if(p.isDisturbed(i)){throw new TypeError("The body has already been consumed.")}if(i.locked){throw new TypeError("The stream is locked.")}i[x]=true;yield*i}}}function throwIfAborted(A){if(A.aborted){throw new k("The operation was aborted.","AbortError")}}function bodyMixinMethods(A){const i={blob(){return specConsumeBody(this,(A=>{let i=bodyMimeType(this);if(i==="failure"){i=""}else if(i){i=Y(i)}return new v([A],{type:i})}),A)},arrayBuffer(){return specConsumeBody(this,(A=>new Uint8Array(A).buffer),A)},text(){return specConsumeBody(this,utf8DecodeBytes,A)},json(){return specConsumeBody(this,parseJSONFromBytes,A)},async formData(){R.brandCheck(this,A);throwIfAborted(this[D]);const i=this.headers.get("Content-Type");if(/multipart\/form-data/.test(i)){const A={};for(const[i,g]of this.headers)A[i.toLowerCase()]=g;const i=new b;let g;try{g=new E({headers:A,preservePath:true})}catch(A){throw new k(`${A}`,"AbortError")}g.on("field",((A,g)=>{i.append(A,g)}));g.on("file",((A,g,E,p,C)=>{const f=[];if(p==="base64"||p.toLowerCase()==="base64"){let p="";g.on("data",(A=>{p+=A.toString().replace(/[\r\n]/gm,"");const i=p.length-p.length%4;f.push(Buffer.from(p.slice(0,i),"base64"));p=p.slice(i)}));g.on("end",(()=>{f.push(Buffer.from(p,"base64"));i.append(A,new V(f,E,{type:C}))}))}else{g.on("data",(A=>{f.push(A)}));g.on("end",(()=>{i.append(A,new V(f,E,{type:C}))}))}}));const p=new Promise(((A,i)=>{g.on("finish",A);g.on("error",(A=>i(new TypeError(A))))}));if(this.body!==null)for await(const A of consumeBody(this[D].body))g.write(A);g.end();await p;return i}else if(/application\/x-www-form-urlencoded/.test(i)){let A;try{let i="";const g=new TextDecoder("utf-8",{ignoreBOM:true});for await(const A of consumeBody(this[D].body)){if(!M(A)){throw new TypeError("Expected Uint8Array chunk")}i+=g.decode(A,{stream:true})}i+=g.decode();A=new URLSearchParams(i)}catch(A){throw Object.assign(new TypeError,{cause:A})}const i=new b;for(const[g,E]of A){i.append(g,E)}return i}else{await Promise.resolve();throwIfAborted(this[D]);throw R.errors.exception({header:`${A.name}.formData`,message:"Could not parse content as FormData."})}}};return i}function mixinBody(A){Object.assign(A.prototype,bodyMixinMethods(A))}async function specConsumeBody(A,i,g){R.brandCheck(A,g);throwIfAborted(A[D]);if(bodyUnusable(A[D].body)){throw new TypeError("Body is unusable")}const E=I();const errorSteps=A=>E.reject(A);const successSteps=A=>{try{E.resolve(i(A))}catch(A){errorSteps(A)}};if(A[D].body==null){successSteps(new Uint8Array);return E.promise}await y(A[D].body,successSteps,errorSteps);return E.promise}function bodyUnusable(A){return A!=null&&(A.stream.locked||p.isDisturbed(A.stream))}function utf8DecodeBytes(A){if(A.length===0){return""}if(A[0]===239&&A[1]===187&&A[2]===191){A=A.subarray(3)}const i=j.decode(A);return i}function parseJSONFromBytes(A){return JSON.parse(utf8DecodeBytes(A))}function bodyMimeType(A){const{headersList:i}=A[D];const g=i.get("content-Line truncated
|
||||
/*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */C[p-4]=this.maskKey[0];C[p-3]=this.maskKey[1];C[p-2]=this.maskKey[2];C[p-1]=this.maskKey[3];C[1]=g;if(g===126){C.writeUInt16BE(i,2)}else if(g===127){C[2]=C[3]=0;C.writeUIntBE(i,4,6)}C[1]|=128;for(let A=0;A<i;A++){C[p+A]=this.frameData[A]^this.maskKey[A%4]}return C}}A.exports={WebsocketFrameSend:WebsocketFrameSend}},5553:(A,i,g)=>{const{Writable:E}=g(2203);const p=g(1637);const{parserStates:C,opcodes:f,states:Q,emptyBuffer:B}=g(1859);const{kReadyState:I,kSentClose:y,kResponse:b,kReceivedClose:D}=g(5199);const{isValidStatusCode:R,failWebsocketConnection:k,websocketMessageReceived:S}=g(4604);const{WebsocketFrameSend:v}=g(231);const F={};F.ping=p.channel("undici:websocket:ping");F.pong=p.channel("undici:websocket:pong");class ByteParser extends E{#n=[];#o=0;#a=C.INFO;#c={};#l=[];constructor(A){super();this.ws=A}_write(A,i,g){this.#n.push(A);this.#o+=A.length;this.run(g)}run(A){while(true){if(this.#a===C.INFO){if(this.#o<2){return A()}const i=this.consume(2);this.#c.fin=(i[0]&128)!==0;this.#c.opcode=i[0]&15;this.#c.originalOpcode??=this.#c.opcode;this.#c.fragmented=!this.#c.fin&&this.#c.opcode!==f.CONTINUATION;if(this.#c.fragmented&&this.#c.opcode!==f.BINARY&&this.#c.opcode!==f.TEXT){k(this.ws,"Invalid frame type was fragmented.");return}const g=i[1]&127;if(g<=125){this.#c.payloadLength=g;this.#a=C.READ_DATA}else if(g===126){this.#a=C.PAYLOADLENGTH_16}else if(g===127){this.#a=C.PAYLOADLENGTH_64}if(this.#c.fragmented&&g>125){k(this.ws,"Fragmented frame exceeded 125 bytes.");return}else if((this.#c.opcode===f.PING||this.#c.opcode===f.PONG||this.#c.opcode===f.CLOSE)&&g>125){k(this.ws,"Payload length for control frame exceeded 125 bytes.");return}else if(this.#c.opcode===f.CLOSE){if(g===1){k(this.ws,"Received close frame with a 1-byte body.");return}const A=this.consume(g);this.#c.closeInfo=this.parseCloseBody(false,A);if(!this.ws[y]){const A=Buffer.allocUnsafe(2);A.writeUInt16BE(this.#c.closeInfo.code,0);const i=new v(A);this.ws[b].socket.write(i.createFrame(f.CLOSE),(A=>{if(!A){this.ws[y]=true}}))}this.ws[I]=Q.CLOSING;this.ws[D]=true;this.end();return}else if(this.#c.opcode===f.PING){const i=this.consume(g);if(!this.ws[D]){const A=new v(i);this.ws[b].socket.write(A.createFrame(f.PONG));if(F.ping.hasSubscribers){F.ping.publish({payload:i})}}this.#a=C.INFO;if(this.#o>0){continue}else{A();return}}else if(this.#c.opcode===f.PONG){const i=this.consume(g);if(F.pong.hasSubscribers){F.pong.publish({payload:i})}if(this.#o>0){continue}else{A();return}}}else if(this.#a===C.PAYLOADLENGTH_16){if(this.#o<2){return A()}const i=this.consume(2);this.#c.payloadLength=i.readUInt16BE(0);this.#a=C.READ_DATA}else if(this.#a===C.PAYLOADLENGTH_64){if(this.#o<8){return A()}const i=this.consume(8);const g=i.readUInt32BE(0);if(g>2**31-1){k(this.ws,"Received payload length > 2^31 bytes.");return}const E=i.readUInt32BE(4);this.#c.payloadLength=(g<<8)+E;this.#a=C.READ_DATA}else if(this.#a===C.READ_DATA){if(this.#o<this.#c.payloadLength){return A()}else if(this.#o>=this.#c.payloadLength){const A=this.consume(this.#c.payloadLength);this.#l.push(A);if(!this.#c.fragmented||this.#c.fin&&this.#c.opcode===f.CONTINUATION){const A=Buffer.concat(this.#l);S(this.ws,this.#c.originalOpcode,A);this.#c={};this.#l.length=0}this.#a=C.INFO}}if(this.#o>0){continue}else{A();break}}}consume(A){if(A>this.#o){return null}else if(A===0){return B}if(this.#n[0].length===A){this.#o-=this.#n[0].length;return this.#n.shift()}const i=Buffer.allocUnsafe(A);let g=0;while(g!==A){const E=this.#n[0];const{length:p}=E;if(p+g===A){i.set(this.#n.shift(),g);break}else if(p+g>A){i.set(E.subarray(0,A-g),g);this.#n[0]=E.subarray(A-g);break}else{i.set(this.#n.shift(),g);g+=E.length}}this.#o-=A;return i}parseCloseBody(A,i){let g;if(i.length>=2){g=i.readUInt16BE(0)}if(A){if(!R(g)){return null}return{code:g}}let E=i.subarray(2);if(E[0]===239&&E[1]===187&&E[2]===191){E=E.subarray(3)}if(g!==undefined&&!R(g)){return null}try{E=new TextDecoder("utf-8",{fatal:true}).decode(E)}catch{return null}return{code:g,reason:E}}get closingInfo(){return this.#c.closeInfo}}A.exports={ByteParser:ByteParser}},5199:A=>{A.exports={kWebSocketURL:Symbol("url"),kReadyState:Symbol("ready state"),kController:Symbol("controller"),kResponse:Symbol("response"),kBinaryType:Symbol("binary type"),kSentClose:Symbol("sent close"),kReceivedClose:Symbol("received close"),kByteParser:Symbol("byte parser")}},4604:(A,i,g)=>{const{kReadyState:E,kController:p,kResponse:C,kBinaryType:f,kWebSocketURL:Q}=g(5199);const{states:B,opcodes:I}=g(1859);const{MessageEvent:y,ErrorEvent:b}=g(3273);function isEstablished(A){return A[E]===B.OPEN}function isClosing(A){return A[E]===B.CLOSING}function isClosed(A){return A[E]===B.CLOSED}function fireEvent(A,i,g=Event,E){const p=new g(A,E);i.dispatchEvent(p)}function websocketMessageReceived(A,i,g){if(A[E]!==B.OPEN){return}let p;if(i===I.TEXT){try{p=new TextDecoder("utf-8",{fatal:true}).decode(g)}catch{failWebsocketConnection(A,"ReceivLine truncated
|
||||
/*!
|
||||
* mime-db
|
||||
* Copyright(c) 2014 Jonathan Ong
|
||||
* Copyright(c) 2015-2022 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
i.exports=p(1813)},4096:(i,A,p)=>{
|
||||
A.exports=g(1813)},4096:(A,i,g)=>{
|
||||
/*!
|
||||
* mime-types
|
||||
* Copyright(c) 2014 Jonathan Ong
|
||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
var g=p(9829);var f=p(6928).extname;var E=/^\s*([^;\s]*)(?:;|\s|$)/;var C=/^text\//i;A.charset=charset;A.charsets={lookup:charset};A.contentType=contentType;A.extension=extension;A.extensions=Object.create(null);A.lookup=lookup;A.types=Object.create(null);populateMaps(A.extensions,A.types);function charset(i){if(!i||typeof i!=="string"){return false}var A=E.exec(i);var p=A&&g[A[1].toLowerCase()];if(p&&p.charset){return p.charset}if(A&&C.test(A[1])){return"UTF-8"}return false}function contentType(i){if(!i||typeof i!=="string"){return false}var p=i.indexOf("/")===-1?A.lookup(i):i;if(!p){return false}if(p.indexOf("charset")===-1){var g=A.charset(p);if(g)p+="; charset="+g.toLowerCase()}return p}function extension(i){if(!i||typeof i!=="string"){return false}var p=E.exec(i);var g=p&&A.extensions[p[1].toLowerCase()];if(!g||!g.length){return false}return g[0]}function lookup(i){if(!i||typeof i!=="string"){return false}var p=f("x."+i).toLowerCase().substr(1);if(!p){return false}return A.types[p]||false}function populateMaps(i,A){var p=["nginx","apache",undefined,"iana"];Object.keys(g).forEach((function forEachMimeType(f){var E=g[f];var C=E.extensions;if(!C||!C.length){return}i[f]=C;for(var Q=0;Q<C.length;Q++){var B=C[Q];if(A[B]){var I=p.indexOf(g[A[B]].source);var y=p.indexOf(E.source);if(A[B]!=="application/octet-stream"&&(I>y||I===y&&A[B].substr(0,12)==="application/")){continue}}A[B]=f}}))}},744:i=>{var A=1e3;var p=A*60;var g=p*60;var f=g*24;var E=f*7;var C=f*365.25;i.exports=function(i,A){A=A||{};var p=typeof i;if(p==="string"&&i.length>0){return parse(i)}else if(p==="number"&&isFinite(i)){return A.long?fmtLong(i):fmtShort(i)}throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(i))};function parse(i){i=String(i);if(i.length>100){return}var Q=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(i);if(!Q){return}var B=parseFloat(Q[1]);var I=(Q[2]||"ms").toLowerCase();switch(I){case"years":case"year":case"yrs":case"yr":case"y":return B*C;case"weeks":case"week":case"w":return B*E;case"days":case"day":case"d":return B*f;case"hours":case"hour":case"hrs":case"hr":case"h":return B*g;case"minutes":case"minute":case"mins":case"min":case"m":return B*p;case"seconds":case"second":case"secs":case"sec":case"s":return B*A;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return B;default:return undefined}}function fmtShort(i){var E=Math.abs(i);if(E>=f){return Math.round(i/f)+"d"}if(E>=g){return Math.round(i/g)+"h"}if(E>=p){return Math.round(i/p)+"m"}if(E>=A){return Math.round(i/A)+"s"}return i+"ms"}function fmtLong(i){var E=Math.abs(i);if(E>=f){return plural(i,E,f,"day")}if(E>=g){return plural(i,E,g,"hour")}if(E>=p){return plural(i,E,p,"minute")}if(E>=A){return plural(i,E,A,"second")}return i+" ms"}function plural(i,A,p,g){var f=A>=p*1.5;return Math.round(i/p)+" "+g+(f?"s":"")}},7777:(i,A,p)=>{var g=p(7016).parse;var f={ftp:21,gopher:70,http:80,https:443,ws:80,wss:443};var E=String.prototype.endsWith||function(i){return i.length<=this.length&&this.indexOf(i,this.length-i.length)!==-1};function getProxyForUrl(i){var A=typeof i==="string"?g(i):i||{};var p=A.protocol;var E=A.host;var C=A.port;if(typeof E!=="string"||!E||typeof p!=="string"){return""}p=p.split(":",1)[0];E=E.replace(/:\d*$/,"");C=parseInt(C)||f[p]||0;if(!shouldProxy(E,C)){return""}var Q=getEnv("npm_config_"+p+"_proxy")||getEnv(p+"_proxy")||getEnv("npm_config_proxy")||getEnv("all_proxy");if(Q&&Q.indexOf("://")===-1){Q=p+"://"+Q}return Q}function shouldProxy(i,A){var p=(getEnv("npm_config_no_proxy")||getEnv("no_proxy")).toLowerCase();if(!p){return true}if(p==="*"){return false}return p.split(/[,\s]/).every((function(p){if(!p){return true}var g=p.match(/^(.+):(\d+)$/);var f=g?g[1]:p;var C=g?parseInt(g[2]):0;if(C&&C!==A){return true}if(!/^[.*]/.test(f)){return i!==f}if(f.charAt(0)==="*"){f=f.slice(1)}return!E.call(i,f)}))}function getEnv(i){return process.env[i.toLowerCase()]||process.env[i.toUpperCase()]||""}A.T=getProxyForUrl},9546:(i,A,p)=>{var g;g={value:true};const f=p(1354);const E=p(7016);const C=p(4434);const Q=p(2830);const B=p(3106);const I=p(4922);const y=p(9023);const b=p(9896);const v=p(9557);const x=p(6928);function _interopDefaultLegacy(i){return i&&typeof i==="object"&&"default"in i?i:{default:i}}const k=_interopDefaultLegacy(f);const R=_interopDefaultLegacy(E);const S=_interopDefaultLegacy(Q);const D=_interopDefaultLegacy(B);const F=_interopDefaultLegacy(I);const T=_interopDefaultLegacy(y);const U=_interopDefaultLegacy(b);const M=_interopDefaultLegacy(v);const L=_interopDefaultLegacy(x);const _=S["default"]("screepsapi:socket");const G={reconnect:true,resubscribe:true,keepAlive:true,maxRetries:10,maxRetryDelay:60*1e3};class Socket extends C.EventEmitter{constructor(i){super();this.api=i;this.opts=Object.assign({},G);this.on("error",(()=>{}));this.reset();this.on("auth",(i=>{if(i.data.status==="ok"){while(this.__queue.lLine truncated
|
||||
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */;const escape=i=>i.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22");const normalizeLinefeeds=i=>i.replace(/\r?\n|\r/g,"\r\n");const g=[];const f=new Uint8Array([13,10]);y=0;let E=false;for(const[A,C]of i){if(typeof C==="string"){const i=_.encode(p+`; name="${escape(normalizeLinefeeds(A))}"`+`\r\n\r\n${normalizeLinefeeds(C)}\r\n`);g.push(i);y+=i.byteLength}else{const i=_.encode(`${p}; name="${escape(normalizeLinefeeds(A))}"`+(C.name?`; filename="${escape(C.name)}"`:"")+"\r\n"+`Content-Type: ${C.type||"application/octet-stream"}\r\n\r\n`);g.push(i,C,f);if(typeof C.size==="number"){y+=i.byteLength+C.size+f.byteLength}else{E=true}}}const C=_.encode(`--${A}--\r\n`);g.push(C);y+=C.byteLength;if(E){y=null}I=i;B=async function*(){for(const i of g){if(i.stream){yield*i.stream()}else{yield i}}};b=`multipart/form-data; boundary=${A}`}else if(E(i)){I=i;y=i.size;if(i.type){b=i.type}}else if(typeof i[Symbol.asyncIterator]==="function"){if(A){throw new TypeError("keepalive")}if(g.isDisturbed(i)||i.locked){throw new TypeError("Response body object should not be disturbed or locked")}p=i instanceof ReadableStream?i:f(i)}if(typeof I==="string"||g.isBuffer(I)){y=Buffer.byteLength(I)}if(B!=null){let A;p=new ReadableStream({async start(){A=B(i)[Symbol.asyncIterator]()},async pull(i){const{value:g,done:f}=await A.next();if(f){queueMicrotask((()=>{i.close();i.byobRequest?.respond(0)}))}else{if(!D(p)){const A=new Uint8Array(g);if(A.byteLength){i.enqueue(A)}}}return i.desiredSize>0},async cancel(i){await A.return()},type:"bytes"})}const v={stream:p,source:I,length:y};return[v,b]}function safelyExtractBody(i,A=false){if(i instanceof ReadableStream){S(!g.isDisturbed(i),"The body has already been consumed.");S(!i.locked,"The stream is locked.")}return extractBody(i,A)}function cloneBody(i,A){const[p,g]=A.stream.tee();A.stream=p;return{stream:g,length:A.length,source:A.source}}function throwIfAborted(i){if(i.aborted){throw new DOMException("The operation was aborted.","AbortError")}}function bodyMixinMethods(i){const A={blob(){return consumeBody(this,(i=>{let A=bodyMimeType(this);if(A===null){A=""}else if(A){A=U(A)}return new R([i],{type:A})}),i)},arrayBuffer(){return consumeBody(this,(i=>new Uint8Array(i).buffer),i)},text(){return consumeBody(this,b,i)},json(){return consumeBody(this,parseJSONFromBytes,i)},formData(){return consumeBody(this,(i=>{const A=bodyMimeType(this);if(A!==null){switch(A.essence){case"multipart/form-data":{const p=M(i,A);if(p==="failure"){throw new TypeError("Failed to parse body as FormData.")}const g=new v;g[x]=p;return g}case"application/x-www-form-urlencoded":{const A=new URLSearchParams(i.toString());const p=new v;for(const[i,g]of A){p.append(i,g)}return p}}}throw new TypeError('Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".')}),i)},bytes(){return consumeBody(this,(i=>new Uint8Array(i)),i)}};return A}function mixinBody(i){Object.assign(i.prototype,bodyMixinMethods(i))}async function consumeBody(i,A,p){k.brandCheck(i,p);if(bodyUnusable(i)){throw new TypeError("Body is unusable: Body has already been read")}throwIfAborted(i[x]);const g=B();const errorSteps=i=>g.reject(i);const successSteps=i=>{try{g.resolve(A(i))}catch(i){errorSteps(i)}};if(i[x].body==null){successSteps(Buffer.allocUnsafe(0));return g.promise}await I(i[x].body,successSteps,errorSteps);return g.promise}function bodyUnusable(i){const A=i[x].body;return A!=null&&(A.stream.locked||g.isDisturbed(A.stream))}function parseJSONFromBytes(i){return JSON.parse(b(i))}function bodyMimeType(i){const A=i[x].headersList;const p=y(A);if(p==="failure"){return null}return p}i.exports={extractBody:extractBody,safelyExtractBody:safelyExtractBody,cloneBody:cloneBody,mixinBody:mixinBody,streamRegistry:H,hasFinalizationRegistry:G,bodyUnusable:bodyUnusable}},4495:i=>{const A=["GET","HEAD","POST"];const p=new Set(A);const g=[101,204,205,304];const f=[301,302,303,307,308];const E=new Set(f);const C=["1","7","9","11","13","15","17","19","20","21","22","23","25","37","42","43","53","69","77","79","87","95","101","102","103","104","109","110","111","113","115","117","119","123","135","137","139","143","161","179","389","427","465","512","513","514","515","526","530","531","532","540","548","554","556","563","587","601","636","989","990","993","995","1719","1720","1723","2049","3659","4045","4190","5060","5061","6000","6566","6665","6666","6667","6668","6669","6679","6697","10080"];const Q=new Set(C);const B=["","no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"];const I=new Set(B);const y=["follow","manual","error"];const b=["GET","HEAD","OPTIONS","TRACE"];const v=new Set(b);const x=["navigate","same-origin","no-cors","cors"];const k=["omit","same-origin","include"];const R=["default","no-store","reload","no-cache","force-cLine truncated
|
||||
/*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */Q[C-4]=p[0];Q[C-3]=p[1];Q[C-2]=p[2];Q[C-1]=p[3];Q[1]=E;if(E===126){Q.writeUInt16BE(f,2)}else if(E===127){Q[2]=Q[3]=0;Q.writeUIntBE(f,4,6)}Q[1]|=128;for(let i=0;i<f;++i){Q[C+i]=A[i]^p[i&3]}return Q}}i.exports={WebsocketFrameSend:WebsocketFrameSend}},9469:(i,A,p)=>{const{createInflateRaw:g,Z_DEFAULT_WINDOWBITS:f}=p(8522);const{isValidClientWindowBits:E}=p(8625);const C=Buffer.from([0,0,255,255]);const Q=Symbol("kBuffer");const B=Symbol("kLength");class PerMessageDeflate{#Z;#h={};constructor(i){this.#h.serverNoContextTakeover=i.has("server_no_context_takeover");this.#h.serverMaxWindowBits=i.get("server_max_window_bits")}decompress(i,A,p){if(!this.#Z){let i=f;if(this.#h.serverMaxWindowBits){if(!E(this.#h.serverMaxWindowBits)){p(new Error("Invalid server_max_window_bits"));return}i=Number.parseInt(this.#h.serverMaxWindowBits)}this.#Z=g({windowBits:i});this.#Z[Q]=[];this.#Z[B]=0;this.#Z.on("data",(i=>{this.#Z[Q].push(i);this.#Z[B]+=i.length}));this.#Z.on("error",(i=>{this.#Z=null;p(i)}))}this.#Z.write(i);if(A){this.#Z.write(C)}this.#Z.flush((()=>{const i=Buffer.concat(this.#Z[Q],this.#Z[B]);this.#Z[Q].length=0;this.#Z[B]=0;p(null,i)}))}}i.exports={PerMessageDeflate:PerMessageDeflate}},1652:(i,A,p)=>{const{Writable:g}=p(7075);const f=p(4589);const{parserStates:E,opcodes:C,states:Q,emptyBuffer:B,sentCloseFrameState:I}=p(736);const{kReadyState:y,kSentClose:b,kResponse:v,kReceivedClose:x}=p(1216);const{channels:k}=p(2414);const{isValidStatusCode:R,isValidOpcode:S,failWebsocketConnection:D,websocketMessageReceived:F,utf8Decode:T,isControlFrame:U,isTextBinaryFrame:M,isContinuationFrame:L}=p(8625);const{WebsocketFrameSend:_}=p(3264);const{closeWebSocketConnection:G}=p(6897);const{PerMessageDeflate:H}=p(9469);class ByteParser extends g{#K=[];#X=0;#$=false;#Q=E.INFO;#ee={};#te=[];#se;constructor(i,A){super();this.ws=i;this.#se=A==null?new Map:A;if(this.#se.has("permessage-deflate")){this.#se.set("permessage-deflate",new H(A))}}_write(i,A,p){this.#K.push(i);this.#X+=i.length;this.#$=true;this.run(p)}run(i){while(this.#$){if(this.#Q===E.INFO){if(this.#X<2){return i()}const A=this.consume(2);const p=(A[0]&128)!==0;const g=A[0]&15;const f=(A[1]&128)===128;const Q=!p&&g!==C.CONTINUATION;const B=A[1]&127;const I=A[0]&64;const y=A[0]&32;const b=A[0]&16;if(!S(g)){D(this.ws,"Invalid opcode received");return i()}if(f){D(this.ws,"Frame cannot be masked");return i()}if(I!==0&&!this.#se.has("permessage-deflate")){D(this.ws,"Expected RSV1 to be clear.");return}if(y!==0||b!==0){D(this.ws,"RSV1, RSV2, RSV3 must be clear");return}if(Q&&!M(g)){D(this.ws,"Invalid frame type was fragmented.");return}if(M(g)&&this.#te.length>0){D(this.ws,"Expected continuation frame");return}if(this.#ee.fragmented&&Q){D(this.ws,"Fragmented frame exceeded 125 bytes.");return}if((B>125||Q)&&U(g)){D(this.ws,"Control frame either too large or fragmented");return}if(L(g)&&this.#te.length===0&&!this.#ee.compressed){D(this.ws,"Unexpected continuation frame");return}if(B<=125){this.#ee.payloadLength=B;this.#Q=E.READ_DATA}else if(B===126){this.#Q=E.PAYLOADLENGTH_16}else if(B===127){this.#Q=E.PAYLOADLENGTH_64}if(M(g)){this.#ee.binaryType=g;this.#ee.compressed=I!==0}this.#ee.opcode=g;this.#ee.masked=f;this.#ee.fin=p;this.#ee.fragmented=Q}else if(this.#Q===E.PAYLOADLENGTH_16){if(this.#X<2){return i()}const A=this.consume(2);this.#ee.payloadLength=A.readUInt16BE(0);this.#Q=E.READ_DATA}else if(this.#Q===E.PAYLOADLENGTH_64){if(this.#X<8){return i()}const A=this.consume(8);const p=A.readUInt32BE(0);if(p>2**31-1){D(this.ws,"Received payload length > 2^31 bytes.");return}const g=A.readUInt32BE(4);this.#ee.payloadLength=(p<<8)+g;this.#Q=E.READ_DATA}else if(this.#Q===E.READ_DATA){if(this.#X<this.#ee.payloadLength){return i()}const A=this.consume(this.#ee.payloadLength);if(U(this.#ee.opcode)){this.#$=this.parseControlFrame(A);this.#Q=E.INFO}else{if(!this.#ee.compressed){this.#te.push(A);if(!this.#ee.fragmented&&this.#ee.fin){const i=Buffer.concat(this.#te);F(this.ws,this.#ee.binaryType,i);this.#te.length=0}this.#Q=E.INFO}else{this.#se.get("permessage-deflate").decompress(A,this.#ee.fin,((A,p)=>{if(A){G(this.ws,1007,A.message,A.message.length);return}this.#te.push(p);if(!this.#ee.fin){this.#Q=E.INFO;this.#$=true;this.run(i);return}F(this.ws,this.#ee.binaryType,Buffer.concat(this.#te));this.#$=true;this.#Q=E.INFO;this.#te.length=0;this.run(i)}));this.#$=false;break}}}}}consume(i){if(i>this.#X){throw new Error("Called consume() before buffers satiated.")}else if(i===0){return B}if(this.#K[0].length===i){this.#X-=this.#K[0].length;return this.#K.shift()}const A=Buffer.allocUnsafe(i);let p=0;while(p!==i){const g=this.#K[0];const{length:f}=g;if(f+p===i){A.set(this.#K.shift(),p);break}else if(f+p>i){A.set(g.subarray(0,i-p),p);this.#K[0]=g.subarray(i-p);break}else{A.set(this.#K.shift(),p);p+=g.length}}this.#X-=i;return A}parseCloseBody(i){f(i.length!==1);let A;if(i.length>=2){A=i.readUInt16BE(0)}if(A!==undefined&&!R(A)){retuLine truncated
|
||||
var E=g(9829);var p=g(6928).extname;var C=/^\s*([^;\s]*)(?:;|\s|$)/;var f=/^text\//i;i.charset=charset;i.charsets={lookup:charset};i.contentType=contentType;i.extension=extension;i.extensions=Object.create(null);i.lookup=lookup;i.types=Object.create(null);populateMaps(i.extensions,i.types);function charset(A){if(!A||typeof A!=="string"){return false}var i=C.exec(A);var g=i&&E[i[1].toLowerCase()];if(g&&g.charset){return g.charset}if(i&&f.test(i[1])){return"UTF-8"}return false}function contentType(A){if(!A||typeof A!=="string"){return false}var g=A.indexOf("/")===-1?i.lookup(A):A;if(!g){return false}if(g.indexOf("charset")===-1){var E=i.charset(g);if(E)g+="; charset="+E.toLowerCase()}return g}function extension(A){if(!A||typeof A!=="string"){return false}var g=C.exec(A);var E=g&&i.extensions[g[1].toLowerCase()];if(!E||!E.length){return false}return E[0]}function lookup(A){if(!A||typeof A!=="string"){return false}var g=p("x."+A).toLowerCase().substr(1);if(!g){return false}return i.types[g]||false}function populateMaps(A,i){var g=["nginx","apache",undefined,"iana"];Object.keys(E).forEach((function forEachMimeType(p){var C=E[p];var f=C.extensions;if(!f||!f.length){return}A[p]=f;for(var Q=0;Q<f.length;Q++){var B=f[Q];if(i[B]){var I=g.indexOf(E[i[B]].source);var y=g.indexOf(C.source);if(i[B]!=="application/octet-stream"&&(I>y||I===y&&i[B].substr(0,12)==="application/")){continue}}i[B]=p}}))}},744:A=>{var i=1e3;var g=i*60;var E=g*60;var p=E*24;var C=p*7;var f=p*365.25;A.exports=function(A,i){i=i||{};var g=typeof A;if(g==="string"&&A.length>0){return parse(A)}else if(g==="number"&&isFinite(A)){return i.long?fmtLong(A):fmtShort(A)}throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(A))};function parse(A){A=String(A);if(A.length>100){return}var Q=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(A);if(!Q){return}var B=parseFloat(Q[1]);var I=(Q[2]||"ms").toLowerCase();switch(I){case"years":case"year":case"yrs":case"yr":case"y":return B*f;case"weeks":case"week":case"w":return B*C;case"days":case"day":case"d":return B*p;case"hours":case"hour":case"hrs":case"hr":case"h":return B*E;case"minutes":case"minute":case"mins":case"min":case"m":return B*g;case"seconds":case"second":case"secs":case"sec":case"s":return B*i;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return B;default:return undefined}}function fmtShort(A){var C=Math.abs(A);if(C>=p){return Math.round(A/p)+"d"}if(C>=E){return Math.round(A/E)+"h"}if(C>=g){return Math.round(A/g)+"m"}if(C>=i){return Math.round(A/i)+"s"}return A+"ms"}function fmtLong(A){var C=Math.abs(A);if(C>=p){return plural(A,C,p,"day")}if(C>=E){return plural(A,C,E,"hour")}if(C>=g){return plural(A,C,g,"minute")}if(C>=i){return plural(A,C,i,"second")}return A+" ms"}function plural(A,i,g,E){var p=i>=g*1.5;return Math.round(A/g)+" "+E+(p?"s":"")}},7777:(A,i,g)=>{var E=g(7016).parse;var p={ftp:21,gopher:70,http:80,https:443,ws:80,wss:443};var C=String.prototype.endsWith||function(A){return A.length<=this.length&&this.indexOf(A,this.length-A.length)!==-1};function getProxyForUrl(A){var i=typeof A==="string"?E(A):A||{};var g=i.protocol;var C=i.host;var f=i.port;if(typeof C!=="string"||!C||typeof g!=="string"){return""}g=g.split(":",1)[0];C=C.replace(/:\d*$/,"");f=parseInt(f)||p[g]||0;if(!shouldProxy(C,f)){return""}var Q=getEnv("npm_config_"+g+"_proxy")||getEnv(g+"_proxy")||getEnv("npm_config_proxy")||getEnv("all_proxy");if(Q&&Q.indexOf("://")===-1){Q=g+"://"+Q}return Q}function shouldProxy(A,i){var g=(getEnv("npm_config_no_proxy")||getEnv("no_proxy")).toLowerCase();if(!g){return true}if(g==="*"){return false}return g.split(/[,\s]/).every((function(g){if(!g){return true}var E=g.match(/^(.+):(\d+)$/);var p=E?E[1]:g;var f=E?parseInt(E[2]):0;if(f&&f!==i){return true}if(!/^[.*]/.test(p)){return A!==p}if(p.charAt(0)==="*"){p=p.slice(1)}return!C.call(A,p)}))}function getEnv(A){return process.env[A.toLowerCase()]||process.env[A.toUpperCase()]||""}i.T=getProxyForUrl},9546:(A,i,g)=>{var E;E={value:true};const p=g(1354);const C=g(7016);const f=g(4434);const Q=g(2830);const B=g(3106);const I=g(4922);const y=g(9023);const b=g(9896);const D=g(9557);const R=g(6928);function _interopDefaultLegacy(A){return A&&typeof A==="object"&&"default"in A?A:{default:A}}const k=_interopDefaultLegacy(p);const S=_interopDefaultLegacy(C);const v=_interopDefaultLegacy(Q);const F=_interopDefaultLegacy(B);const x=_interopDefaultLegacy(I);const U=_interopDefaultLegacy(y);const L=_interopDefaultLegacy(b);const M=_interopDefaultLegacy(D);const T=_interopDefaultLegacy(R);const H=v["default"]("screepsapi:socket");const G={reconnect:true,resubscribe:true,keepAlive:true,maxRetries:10,maxRetryDelay:60*1e3};class Socket extends f.EventEmitter{constructor(A){super();this.api=A;this.opts=Object.assign({},G);this.on("error",(()=>{}));this.reset();this.on("auth",(A=>{if(A.data.status==="ok"){while(this.__queue.lLine truncated
|
||||
/*!
|
||||
* Tmp
|
||||
*
|
||||
* Copyright (c) 2011-2017 KARASZI Istvan <github@spam.raszi.hu>
|
||||
*
|
||||
* MIT Licensed
|
||||
*/
|
||||
const E=g(9896);const p=g(857);const C=g(6928);const f=g(6982);const Q={fs:E.constants,os:p.constants};const B="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",I=/XXXXXX/,y=3,b=(Q.O_CREAT||Q.fs.O_CREAT)|(Q.O_EXCL||Q.fs.O_EXCL)|(Q.O_RDWR||Q.fs.O_RDWR),D=p.platform()==="win32",R=Q.EBADF||Q.os.errno.EBADF,k=Q.ENOENT||Q.os.errno.ENOENT,S=448,v=384,F="exit",x=[],U=E.rmdirSync.bind(E);let L=false;function rimraf(A,i){return E.rm(A,{recursive:true},i)}function FN_RIMRAF_SYNC(A){return E.rmSync(A,{recursive:true})}function tmpName(A,i){const g=_parseArguments(A,i),p=g[0],C=g[1];_assertAndSanitizeOptions(p,(function(A,i){if(A)return C(A);let g=i.tries;(function _getUniqueName(){try{const A=_generateTmpName(i);E.stat(A,(function(i){if(!i){if(g-- >0)return _getUniqueName();return C(new Error("Could not get a unique tmp filename, max tries reached "+A))}C(null,A)}))}catch(A){C(A)}})()}))}function tmpNameSync(A){const i=_parseArguments(A),g=i[0];const p=_assertAndSanitizeOptionsSync(g);let C=p.tries;do{const A=_generateTmpName(p);try{E.statSync(A)}catch(i){return A}}while(C-- >0);throw new Error("Could not get a unique tmp filename, max tries reached")}function file(A,i){const g=_parseArguments(A,i),p=g[0],C=g[1];tmpName(p,(function _tmpNameCreated(A,i){if(A)return C(A);E.open(i,b,p.mode||v,(function _fileCreated(A,g){if(A)return C(A);if(p.discardDescriptor){return E.close(g,(function _discardCallback(A){return C(A,i,undefined,_prepareTmpFileRemoveCallback(i,-1,p,false))}))}else{const A=p.discardDescriptor||p.detachDescriptor;C(null,i,g,_prepareTmpFileRemoveCallback(i,A?-1:g,p,false))}}))}))}function fileSync(A){const i=_parseArguments(A),g=i[0];const p=g.discardDescriptor||g.detachDescriptor;const C=tmpNameSync(g);let f=E.openSync(C,b,g.mode||v);if(g.discardDescriptor){E.closeSync(f);f=undefined}return{name:C,fd:f,removeCallback:_prepareTmpFileRemoveCallback(C,p?-1:f,g,true)}}function dir(A,i){const g=_parseArguments(A,i),p=g[0],C=g[1];tmpName(p,(function _tmpNameCreated(A,i){if(A)return C(A);E.mkdir(i,p.mode||S,(function _dirCreated(A){if(A)return C(A);C(null,i,_prepareTmpDirRemoveCallback(i,p,false))}))}))}function dirSync(A){const i=_parseArguments(A),g=i[0];const p=tmpNameSync(g);E.mkdirSync(p,g.mode||S);return{name:p,removeCallback:_prepareTmpDirRemoveCallback(p,g,true)}}function _removeFileAsync(A,i){const _handler=function(A){if(A&&!_isENOENT(A)){return i(A)}i()};if(0<=A[0])E.close(A[0],(function(){E.unlink(A[1],_handler)}));else E.unlink(A[1],_handler)}function _removeFileSync(A){let i=null;try{if(0<=A[0])E.closeSync(A[0])}catch(A){if(!_isEBADF(A)&&!_isENOENT(A))throw A}finally{try{E.unlinkSync(A[1])}catch(A){if(!_isENOENT(A))i=A}}if(i!==null){throw i}}function _prepareTmpFileRemoveCallback(A,i,g,E){const p=_prepareRemoveCallback(_removeFileSync,[i,A],E);const C=_prepareRemoveCallback(_removeFileAsync,[i,A],E,p);if(!g.keep)x.unshift(p);return E?p:C}function _prepareTmpDirRemoveCallback(A,i,g){const p=i.unsafeCleanup?rimraf:E.rmdir.bind(E);const C=i.unsafeCleanup?FN_RIMRAF_SYNC:U;const f=_prepareRemoveCallback(C,A,g);const Q=_prepareRemoveCallback(p,A,g,f);if(!i.keep)x.unshift(f);return g?f:Q}function _prepareRemoveCallback(A,i,g,E){let p=false;return function _cleanupCallback(C){if(!p){const f=E||_cleanupCallback;const Q=x.indexOf(f);if(Q>=0)x.splice(Q,1);p=true;if(g||A===U||A===FN_RIMRAF_SYNC){return A(i)}else{return A(i,C||function(){})}}}}function _garbageCollector(){if(!L)return;while(x.length){try{x[0]()}catch(A){}}}function _randomChars(A){let i=[],g=null;try{g=f.randomBytes(A)}catch(i){g=f.pseudoRandomBytes(A)}for(let E=0;E<A;E++){i.push(B[g[E]%B.length])}return i.join("")}function _isUndefined(A){return typeof A==="undefined"}function _parseArguments(A,i){if(typeof A==="function"){return[{},A]}if(_isUndefined(A)){return[{},i]}const g={};for(const i of Object.getOwnPropertyNames(A)){g[i]=A[i]}return[g,i]}function _resolvePath(A,i,g){const p=C.isAbsolute(A)?A:C.join(i,A);E.stat(p,(function(A){if(A){E.realpath(C.dirname(p),(function(A,i){if(A)return g(A);g(null,C.join(i,C.basename(p)))}))}else{E.realpath(p,g)}}))}function _resolvePathSync(A,i){const g=C.isAbsolute(A)?A:C.join(i,A);try{E.statSync(g);return E.realpathSync(g)}catch(A){const i=E.realpathSync(C.dirname(g));return C.join(i,C.basename(g))}}function _generateTmpName(A){const i=A.tmpdir;if(!_isUndefined(A.name)){return C.join(i,A.dir,A.name)}if(!_isUndefined(A.template)){return C.join(i,A.dir,A.template).replace(I,_randomChars(6))}const g=[A.prefix?A.prefix:"tmp","-",process.pid,"-",_randomChars(12),A.postfix?"-"+A.postfix:""].join("");return C.join(i,A.dir,g)}function _assertOptionsBase(A){if(!_isUndefined(A.name)){const i=A.name;if(C.isAbsolute(i))throw new Error(`name option must not contain an absolute path, found "${i}".`);const g=C.basename(i);if(g===".."||g==="."||g!==i)throw new Error(`name option must not contain a path, found "${i}".`)}if(!_isUndefined(A.template)&&!A.template.match(I)){throw new Error(`Invalid template,
Line truncated
|
||||
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */;const escape=A=>A.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22");const normalizeLinefeeds=A=>A.replace(/\r?\n|\r/g,"\r\n");const E=[];const p=new Uint8Array([13,10]);y=0;let C=false;for(const[i,f]of A){if(typeof f==="string"){const A=H.encode(g+`; name="${escape(normalizeLinefeeds(i))}"`+`\r\n\r\n${normalizeLinefeeds(f)}\r\n`);E.push(A);y+=A.byteLength}else{const A=H.encode(`${g}; name="${escape(normalizeLinefeeds(i))}"`+(f.name?`; filename="${escape(f.name)}"`:"")+"\r\n"+`Content-Type: ${f.type||"application/octet-stream"}\r\n\r\n`);E.push(A,f,p);if(typeof f.size==="number"){y+=A.byteLength+f.size+p.byteLength}else{C=true}}}const f=H.encode(`--${i}--\r\n`);E.push(f);y+=f.byteLength;if(C){y=null}I=A;B=async function*(){for(const A of E){if(A.stream){yield*A.stream()}else{yield A}}};b=`multipart/form-data; boundary=${i}`}else if(C(A)){I=A;y=A.size;if(A.type){b=A.type}}else if(typeof A[Symbol.asyncIterator]==="function"){if(i){throw new TypeError("keepalive")}if(E.isDisturbed(A)||A.locked){throw new TypeError("Response body object should not be disturbed or locked")}g=A instanceof ReadableStream?A:p(A)}if(typeof I==="string"||E.isBuffer(I)){y=Buffer.byteLength(I)}if(B!=null){let i;g=new ReadableStream({async start(){i=B(A)[Symbol.asyncIterator]()},async pull(A){const{value:E,done:p}=await i.next();if(p){queueMicrotask((()=>{A.close();A.byobRequest?.respond(0)}))}else{if(!F(g)){const i=new Uint8Array(E);if(i.byteLength){A.enqueue(i)}}}return A.desiredSize>0},async cancel(A){await i.return()},type:"bytes"})}const D={stream:g,source:I,length:y};return[D,b]}function safelyExtractBody(A,i=false){if(A instanceof ReadableStream){v(!E.isDisturbed(A),"The body has already been consumed.");v(!A.locked,"The stream is locked.")}return extractBody(A,i)}function cloneBody(A,i){const[g,E]=i.stream.tee();i.stream=g;return{stream:E,length:i.length,source:i.source}}function throwIfAborted(A){if(A.aborted){throw new DOMException("The operation was aborted.","AbortError")}}function bodyMixinMethods(A){const i={blob(){return consumeBody(this,(A=>{let i=bodyMimeType(this);if(i===null){i=""}else if(i){i=L(i)}return new S([A],{type:i})}),A)},arrayBuffer(){return consumeBody(this,(A=>new Uint8Array(A).buffer),A)},text(){return consumeBody(this,b,A)},json(){return consumeBody(this,parseJSONFromBytes,A)},formData(){return consumeBody(this,(A=>{const i=bodyMimeType(this);if(i!==null){switch(i.essence){case"multipart/form-data":{const g=M(A,i);if(g==="failure"){throw new TypeError("Failed to parse body as FormData.")}const E=new D;E[R]=g;return E}case"application/x-www-form-urlencoded":{const i=new URLSearchParams(A.toString());const g=new D;for(const[A,E]of i){g.append(A,E)}return g}}}throw new TypeError('Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".')}),A)},bytes(){return consumeBody(this,(A=>new Uint8Array(A)),A)}};return i}function mixinBody(A){Object.assign(A.prototype,bodyMixinMethods(A))}async function consumeBody(A,i,g){k.brandCheck(A,g);if(bodyUnusable(A)){throw new TypeError("Body is unusable: Body has already been read")}throwIfAborted(A[R]);const E=B();const errorSteps=A=>E.reject(A);const successSteps=A=>{try{E.resolve(i(A))}catch(A){errorSteps(A)}};if(A[R].body==null){successSteps(Buffer.allocUnsafe(0));return E.promise}await I(A[R].body,successSteps,errorSteps);return E.promise}function bodyUnusable(A){const i=A[R].body;return i!=null&&(i.stream.locked||E.isDisturbed(i.stream))}function parseJSONFromBytes(A){return JSON.parse(b(A))}function bodyMimeType(A){const i=A[R].headersList;const g=y(i);if(g==="failure"){return null}return g}A.exports={extractBody:extractBody,safelyExtractBody:safelyExtractBody,cloneBody:cloneBody,mixinBody:mixinBody,streamRegistry:Y,hasFinalizationRegistry:G,bodyUnusable:bodyUnusable}},4495:A=>{const i=["GET","HEAD","POST"];const g=new Set(i);const E=[101,204,205,304];const p=[301,302,303,307,308];const C=new Set(p);const f=["1","7","9","11","13","15","17","19","20","21","22","23","25","37","42","43","53","69","77","79","87","95","101","102","103","104","109","110","111","113","115","117","119","123","135","137","139","143","161","179","389","427","465","512","513","514","515","526","530","531","532","540","548","554","556","563","587","601","636","989","990","993","995","1719","1720","1723","2049","3659","4045","4190","5060","5061","6000","6566","6665","6666","6667","6668","6669","6679","6697","10080"];const Q=new Set(f);const B=["","no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"];const I=new Set(B);const y=["follow","manual","error"];const b=["GET","HEAD","OPTIONS","TRACE"];const D=new Set(b);const R=["navigate","same-origin","no-cors","cors"];const k=["omit","same-origin","include"];const S=["default","no-store","reload","no-cache","force-cLine truncated
|
||||
/*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */Q[f-4]=g[0];Q[f-3]=g[1];Q[f-2]=g[2];Q[f-1]=g[3];Q[1]=C;if(C===126){Q.writeUInt16BE(p,2)}else if(C===127){Q[2]=Q[3]=0;Q.writeUIntBE(p,4,6)}Q[1]|=128;for(let A=0;A<p;++A){Q[f+A]=i[A]^g[A&3]}return Q}}A.exports={WebsocketFrameSend:WebsocketFrameSend}},9469:(A,i,g)=>{const{createInflateRaw:E,Z_DEFAULT_WINDOWBITS:p}=g(8522);const{isValidClientWindowBits:C}=g(8625);const f=Buffer.from([0,0,255,255]);const Q=Symbol("kBuffer");const B=Symbol("kLength");class PerMessageDeflate{#re;#S={};constructor(A){this.#S.serverNoContextTakeover=A.has("server_no_context_takeover");this.#S.serverMaxWindowBits=A.get("server_max_window_bits")}decompress(A,i,g){if(!this.#re){let A=p;if(this.#S.serverMaxWindowBits){if(!C(this.#S.serverMaxWindowBits)){g(new Error("Invalid server_max_window_bits"));return}A=Number.parseInt(this.#S.serverMaxWindowBits)}this.#re=E({windowBits:A});this.#re[Q]=[];this.#re[B]=0;this.#re.on("data",(A=>{this.#re[Q].push(A);this.#re[B]+=A.length}));this.#re.on("error",(A=>{this.#re=null;g(A)}))}this.#re.write(A);if(i){this.#re.write(f)}this.#re.flush((()=>{const A=Buffer.concat(this.#re[Q],this.#re[B]);this.#re[Q].length=0;this.#re[B]=0;g(null,A)}))}}A.exports={PerMessageDeflate:PerMessageDeflate}},1652:(A,i,g)=>{const{Writable:E}=g(7075);const p=g(4589);const{parserStates:C,opcodes:f,states:Q,emptyBuffer:B,sentCloseFrameState:I}=g(736);const{kReadyState:y,kSentClose:b,kResponse:D,kReceivedClose:R}=g(1216);const{channels:k}=g(2414);const{isValidStatusCode:S,isValidOpcode:v,failWebsocketConnection:F,websocketMessageReceived:x,utf8Decode:U,isControlFrame:L,isTextBinaryFrame:M,isContinuationFrame:T}=g(8625);const{WebsocketFrameSend:H}=g(3264);const{closeWebSocketConnection:G}=g(6897);const{PerMessageDeflate:Y}=g(9469);class ByteParser extends E{#n=[];#o=0;#ie=false;#a=C.INFO;#c={};#l=[];#d;constructor(A,i){super();this.ws=A;this.#d=i==null?new Map:i;if(this.#d.has("permessage-deflate")){this.#d.set("permessage-deflate",new Y(i))}}_write(A,i,g){this.#n.push(A);this.#o+=A.length;this.#ie=true;this.run(g)}run(A){while(this.#ie){if(this.#a===C.INFO){if(this.#o<2){return A()}const i=this.consume(2);const g=(i[0]&128)!==0;const E=i[0]&15;const p=(i[1]&128)===128;const Q=!g&&E!==f.CONTINUATION;const B=i[1]&127;const I=i[0]&64;const y=i[0]&32;const b=i[0]&16;if(!v(E)){F(this.ws,"Invalid opcode received");return A()}if(p){F(this.ws,"Frame cannot be masked");return A()}if(I!==0&&!this.#d.has("permessage-deflate")){F(this.ws,"Expected RSV1 to be clear.");return}if(y!==0||b!==0){F(this.ws,"RSV1, RSV2, RSV3 must be clear");return}if(Q&&!M(E)){F(this.ws,"Invalid frame type was fragmented.");return}if(M(E)&&this.#l.length>0){F(this.ws,"Expected continuation frame");return}if(this.#c.fragmented&&Q){F(this.ws,"Fragmented frame exceeded 125 bytes.");return}if((B>125||Q)&&L(E)){F(this.ws,"Control frame either too large or fragmented");return}if(T(E)&&this.#l.length===0&&!this.#c.compressed){F(this.ws,"Unexpected continuation frame");return}if(B<=125){this.#c.payloadLength=B;this.#a=C.READ_DATA}else if(B===126){this.#a=C.PAYLOADLENGTH_16}else if(B===127){this.#a=C.PAYLOADLENGTH_64}if(M(E)){this.#c.binaryType=E;this.#c.compressed=I!==0}this.#c.opcode=E;this.#c.masked=p;this.#c.fin=g;this.#c.fragmented=Q}else if(this.#a===C.PAYLOADLENGTH_16){if(this.#o<2){return A()}const i=this.consume(2);this.#c.payloadLength=i.readUInt16BE(0);this.#a=C.READ_DATA}else if(this.#a===C.PAYLOADLENGTH_64){if(this.#o<8){return A()}const i=this.consume(8);const g=i.readUInt32BE(0);if(g>2**31-1){F(this.ws,"Received payload length > 2^31 bytes.");return}const E=i.readUInt32BE(4);this.#c.payloadLength=(g<<8)+E;this.#a=C.READ_DATA}else if(this.#a===C.READ_DATA){if(this.#o<this.#c.payloadLength){return A()}const i=this.consume(this.#c.payloadLength);if(L(this.#c.opcode)){this.#ie=this.parseControlFrame(i);this.#a=C.INFO}else{if(!this.#c.compressed){this.#l.push(i);if(!this.#c.fragmented&&this.#c.fin){const A=Buffer.concat(this.#l);x(this.ws,this.#c.binaryType,A);this.#l.length=0}this.#a=C.INFO}else{this.#d.get("permessage-deflate").decompress(i,this.#c.fin,((i,g)=>{if(i){G(this.ws,1007,i.message,i.message.length);return}this.#l.push(g);if(!this.#c.fin){this.#a=C.INFO;this.#ie=true;this.run(A);return}x(this.ws,this.#c.binaryType,Buffer.concat(this.#l));this.#ie=true;this.#a=C.INFO;this.#l.length=0;this.run(A)}));this.#ie=false;break}}}}}consume(A){if(A>this.#o){throw new Error("Called consume() before buffers satiated.")}else if(A===0){return B}if(this.#n[0].length===A){this.#o-=this.#n[0].length;return this.#n.shift()}const i=Buffer.allocUnsafe(A);let g=0;while(g!==A){const E=this.#n[0];const{length:p}=E;if(p+g===A){i.set(this.#n.shift(),g);break}else if(p+g>A){i.set(E.subarray(0,A-g),g);this.#n[0]=E.subarray(A-g);break}else{i.set(this.#n.shift(),g);g+=E.length}}this.#o-=A;return i}parseCloseBody(A){p(A.length!==1);let i;if(A.length>=2){i=A.readUInt16BE(0)}if(i!==undefined&&!S(i)){return{code:1002,Line truncated
|
||||
@@ -4,6 +4,7 @@ import fs from "fs";
|
||||
import { glob } from "glob";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { monitorConsole } from "./monitor.js";
|
||||
|
||||
/**
|
||||
* Replaces specific placeholder strings within the provided content with corresponding dynamic values.
|
||||
@@ -39,7 +40,8 @@ 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.
|
||||
*/
|
||||
export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
||||
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||
let globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||
globPattern = globPattern.replace(/\\/g, "/");
|
||||
const files = await glob(globPattern);
|
||||
|
||||
let processPromises = files.map((file) => {
|
||||
@@ -61,7 +63,8 @@ export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
||||
*/
|
||||
export async function readFilesIntoDict(pattern, prefix) {
|
||||
// Prepend the prefix to the glob pattern
|
||||
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||
let globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||
globPattern = globPattern.replace(/\\/g, "/");
|
||||
const files = await glob(globPattern);
|
||||
|
||||
let fileDict = {};
|
||||
@@ -108,6 +111,28 @@ export function validateAuthentication(token, username, password) {
|
||||
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
|
||||
* @returns {boolean} - Returns true if the action was 'fail' and the flag was true.
|
||||
*/
|
||||
export function applyOnAction(action, flag, message) {
|
||||
if (!flag) return false;
|
||||
if (action === "warn") {
|
||||
core.warning(message);
|
||||
return false;
|
||||
}
|
||||
if (action === "fail") {
|
||||
core.setFailed(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts code to Screeps server.
|
||||
*/
|
||||
@@ -156,23 +181,112 @@ export async function postCode() {
|
||||
return;
|
||||
}
|
||||
let api = new ScreepsAPI(login_arguments);
|
||||
if (token) {
|
||||
|
||||
if (!token) {
|
||||
core.info(`Logging in as user ${username}`);
|
||||
try {
|
||||
await api.auth(username, password, login_arguments);
|
||||
} catch (err) {
|
||||
core.error(`Authentication error: ${err}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
let oldCode = null;
|
||||
let rollbackOnFailure = false;
|
||||
try {
|
||||
rollbackOnFailure = core.getBooleanInput("rollback_on_failure");
|
||||
} catch (e) {
|
||||
// getBooleanInput throws if not 'true' or 'false', ignore
|
||||
}
|
||||
|
||||
if (rollbackOnFailure) {
|
||||
core.info(
|
||||
`Downloading existing code from branch ${branch} for potential rollback...`,
|
||||
);
|
||||
try {
|
||||
const getResponse = await api.code.get(branch);
|
||||
if (getResponse && getResponse.ok && getResponse.modules) {
|
||||
oldCode = getResponse.modules;
|
||||
core.info(
|
||||
`Successfully downloaded existing code (modules: ${Object.keys(oldCode).join(", ")})`,
|
||||
);
|
||||
} else {
|
||||
core.setFailed(
|
||||
`Failed to download existing code, but rollback_on_failure is enabled. Aborting deployment.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
core.setFailed(
|
||||
`Error downloading existing code: ${err.message}. Aborting deployment.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await api.code.set(branch, files_to_push);
|
||||
core.info(JSON.stringify(response, null, 2));
|
||||
console.log(`Code set successfully to ${branch}`);
|
||||
} else {
|
||||
core.info(`Logging in as user ${username}`);
|
||||
await Promise.resolve()
|
||||
.then(() => api.auth(username, password, login_arguments))
|
||||
.then(() => {
|
||||
api.code.set(branch, files_to_push);
|
||||
})
|
||||
.then(() => {
|
||||
console.log(`Code set successfully to ${branch}`);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error:", err);
|
||||
});
|
||||
core.info(`Code set successfully to ${branch}`);
|
||||
} catch (err) {
|
||||
core.error(`Upload error: ${err}`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Console monitoring (optional)
|
||||
const monitorTicks = parseInt(core.getInput("monitor") || "0", 10);
|
||||
if (monitorTicks > 0) {
|
||||
const onTraceback = core.getInput("on_traceback") || "fail";
|
||||
const onErrorLog = core.getInput("on_error_log") || "warn";
|
||||
const onWarningLog = core.getInput("on_warning_log") || "ignore";
|
||||
|
||||
const result = await monitorConsole(api, {
|
||||
monitor: monitorTicks,
|
||||
logToFile: core.getBooleanInput("log_to_file"),
|
||||
onTraceback,
|
||||
onErrorLog,
|
||||
onWarningLog,
|
||||
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));
|
||||
|
||||
const fail1 = applyOnAction(
|
||||
onTraceback,
|
||||
result.sawTraceback,
|
||||
"Screeps console: traceback detected",
|
||||
);
|
||||
const fail2 = applyOnAction(
|
||||
onErrorLog,
|
||||
result.sawErrorLog,
|
||||
"Screeps console: error log output detected",
|
||||
);
|
||||
const fail3 = applyOnAction(
|
||||
onWarningLog,
|
||||
result.sawWarningLog,
|
||||
"Screeps console: warning log output detected",
|
||||
);
|
||||
|
||||
const shouldFail = fail1 || fail2 || fail3;
|
||||
|
||||
if (shouldFail && rollbackOnFailure && oldCode) {
|
||||
core.info(
|
||||
"Action failed based on monitor configuration. Rolling back to previous code...",
|
||||
);
|
||||
try {
|
||||
await api.code.set(branch, oldCode);
|
||||
core.info(
|
||||
`Successfully rolled back to previous code on branch ${branch}.`,
|
||||
);
|
||||
} catch (err) {
|
||||
core.error(`Rollback failed: ${err}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
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
+223
-136
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "screeps-deploy-action",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "screeps-deploy-action",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.1",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^1.1.2",
|
||||
"@actions/core": "^3.0.0",
|
||||
"glob": "^13.0.0",
|
||||
"screeps-api": "^1.7.2"
|
||||
@@ -18,6 +19,65 @@
|
||||
"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": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz",
|
||||
@@ -147,6 +207,15 @@
|
||||
"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": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
|
||||
@@ -204,9 +273,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.129.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz",
|
||||
"integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==",
|
||||
"version": "0.133.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -214,9 +283,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz",
|
||||
"integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -231,9 +300,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz",
|
||||
"integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -248,9 +317,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz",
|
||||
"integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
|
||||
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -265,9 +334,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz",
|
||||
"integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
|
||||
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -282,9 +351,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz",
|
||||
"integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
|
||||
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -299,9 +368,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz",
|
||||
"integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -319,9 +388,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz",
|
||||
"integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
|
||||
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -339,9 +408,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz",
|
||||
"integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -359,9 +428,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz",
|
||||
"integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -379,9 +448,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz",
|
||||
"integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -399,9 +468,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz",
|
||||
"integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -419,9 +488,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz",
|
||||
"integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -436,9 +505,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz",
|
||||
"integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
|
||||
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
@@ -455,9 +524,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz",
|
||||
"integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
|
||||
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -472,9 +541,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz",
|
||||
"integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
|
||||
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -489,9 +558,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz",
|
||||
"integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -549,14 +618,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz",
|
||||
"integrity": "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz",
|
||||
"integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^1.0.2",
|
||||
"@vitest/utils": "4.1.6",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"ast-v8-to-istanbul": "^1.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
@@ -570,8 +639,8 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/browser": "4.1.6",
|
||||
"vitest": "4.1.6"
|
||||
"@vitest/browser": "4.1.8",
|
||||
"vitest": "4.1.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vitest/browser": {
|
||||
@@ -580,16 +649,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
|
||||
"integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz",
|
||||
"integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.6",
|
||||
"@vitest/utils": "4.1.6",
|
||||
"@vitest/spy": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -598,13 +667,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz",
|
||||
"integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz",
|
||||
"integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.6",
|
||||
"@vitest/spy": "4.1.8",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@@ -625,9 +694,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz",
|
||||
"integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz",
|
||||
"integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -638,13 +707,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz",
|
||||
"integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz",
|
||||
"integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.6",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -652,14 +721,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz",
|
||||
"integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz",
|
||||
"integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.6",
|
||||
"@vitest/utils": "4.1.6",
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@@ -668,9 +737,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz",
|
||||
"integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz",
|
||||
"integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -678,13 +747,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz",
|
||||
"integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz",
|
||||
"integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.6",
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -1741,9 +1810,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.14",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
||||
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1761,7 +1830,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"nanoid": "^3.3.12",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -1776,14 +1845,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz",
|
||||
"integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.129.0",
|
||||
"@rolldown/pluginutils": "1.0.0"
|
||||
"@oxc-project/types": "=0.133.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
@@ -1792,21 +1861,21 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0"
|
||||
"@rolldown/binding-android-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/screeps-api": {
|
||||
@@ -1910,9 +1979,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.16",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1936,6 +2005,24 @@
|
||||
"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": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
@@ -1977,17 +2064,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.12",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz",
|
||||
"integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==",
|
||||
"version": "8.0.16",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.14",
|
||||
"rolldown": "1.0.0",
|
||||
"tinyglobby": "^0.2.16"
|
||||
"postcss": "^8.5.15",
|
||||
"rolldown": "1.0.3",
|
||||
"tinyglobby": "^0.2.17"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -2055,19 +2142,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz",
|
||||
"integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==",
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz",
|
||||
"integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.6",
|
||||
"@vitest/mocker": "4.1.6",
|
||||
"@vitest/pretty-format": "4.1.6",
|
||||
"@vitest/runner": "4.1.6",
|
||||
"@vitest/snapshot": "4.1.6",
|
||||
"@vitest/spy": "4.1.6",
|
||||
"@vitest/utils": "4.1.6",
|
||||
"@vitest/expect": "4.1.8",
|
||||
"@vitest/mocker": "4.1.8",
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"@vitest/runner": "4.1.8",
|
||||
"@vitest/snapshot": "4.1.8",
|
||||
"@vitest/spy": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
@@ -2095,12 +2182,12 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.6",
|
||||
"@vitest/browser-preview": "4.1.6",
|
||||
"@vitest/browser-webdriverio": "4.1.6",
|
||||
"@vitest/coverage-istanbul": "4.1.6",
|
||||
"@vitest/coverage-v8": "4.1.6",
|
||||
"@vitest/ui": "4.1.6",
|
||||
"@vitest/browser-playwright": "4.1.8",
|
||||
"@vitest/browser-preview": "4.1.8",
|
||||
"@vitest/browser-webdriverio": "4.1.8",
|
||||
"@vitest/coverage-istanbul": "4.1.8",
|
||||
"@vitest/coverage-v8": "4.1.8",
|
||||
"@vitest/ui": "4.1.8",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "screeps-deploy-action",
|
||||
"version": "0.1.1",
|
||||
"description": "Deploys screeps code to the official game or an pirvate server.",
|
||||
"version": "0.2.1",
|
||||
"description": "Deploys screeps code to the official game or a private server.",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -10,6 +10,7 @@
|
||||
"build": "ncc build index.js -o dist -m --external utf-8-validate --external bufferutil"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^1.1.2",
|
||||
"@actions/core": "^3.0.0",
|
||||
"glob": "^13.0.0",
|
||||
"screeps-api": "^1.7.2"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
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();
|
||||
@@ -0,0 +1,12 @@
|
||||
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