@blackasteroid/riu 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +371 -0
- package/dist/cache/uploads.js +48 -0
- package/dist/cache/uploads.js.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.js +89 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.js +168 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-sdk.js +121 -0
- package/dist/commands/install-sdk.js.map +1 -0
- package/dist/commands/list.js +67 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/new.js +177 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/update.js +116 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/upgrade.js +93 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/upload-all.js +250 -0
- package/dist/commands/upload-all.js.map +1 -0
- package/dist/commands/upload.js +205 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/config/schema.js +76 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.js +70 -0
- package/dist/config/store.js.map +1 -0
- package/dist/manifest/builder.js +84 -0
- package/dist/manifest/builder.js.map +1 -0
- package/dist/manifest/itemTypes.js +44 -0
- package/dist/manifest/itemTypes.js.map +1 -0
- package/dist/manifest/writer.js +38 -0
- package/dist/manifest/writer.js.map +1 -0
- package/dist/sdk/installer.js +59 -0
- package/dist/sdk/installer.js.map +1 -0
- package/dist/sdk/locator.js +160 -0
- package/dist/sdk/locator.js.map +1 -0
- package/dist/steam/client.js +163 -0
- package/dist/steam/client.js.map +1 -0
- package/dist/steam/mock.js +51 -0
- package/dist/steam/mock.js.map +1 -0
- package/dist/steam/types.js +7 -0
- package/dist/steam/types.js.map +1 -0
- package/dist/ui/BulkUploadProgress.js +21 -0
- package/dist/ui/BulkUploadProgress.js.map +1 -0
- package/dist/ui/InitWizard.js +67 -0
- package/dist/ui/InitWizard.js.map +1 -0
- package/dist/ui/NewSkinWizard.js +52 -0
- package/dist/ui/NewSkinWizard.js.map +1 -0
- package/dist/ui/UploadProgress.js +46 -0
- package/dist/ui/UploadProgress.js.map +1 -0
- package/dist/utils/iconValidator.js +68 -0
- package/dist/utils/iconValidator.js.map +1 -0
- package/dist/utils/slugify.js +13 -0
- package/dist/utils/slugify.js.map +1 -0
- package/dist/utils/updateCheck.js +93 -0
- package/dist/utils/updateCheck.js.map +1 -0
- package/dist/version.js +9 -0
- package/dist/version.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { readConfig } from "../config/store.js";
|
|
8
|
+
import { readManifest } from "../manifest/writer.js";
|
|
9
|
+
import { validateIcon } from "../utils/iconValidator.js";
|
|
10
|
+
import { createSteamClient } from "../steam/client.js";
|
|
11
|
+
import { appendUpload } from "../cache/uploads.js";
|
|
12
|
+
import { UploadProgress } from "../ui/UploadProgress.js";
|
|
13
|
+
const UploadPayloadSchema = z.object({
|
|
14
|
+
skinDir: z.string().min(1, "skinDir is required"),
|
|
15
|
+
title: z.string().min(1).max(128).optional(),
|
|
16
|
+
description: z.string().optional(),
|
|
17
|
+
tags: z.array(z.string().min(1)).optional(),
|
|
18
|
+
});
|
|
19
|
+
function emitJson(payload, exitCode) {
|
|
20
|
+
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
21
|
+
process.exit(exitCode);
|
|
22
|
+
}
|
|
23
|
+
function emitErr(opts, message, field, exitCode = 2) {
|
|
24
|
+
if (opts.jsonFlag) {
|
|
25
|
+
emitJson({ status: "error", error: { message, field } }, exitCode);
|
|
26
|
+
}
|
|
27
|
+
process.stderr.write(`error: ${message}${field ? ` (field: ${field})` : ""}\n`);
|
|
28
|
+
process.exit(exitCode);
|
|
29
|
+
}
|
|
30
|
+
async function resolveUpload(opts) {
|
|
31
|
+
const cfg = readConfig();
|
|
32
|
+
if (!cfg) {
|
|
33
|
+
emitErr(opts, "no config found — run `riu init` first", undefined, 1);
|
|
34
|
+
}
|
|
35
|
+
// Source of skinDir: positional arg > JSON payload > error
|
|
36
|
+
let skinDirRaw = opts.positionalSkinDir;
|
|
37
|
+
let titleOverride = opts.title;
|
|
38
|
+
let descriptionOverride = opts.description;
|
|
39
|
+
let tagsOverride = opts.tags
|
|
40
|
+
? opts.tags.split(",").map((t) => t.trim()).filter(Boolean)
|
|
41
|
+
: undefined;
|
|
42
|
+
if (opts.jsonPayload && typeof opts.jsonPayload === "object") {
|
|
43
|
+
const parsed = UploadPayloadSchema.safeParse(opts.jsonPayload);
|
|
44
|
+
if (!parsed.success) {
|
|
45
|
+
const issue = parsed.error.issues[0];
|
|
46
|
+
emitErr(opts, issue?.message ?? "validation failed", issue?.path.join(".") ?? undefined);
|
|
47
|
+
}
|
|
48
|
+
const payload = parsed.data;
|
|
49
|
+
skinDirRaw = skinDirRaw ?? payload.skinDir;
|
|
50
|
+
titleOverride = titleOverride ?? payload.title;
|
|
51
|
+
descriptionOverride = descriptionOverride ?? payload.description;
|
|
52
|
+
tagsOverride = tagsOverride ?? payload.tags;
|
|
53
|
+
}
|
|
54
|
+
if (!skinDirRaw) {
|
|
55
|
+
emitErr(opts, "skinDir is required (pass as positional arg or in --json payload)", "skinDir");
|
|
56
|
+
}
|
|
57
|
+
const skinDir = resolve(skinDirRaw);
|
|
58
|
+
if (!existsSync(skinDir)) {
|
|
59
|
+
emitErr(opts, `skin folder not found: ${skinDir}`, "skinDir");
|
|
60
|
+
}
|
|
61
|
+
// Read manifest.txt to source itemType (and sanity check this is a riu skin folder)
|
|
62
|
+
const manifest = readManifest(skinDir);
|
|
63
|
+
if (!manifest) {
|
|
64
|
+
emitErr(opts, `no manifest.txt in ${skinDir} — run \`riu new\` first`, "skinDir");
|
|
65
|
+
}
|
|
66
|
+
// Look for icon.png
|
|
67
|
+
const iconPath = join(skinDir, "icon.png");
|
|
68
|
+
if (!existsSync(iconPath)) {
|
|
69
|
+
emitErr(opts, `no icon.png in ${skinDir}`, "skinDir");
|
|
70
|
+
}
|
|
71
|
+
// Validate the icon (defensive — `riu new` already did this, but the user
|
|
72
|
+
// could have hand-edited the folder)
|
|
73
|
+
const iconResult = await validateIcon(iconPath);
|
|
74
|
+
if (!iconResult.ok) {
|
|
75
|
+
emitErr(opts, `icon validation failed: ${iconResult.errors.join("; ")}`, "iconPath");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
skinDir,
|
|
79
|
+
iconPath,
|
|
80
|
+
itemType: manifest.ItemType,
|
|
81
|
+
title: titleOverride ?? manifest.ItemType + " skin",
|
|
82
|
+
description: descriptionOverride ?? cfg.defaultDescription,
|
|
83
|
+
tags: tagsOverride ?? cfg.defaultTags,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function UploadRunner({ resolved, client, dryRun, onDone }) {
|
|
87
|
+
const [stage, setStage] = useState("validating");
|
|
88
|
+
const [errorMsg, setErrorMsg] = useState(undefined);
|
|
89
|
+
const [result, setResult] = useState(undefined);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
void (async () => {
|
|
92
|
+
try {
|
|
93
|
+
// Stages exist mostly for the user-facing progress UI; the underlying
|
|
94
|
+
// client.uploadSkin() does CreateItem→Set*→Submit in one shot.
|
|
95
|
+
setStage("creating");
|
|
96
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
97
|
+
setStage("configuring");
|
|
98
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
99
|
+
setStage("uploading");
|
|
100
|
+
const r = await client.uploadSkin({
|
|
101
|
+
skinDir: resolved.skinDir,
|
|
102
|
+
title: resolved.title,
|
|
103
|
+
description: resolved.description,
|
|
104
|
+
tags: resolved.tags,
|
|
105
|
+
previewPng: resolved.iconPath,
|
|
106
|
+
});
|
|
107
|
+
setStage("submitting");
|
|
108
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
109
|
+
setStage("done");
|
|
110
|
+
setResult(r);
|
|
111
|
+
// Defer to next tick so the "done" frame renders before we tear down
|
|
112
|
+
setTimeout(() => onDone(r, null), 50);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
116
|
+
setErrorMsg(msg);
|
|
117
|
+
setStage("error");
|
|
118
|
+
setTimeout(() => onDone({ publishedFileId: "", url: "", needsLegalAgreement: false }, e instanceof Error ? e : new Error(msg)), 50);
|
|
119
|
+
}
|
|
120
|
+
})();
|
|
121
|
+
}, [client, resolved]);
|
|
122
|
+
return (_jsx(UploadProgress, { title: resolved.title, stage: stage, publishedFileId: result?.publishedFileId, url: result?.url, errorMsg: errorMsg, isMock: dryRun }));
|
|
123
|
+
}
|
|
124
|
+
export async function runUpload(opts) {
|
|
125
|
+
const cfg = readConfig();
|
|
126
|
+
if (!cfg)
|
|
127
|
+
emitErr(opts, "no config found — run `riu init` first", undefined, 1);
|
|
128
|
+
const resolved = await resolveUpload(opts);
|
|
129
|
+
// Build the Steam client (mock if dry-run, real otherwise)
|
|
130
|
+
let client;
|
|
131
|
+
try {
|
|
132
|
+
client = await createSteamClient({
|
|
133
|
+
sdkPath: cfg.steamSdkPath,
|
|
134
|
+
appId: cfg.steamAppId,
|
|
135
|
+
mock: opts.dryRun,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
emitErr(opts, e instanceof Error ? e.message : String(e), "steamSdkPath", 1);
|
|
140
|
+
}
|
|
141
|
+
// JSON mode: skip the Ink UI entirely, just run + emit a single result
|
|
142
|
+
if (opts.jsonFlag) {
|
|
143
|
+
try {
|
|
144
|
+
const result = await client.uploadSkin({
|
|
145
|
+
skinDir: resolved.skinDir,
|
|
146
|
+
title: resolved.title,
|
|
147
|
+
description: resolved.description,
|
|
148
|
+
tags: resolved.tags,
|
|
149
|
+
previewPng: resolved.iconPath,
|
|
150
|
+
});
|
|
151
|
+
// Persist to cache (dry-run entries get flagged so `riu list` can filter them)
|
|
152
|
+
appendUpload(cfg.cacheDir, {
|
|
153
|
+
publishedFileId: result.publishedFileId,
|
|
154
|
+
title: resolved.title,
|
|
155
|
+
itemType: resolved.itemType,
|
|
156
|
+
skinDir: resolved.skinDir,
|
|
157
|
+
uploadedAt: new Date().toISOString(),
|
|
158
|
+
url: result.url,
|
|
159
|
+
tags: resolved.tags,
|
|
160
|
+
description: resolved.description,
|
|
161
|
+
dryRun: opts.dryRun || undefined,
|
|
162
|
+
});
|
|
163
|
+
client.shutdown();
|
|
164
|
+
emitJson({
|
|
165
|
+
status: "ok",
|
|
166
|
+
mode: opts.dryRun ? "dry-run" : "uploaded",
|
|
167
|
+
publishedFileId: result.publishedFileId,
|
|
168
|
+
url: result.url,
|
|
169
|
+
title: resolved.title,
|
|
170
|
+
itemType: resolved.itemType,
|
|
171
|
+
skinDir: resolved.skinDir,
|
|
172
|
+
}, 0);
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
client.shutdown();
|
|
176
|
+
emitErr(opts, e instanceof Error ? e.message : String(e));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Interactive mode — render the Ink progress UI
|
|
180
|
+
await new Promise((resolveOuter) => {
|
|
181
|
+
const app = render(_jsx(UploadRunner, { resolved: resolved, client: client, cfg: cfg, dryRun: opts.dryRun, onDone: (result, error) => {
|
|
182
|
+
if (!error) {
|
|
183
|
+
appendUpload(cfg.cacheDir, {
|
|
184
|
+
publishedFileId: result.publishedFileId,
|
|
185
|
+
title: resolved.title,
|
|
186
|
+
itemType: resolved.itemType,
|
|
187
|
+
skinDir: resolved.skinDir,
|
|
188
|
+
uploadedAt: new Date().toISOString(),
|
|
189
|
+
url: result.url,
|
|
190
|
+
tags: resolved.tags,
|
|
191
|
+
description: resolved.description,
|
|
192
|
+
dryRun: opts.dryRun || undefined,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// Let the final frame render before tearing down
|
|
196
|
+
setTimeout(() => {
|
|
197
|
+
app.unmount();
|
|
198
|
+
client.shutdown();
|
|
199
|
+
resolveOuter();
|
|
200
|
+
process.exit(error ? 1 : 0);
|
|
201
|
+
}, 100);
|
|
202
|
+
} }));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
// Default cache dir lives in the user's home so it survives across project clones.
|
|
5
|
+
export const DEFAULT_CACHE_DIR = join(homedir(), ".riu", "cache");
|
|
6
|
+
export const RUST_APP_ID = 252490;
|
|
7
|
+
// Steam IDs are 17-digit numerics starting with 7656.
|
|
8
|
+
const steamId64 = z
|
|
9
|
+
.string()
|
|
10
|
+
.regex(/^7656\d{13}$/, "must be a 17-digit SteamID64 starting with 7656");
|
|
11
|
+
export const ConfigSchema = z.object({
|
|
12
|
+
steamSdkPath: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1, "steamSdkPath is required")
|
|
15
|
+
.describe("absolute path to the directory containing libsteam_api.dylib"),
|
|
16
|
+
steamAppId: z
|
|
17
|
+
.number()
|
|
18
|
+
.int()
|
|
19
|
+
.positive()
|
|
20
|
+
.default(RUST_APP_ID)
|
|
21
|
+
.describe("Steam AppID to upload as (default 252490 = Rust)"),
|
|
22
|
+
authorId: steamId64.describe("SteamID64 of the uploader"),
|
|
23
|
+
defaultTags: z
|
|
24
|
+
.array(z.string().min(1))
|
|
25
|
+
.default(["Version3", "Skin"])
|
|
26
|
+
.describe("default tags applied to every upload"),
|
|
27
|
+
defaultDescription: z
|
|
28
|
+
.string()
|
|
29
|
+
.default("")
|
|
30
|
+
.describe("default description applied to uploads when none is provided"),
|
|
31
|
+
cacheDir: z
|
|
32
|
+
.string()
|
|
33
|
+
.default(DEFAULT_CACHE_DIR)
|
|
34
|
+
.describe("where uploaded skins are recorded for `riu list`"),
|
|
35
|
+
});
|
|
36
|
+
// Partial input shape — what `riu init --json` accepts. Defaults filled in by ConfigSchema.parse().
|
|
37
|
+
export const ConfigInputSchema = ConfigSchema.partial({
|
|
38
|
+
steamAppId: true,
|
|
39
|
+
defaultTags: true,
|
|
40
|
+
defaultDescription: true,
|
|
41
|
+
cacheDir: true,
|
|
42
|
+
});
|
|
43
|
+
// Field metadata for the interactive wizard — keeps prompts and schema in sync.
|
|
44
|
+
export const FIELD_ORDER = [
|
|
45
|
+
{
|
|
46
|
+
key: "steamSdkPath",
|
|
47
|
+
label: "Steamworks SDK path",
|
|
48
|
+
hint: "absolute path to dir containing libsteam_api.dylib",
|
|
49
|
+
required: true,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "authorId",
|
|
53
|
+
label: "Author SteamID64",
|
|
54
|
+
hint: "17-digit numeric ID, e.g. 76561198000000000",
|
|
55
|
+
required: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "steamAppId",
|
|
59
|
+
label: "Steam App ID",
|
|
60
|
+
hint: `default ${RUST_APP_ID} (Rust)`,
|
|
61
|
+
required: false,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: "defaultTags",
|
|
65
|
+
label: "Default tags",
|
|
66
|
+
hint: "comma-separated, default: Version3,Skin",
|
|
67
|
+
required: false,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: "defaultDescription",
|
|
71
|
+
label: "Default description",
|
|
72
|
+
hint: "optional template applied when --description is omitted",
|
|
73
|
+
required: false,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,mFAAmF;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAElC,sDAAsD;AACtD,MAAM,SAAS,GAAG,CAAC;KAChB,MAAM,EAAE;KACR,KAAK,CAAC,cAAc,EAAE,iDAAiD,CAAC,CAAC;AAE5E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,0BAA0B,CAAC;SAClC,QAAQ,CAAC,8DAA8D,CAAC;IAC3E,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,WAAW,CAAC;SACpB,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IACzD,WAAW,EAAE,CAAC;SACX,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACxB,OAAO,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;SAC7B,QAAQ,CAAC,sCAAsC,CAAC;IACnD,kBAAkB,EAAE,CAAC;SAClB,MAAM,EAAE;SACR,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,8DAA8D,CAAC;IAC3E,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,OAAO,CAAC,iBAAiB,CAAC;SAC1B,QAAQ,CAAC,kDAAkD,CAAC;CAChE,CAAC,CAAC;AAIH,oGAAoG;AACpG,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,OAAO,CAAC;IACpD,UAAU,EAAE,IAAI;IAChB,WAAW,EAAE,IAAI;IACjB,kBAAkB,EAAE,IAAI;IACxB,QAAQ,EAAE,IAAI;CACf,CAAC,CAAC;AAGH,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAKnB;IACH;QACE,GAAG,EAAE,cAAc;QACnB,KAAK,EAAE,qBAAqB;QAC5B,IAAI,EAAE,oDAAoD;QAC1D,QAAQ,EAAE,IAAI;KACf;IACD;QACE,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,6CAA6C;QACnD,QAAQ,EAAE,IAAI;KACf;IACD;QACE,GAAG,EAAE,YAAY;QACjB,KAAK,EAAE,cAAc;QACrB,IAAI,EAAE,WAAW,WAAW,SAAS;QACrC,QAAQ,EAAE,KAAK;KAChB;IACD;QACE,GAAG,EAAE,aAAa;QAClB,KAAK,EAAE,cAAc;QACrB,IAAI,EAAE,yCAAyC;QAC/C,QAAQ,EAAE,KAAK;KAChB;IACD;QACE,GAAG,EAAE,oBAAoB;QACzB,KAAK,EAAE,qBAAqB;QAC5B,IAAI,EAAE,yDAAyD;QAC/D,QAAQ,EAAE,KAAK;KAChB;CACF,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import Conf from "conf";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { ConfigSchema, RUST_APP_ID, DEFAULT_CACHE_DIR, } from "./schema.js";
|
|
5
|
+
// Single shared conf instance — safe because Conf is just a thin wrapper around a JSON file.
|
|
6
|
+
// RIU_CONFIG_DIR env var overrides the storage location (used for tests + dry-run isolation).
|
|
7
|
+
const store = new Conf({
|
|
8
|
+
projectName: "rust-icon-uploader",
|
|
9
|
+
...(process.env.RIU_CONFIG_DIR ? { cwd: process.env.RIU_CONFIG_DIR } : {}),
|
|
10
|
+
// No JSON-schema validation here — we use Zod at the read/write boundary instead.
|
|
11
|
+
});
|
|
12
|
+
export const CONFIG_PATH = store.path;
|
|
13
|
+
export function hasConfig() {
|
|
14
|
+
// `conf` creates the file lazily on first write, so existence of the file == initialized.
|
|
15
|
+
return existsSync(store.path) && Object.keys(store.store).length > 0;
|
|
16
|
+
}
|
|
17
|
+
export function readConfig() {
|
|
18
|
+
if (!hasConfig())
|
|
19
|
+
return null;
|
|
20
|
+
const raw = store.store;
|
|
21
|
+
// Apply defaults via the schema; throws if required fields are missing.
|
|
22
|
+
return ConfigSchema.parse({
|
|
23
|
+
steamSdkPath: raw.steamSdkPath,
|
|
24
|
+
steamAppId: raw.steamAppId ?? RUST_APP_ID,
|
|
25
|
+
authorId: raw.authorId,
|
|
26
|
+
defaultTags: raw.defaultTags ?? ["Version3", "Skin"],
|
|
27
|
+
defaultDescription: raw.defaultDescription ?? "",
|
|
28
|
+
cacheDir: raw.cacheDir ?? DEFAULT_CACHE_DIR,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Pure: build a fully-merged Config from a partial input without touching disk.
|
|
32
|
+
// Used by dry-run + writeConfig.
|
|
33
|
+
export function buildConfig(input) {
|
|
34
|
+
return ConfigSchema.parse({
|
|
35
|
+
steamSdkPath: input.steamSdkPath,
|
|
36
|
+
steamAppId: input.steamAppId ?? RUST_APP_ID,
|
|
37
|
+
authorId: input.authorId,
|
|
38
|
+
defaultTags: input.defaultTags ?? ["Version3", "Skin"],
|
|
39
|
+
defaultDescription: input.defaultDescription ?? "",
|
|
40
|
+
cacheDir: input.cacheDir ?? DEFAULT_CACHE_DIR,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function writeConfig(input) {
|
|
44
|
+
const merged = buildConfig(input);
|
|
45
|
+
store.set(merged);
|
|
46
|
+
return merged;
|
|
47
|
+
}
|
|
48
|
+
export function clearConfig() {
|
|
49
|
+
store.clear();
|
|
50
|
+
}
|
|
51
|
+
// Probe whether the configured SDK path actually contains the macOS dylib.
|
|
52
|
+
// Used by `riu init` validation and `riu doctor`.
|
|
53
|
+
export function probeSteamSdk(sdkPath) {
|
|
54
|
+
if (!existsSync(sdkPath)) {
|
|
55
|
+
return { ok: false, reason: `path does not exist: ${sdkPath}` };
|
|
56
|
+
}
|
|
57
|
+
const stat = statSync(sdkPath);
|
|
58
|
+
if (!stat.isDirectory()) {
|
|
59
|
+
return { ok: false, reason: `path is not a directory: ${sdkPath}` };
|
|
60
|
+
}
|
|
61
|
+
const dylibPath = join(sdkPath, "libsteam_api.dylib");
|
|
62
|
+
if (!existsSync(dylibPath)) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
reason: `libsteam_api.dylib not found in ${sdkPath}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { ok: true, dylibPath };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/config/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Builds the JSON manifest that Rust's workshop ingester reads when it
|
|
2
|
+
// imports a community item. Format is "Version 3" — extracted from the
|
|
3
|
+
// existing "Rust Custom Icons" tool's example skin and confirmed against
|
|
4
|
+
// what real workshop uploads carry.
|
|
5
|
+
//
|
|
6
|
+
// The crucial detail for icon-only skins: the Textures dict is EMPTY.
|
|
7
|
+
// That tells Rust "don't apply any texture overrides," and the workshop
|
|
8
|
+
// item's preview image is what shows up as the inventory icon in-game.
|
|
9
|
+
import { isKnownItemType } from "./itemTypes.js";
|
|
10
|
+
// Default Floats and Colors copied verbatim from the reference manifest.
|
|
11
|
+
// These are the "neutral" Rust standard-shader values; they keep the original
|
|
12
|
+
// material lit normally so only the icon swap is visible.
|
|
13
|
+
const DEFAULT_FLOATS = {
|
|
14
|
+
_Cutoff: 0.0,
|
|
15
|
+
_BumpScale: 1.0,
|
|
16
|
+
_Glossiness: 0.0,
|
|
17
|
+
_OcclusionStrength: 1.0,
|
|
18
|
+
_MicrofiberFuzzIntensity: 1.0,
|
|
19
|
+
_MicrofiberFuzzScatter: 1.0,
|
|
20
|
+
_MicrofiberFuzzOcclusion: 1.0,
|
|
21
|
+
};
|
|
22
|
+
const DEFAULT_COLORS = {
|
|
23
|
+
_Color: { r: 1.0, g: 1.0, b: 1.0 },
|
|
24
|
+
_SpecColor: { r: 0.0, g: 0.0, b: 0.0 },
|
|
25
|
+
_EmissionColor: { r: 0.0, g: 0.0, b: 0.0 },
|
|
26
|
+
_MicrofiberFuzzColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
27
|
+
};
|
|
28
|
+
function coerceAuthorId(raw) {
|
|
29
|
+
if (typeof raw === "number") {
|
|
30
|
+
if (!Number.isFinite(raw) || raw <= 0) {
|
|
31
|
+
throw new Error(`authorId must be a positive number, got: ${raw}`);
|
|
32
|
+
}
|
|
33
|
+
return raw;
|
|
34
|
+
}
|
|
35
|
+
if (!/^7656\d{13}$/.test(raw)) {
|
|
36
|
+
throw new Error(`authorId must be a 17-digit SteamID64, got: ${raw}`);
|
|
37
|
+
}
|
|
38
|
+
// SteamID64s exceed Number.MAX_SAFE_INTEGER (9007199254740991), so converting
|
|
39
|
+
// to a JS number loses the lower digits. The reference manifest stores it as
|
|
40
|
+
// a JSON number, but we round-trip through a string to preserve precision in
|
|
41
|
+
// the serialized output. JSON.stringify on a number always loses precision,
|
|
42
|
+
// so we'll use a custom serializer in the writer.
|
|
43
|
+
return Number(raw);
|
|
44
|
+
}
|
|
45
|
+
export function buildManifest(input) {
|
|
46
|
+
const warnings = [];
|
|
47
|
+
if (!input.itemType || input.itemType.trim().length === 0) {
|
|
48
|
+
throw new Error("itemType is required");
|
|
49
|
+
}
|
|
50
|
+
if (!isKnownItemType(input.itemType)) {
|
|
51
|
+
if (!input.allowCustomItemType) {
|
|
52
|
+
throw new Error(`unknown itemType "${input.itemType}". Pass allowCustomItemType: true to override.`);
|
|
53
|
+
}
|
|
54
|
+
warnings.push(`itemType "${input.itemType}" is not in the known catalog`);
|
|
55
|
+
}
|
|
56
|
+
const authorId = coerceAuthorId(input.authorId);
|
|
57
|
+
const publishDate = (input.publishDate ?? new Date()).toISOString();
|
|
58
|
+
const manifest = {
|
|
59
|
+
Version: 3,
|
|
60
|
+
ItemType: input.itemType,
|
|
61
|
+
AuthorId: authorId,
|
|
62
|
+
PublishDate: publishDate,
|
|
63
|
+
Groups: [
|
|
64
|
+
{
|
|
65
|
+
Textures: {}, // empty = icon-only skin (this is the trick)
|
|
66
|
+
Floats: { ...DEFAULT_FLOATS },
|
|
67
|
+
Colors: structuredClone(DEFAULT_COLORS),
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
return { manifest, warnings };
|
|
72
|
+
}
|
|
73
|
+
// Custom serializer that preserves SteamID64 precision. JSON.stringify would
|
|
74
|
+
// reduce the number to a float. We sub a placeholder, stringify, then patch.
|
|
75
|
+
export function serializeManifest(manifest, originalAuthorId) {
|
|
76
|
+
const placeholder = "__AUTHOR_ID_PLACEHOLDER__";
|
|
77
|
+
const cloned = { ...manifest, AuthorId: placeholder };
|
|
78
|
+
const json = JSON.stringify(cloned, null, 2);
|
|
79
|
+
const idStr = typeof originalAuthorId === "string"
|
|
80
|
+
? originalAuthorId
|
|
81
|
+
: String(originalAuthorId ?? manifest.AuthorId);
|
|
82
|
+
return json.replace(`"${placeholder}"`, idStr);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/manifest/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Rust workshop ItemType catalog.
|
|
2
|
+
//
|
|
3
|
+
// This is the value Rust uses to figure out which inventory slot the workshop
|
|
4
|
+
// item's preview image should be assigned to. The Rust workshop has more
|
|
5
|
+
// categories than the ones below — this is the practical starting set, and
|
|
6
|
+
// users can pass any string via JSON if they need an ItemType not listed here
|
|
7
|
+
// (with `allowCustomItemType: true`).
|
|
8
|
+
//
|
|
9
|
+
// Source: extracted from inspecting Billy Joe's "Rust Custom Icons" tool +
|
|
10
|
+
// the Rust workshop wiki. The string MUST match Rust's category names exactly
|
|
11
|
+
// (case-sensitive) — the game uses string equality to look up the slot.
|
|
12
|
+
export const KNOWN_ITEM_TYPES = [
|
|
13
|
+
// Throwables (UAV signal, patrol signal, etc. all live here)
|
|
14
|
+
"Grenade",
|
|
15
|
+
// Melee
|
|
16
|
+
"Rock",
|
|
17
|
+
"Sword",
|
|
18
|
+
"Spear",
|
|
19
|
+
"Knife",
|
|
20
|
+
"Axe",
|
|
21
|
+
"Hammer",
|
|
22
|
+
// Firearms
|
|
23
|
+
"Pistol",
|
|
24
|
+
"Rifle",
|
|
25
|
+
"Shotgun",
|
|
26
|
+
"SMG",
|
|
27
|
+
"Bow",
|
|
28
|
+
// Tools / utilities
|
|
29
|
+
"Tool",
|
|
30
|
+
// Attire
|
|
31
|
+
"Hat",
|
|
32
|
+
"Shirt",
|
|
33
|
+
"Pants",
|
|
34
|
+
"Boots",
|
|
35
|
+
"Gloves",
|
|
36
|
+
// World / placed
|
|
37
|
+
"Container",
|
|
38
|
+
"SleepingBag",
|
|
39
|
+
"Furniture",
|
|
40
|
+
];
|
|
41
|
+
export function isKnownItemType(value) {
|
|
42
|
+
return KNOWN_ITEM_TYPES.includes(value);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=itemTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"itemTypes.js","sourceRoot":"","sources":["../../src/manifest/itemTypes.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,2EAA2E;AAC3E,8EAA8E;AAC9E,sCAAsC;AACtC,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,wEAAwE;AAExE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6DAA6D;IAC7D,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,KAAK;IACL,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,OAAO;IACP,SAAS;IACT,KAAK;IACL,KAAK;IACL,oBAAoB;IACpB,MAAM;IACN,SAAS;IACT,KAAK;IACL,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,iBAAiB;IACjB,WAAW;IACX,aAAa;IACb,WAAW;CACH,CAAC;AAIX,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAQ,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { serializeManifest } from "./builder.js";
|
|
4
|
+
export const MANIFEST_FILENAME = "manifest.txt";
|
|
5
|
+
export function manifestPath(skinDir) {
|
|
6
|
+
return join(skinDir, MANIFEST_FILENAME);
|
|
7
|
+
}
|
|
8
|
+
export function writeManifest(skinDir, manifest, opts = {}) {
|
|
9
|
+
mkdirSync(skinDir, { recursive: true });
|
|
10
|
+
const path = manifestPath(skinDir);
|
|
11
|
+
const json = serializeManifest(manifest, opts.originalAuthorId);
|
|
12
|
+
writeFileSync(path, json + "\n", "utf8");
|
|
13
|
+
return path;
|
|
14
|
+
}
|
|
15
|
+
export function readManifest(skinDir) {
|
|
16
|
+
const path = manifestPath(skinDir);
|
|
17
|
+
if (!existsSync(path))
|
|
18
|
+
return null;
|
|
19
|
+
const raw = readFileSync(path, "utf8");
|
|
20
|
+
// The author ID may exceed Number.MAX_SAFE_INTEGER. JSON.parse will lose
|
|
21
|
+
// precision, but for the read path we only consume metadata, not the ID
|
|
22
|
+
// for upload. The upload path always sources the ID from config, not the
|
|
23
|
+
// manifest, so this lossiness is safe.
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
// Used by bulk upload to record the result back into the source manifest
|
|
27
|
+
// so a re-run can skip already-uploaded folders. Preserves SteamID64
|
|
28
|
+
// precision by patching the JSON via the same placeholder dance the
|
|
29
|
+
// initial write uses.
|
|
30
|
+
export function setManifestPublishedFileId(skinDir, publishedFileId, originalAuthorId) {
|
|
31
|
+
const existing = readManifest(skinDir);
|
|
32
|
+
if (!existing)
|
|
33
|
+
throw new Error(`no manifest at ${manifestPath(skinDir)}`);
|
|
34
|
+
existing.PublishedFileId = publishedFileId;
|
|
35
|
+
const json = serializeManifest(existing, originalAuthorId);
|
|
36
|
+
writeFileSync(manifestPath(skinDir), json + "\n", "utf8");
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/manifest/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAqB,MAAM,cAAc,CAAC;AAIpE,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAOhD,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,QAAsB,EACtB,OAA6B,EAAE;IAE/B,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAChE,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,uCAAuC;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,qEAAqE;AACrE,oEAAoE;AACpE,sBAAsB;AACtB,MAAM,UAAU,0BAA0B,CACxC,OAAe,EACf,eAAuB,EACvB,gBAAiC;IAEjC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1E,QAAQ,CAAC,eAAe,GAAG,eAAe,CAAC;IAC3C,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAC3D,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Manages the riu-owned dylib install at ~/.riu/sdk/libsteam_api.dylib.
|
|
2
|
+
//
|
|
3
|
+
// We always normalize the destination filename to libsteam_api.dylib so
|
|
4
|
+
// steamworks-ffi-node's loader finds it regardless of the original
|
|
5
|
+
// extension (.bundle, .dylib).
|
|
6
|
+
import { copyFileSync, existsSync, mkdirSync, statSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
export const SDK_INSTALL_DIR = join(homedir(), ".riu", "sdk");
|
|
10
|
+
export const SDK_DYLIB_FILENAME = "libsteam_api.dylib";
|
|
11
|
+
export const SDK_DYLIB_PATH = join(SDK_INSTALL_DIR, SDK_DYLIB_FILENAME);
|
|
12
|
+
export function getManagedSdkDir() {
|
|
13
|
+
return SDK_INSTALL_DIR;
|
|
14
|
+
}
|
|
15
|
+
export function isSdkInstalled() {
|
|
16
|
+
try {
|
|
17
|
+
return statSync(SDK_DYLIB_PATH).isFile();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function installFromPath(srcPath, sourceLabel = "manual") {
|
|
24
|
+
if (!existsSync(srcPath)) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
installedPath: SDK_DYLIB_PATH,
|
|
28
|
+
error: `source not found: ${srcPath}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let bytes = 0;
|
|
32
|
+
try {
|
|
33
|
+
bytes = statSync(srcPath).size;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore — copy will fail with a clear error below
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
mkdirSync(dirname(SDK_DYLIB_PATH), { recursive: true });
|
|
40
|
+
copyFileSync(srcPath, SDK_DYLIB_PATH);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
installedPath: SDK_DYLIB_PATH,
|
|
46
|
+
error: e instanceof Error ? e.message : String(e),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
ok: true,
|
|
51
|
+
installedPath: SDK_DYLIB_PATH,
|
|
52
|
+
source: sourceLabel,
|
|
53
|
+
bytesCopied: bytes,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function installFromSource(source) {
|
|
57
|
+
return installFromPath(source.path, source.game);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/sdk/installer.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,+BAA+B;AAE/B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AACvD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAC;AAExE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,cAAc,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAUD,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,WAAW,GAAG,QAAQ;IACrE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,aAAa,EAAE,cAAc;YAC7B,KAAK,EAAE,qBAAqB,OAAO,EAAE;SACtC,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;IACrD,CAAC;IACD,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,KAAK;YACT,aAAa,EAAE,cAAc;YAC7B,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SAClD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,aAAa,EAAE,cAAc;QAC7B,MAAM,EAAE,WAAW;QACnB,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC"}
|