@roster-lock/config-editor-cli 0.0.1 → 0.1.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.
@@ -20,5 +20,6 @@ __exportStar(require("./edit-definition"), exports);
20
20
  __exportStar(require("./add-asset"), exports);
21
21
  __exportStar(require("./remove-piece-type"), exports);
22
22
  __exportStar(require("./remove-asset"), exports);
23
+ __exportStar(require("./official-selection"), exports);
23
24
  __exportStar(require("./show"), exports);
24
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/engine/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,mDAAiC;AACjC,oDAAkC;AAClC,8CAA4B;AAC5B,sDAAoC;AACpC,iDAA+B;AAC/B,yCAAuB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/engine/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,mDAAiC;AACjC,oDAAkC;AAClC,8CAA4B;AAC5B,sDAAoC;AACpC,iDAA+B;AAC/B,uDAAqC;AACrC,yCAAuB"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addOfficialSelectionCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const shared_1 = require("@roster-lock/shared");
6
+ const utils_1 = require("@roster-lock/utils");
7
+ const draft_io_1 = require("../../lib/draft-io");
8
+ const cli_options_1 = require("../../lib/cli-options");
9
+ const errors_1 = require("../../lib/errors");
10
+ exports.addOfficialSelectionCommand = (0, cli_options_1.withDraftOption)(new commander_1.Command("add-official-selection"))
11
+ .description("Register a selection config hash under a tag the engine's own UI can recognise")
12
+ .argument("<tag>", "the tag the engine matches to one of its selection screens, e.g. \"single\" or \"3v3-tag\"")
13
+ .option("--hash <sha256>", "the selection config's hash (from \"selection hash\"); defaults to hashing the draft's current selection")
14
+ .action((0, errors_1.withErrorHandling)(async (tag, opts) => {
15
+ const draftPath = (0, draft_io_1.resolveDraftPath)(opts.draft);
16
+ const draft = (0, draft_io_1.readDraft)(draftPath);
17
+ const hash = opts.hash ?? await (0, utils_1.createShaFromJSON)(draft.stagedLock.selection);
18
+ const list = draft.stagedLock.engine.officialSelections ??= [];
19
+ const existing = list.find((entry) => entry.hash === hash);
20
+ if (existing) {
21
+ if (existing.tag === tag) {
22
+ console.log(`Already registered: ${tag} ${hash}`);
23
+ return;
24
+ }
25
+ throw new Error(`Hash ${hash} is already registered under tag "${existing.tag}"; ` +
26
+ "a selection config can only carry one tag");
27
+ }
28
+ list.push({ tag, hash });
29
+ shared_1.ROSTERLOCK_V1_CASTER_JSONSCHEMA.cast(draft.stagedLock);
30
+ (0, draft_io_1.writeDraft)(draftPath, draft);
31
+ console.log(`Registered official selection: ${tag} ${hash}`);
32
+ }));
33
+ //# sourceMappingURL=official-selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"official-selection.js","sourceRoot":"","sources":["../../../src/commands/engine/official-selection.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,gDAAsE;AACtE,8CAAuD;AACvD,iDAA6E;AAC7E,uDAAwD;AACxD,6CAAqD;AAExC,QAAA,2BAA2B,GAAG,IAAA,6BAAe,EAAC,IAAI,mBAAO,CAAC,wBAAwB,CAAC,CAAC;KAC9F,WAAW,CAAC,gFAAgF,CAAC;KAC7F,QAAQ,CAAC,OAAO,EAAE,4FAA4F,CAAC;KAC/G,MAAM,CACL,iBAAiB,EACjB,0GAA0G,CAC3G;KACA,MAAM,CAAC,IAAA,0BAAiB,EAAC,KAAK,EAAE,GAAW,EAAE,IAAuC,EAAE,EAAE;IACvF,MAAM,SAAS,GAAG,IAAA,2BAAgB,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAA,oBAAS,EAAC,SAAS,CAAC,CAAC;IAKnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,IAAA,yBAAiB,EAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAE9E,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,kBAAkB,KAAK,EAAE,CAAC;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC3D,IAAG,QAAQ,EAAC,CAAC;QACX,IAAG,QAAQ,CAAC,GAAG,KAAK,GAAG,EAAC,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,KAAK,CACb,QAAQ,IAAI,qCAAqC,QAAQ,CAAC,GAAG,KAAK;YAClE,2CAA2C,CAC5C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACzB,wCAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEvD,IAAA,qBAAU,EAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,kCAAkC,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC,CAAC"}
@@ -10,6 +10,7 @@ const parse_1 = require("../../lib/parse");
10
10
  const json_input_1 = require("../../lib/json-input");
11
11
  const schemas_1 = require("../../lib/schemas");
12
12
  const schema_help_1 = require("../../lib/schema-help");
13
+ const image_1 = require("../../lib/image");
13
14
  function collect(value, previous) {
14
15
  previous.push(value);
15
16
  return previous;
@@ -21,7 +22,7 @@ exports.editPieceCommand = (0, cli_options_1.withDraftOption)(new commander_1.Co
21
22
  .option("--name <name>", "human-readable name")
22
23
  .option("--author <author>", "author name")
23
24
  .option("--url <url>", "info url")
24
- .option("--image <url>", "image url")
25
+ .option("--image <path>", "path to a local image file (png/jpg/gif/webp/svg) to embed, or \"-\" to remove it")
25
26
  .option("--add-download-source <url>", "download source url to add (repeatable)", collect, [])
26
27
  .option("--remove-download-source <url>", "download source url to remove (repeatable)", collect, [])
27
28
  .option("--path-variables <k=v,...>", "path variable values to set (existing keys not mentioned are left alone)")
@@ -64,8 +65,12 @@ exports.editPieceCommand = (0, cli_options_1.withDraftOption)(new commander_1.Co
64
65
  piece.humanInfo.author = opts.author;
65
66
  if (opts.url !== undefined)
66
67
  piece.humanInfo.url = opts.url;
67
- if (opts.image !== undefined)
68
- piece.humanInfo.image = opts.image;
68
+ if (opts.image !== undefined) {
69
+ if (opts.image === "-")
70
+ delete piece.humanInfo.image;
71
+ else
72
+ piece.humanInfo.image = (0, image_1.encodeImageFile)(opts.image);
73
+ }
69
74
  for (const source of opts.addDownloadSource) {
70
75
  if (!piece.downloadSources.includes(source))
71
76
  piece.downloadSources.push(source);
@@ -1 +1 @@
1
- {"version":3,"file":"edit-piece.js","sourceRoot":"","sources":["../../../src/commands/roster/edit-piece.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"edit-piece.js","sourceRoot":"","sources":["../../../src/commands/roster/edit-piece.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectionHashCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const utils_1 = require("@roster-lock/utils");
6
+ const draft_io_1 = require("../../lib/draft-io");
7
+ const cli_options_1 = require("../../lib/cli-options");
8
+ const errors_1 = require("../../lib/errors");
9
+ exports.selectionHashCommand = (0, cli_options_1.withDraftOption)(new commander_1.Command("hash"))
10
+ .description("Print the sha256 of the staged lock's selection config (its officialSelections identity)")
11
+ .action((0, errors_1.withErrorHandling)(async (opts) => {
12
+ const draftPath = (0, draft_io_1.resolveDraftPath)(opts.draft);
13
+ const draft = (0, draft_io_1.readDraft)(draftPath);
14
+ console.log(await (0, utils_1.createShaFromJSON)(draft.stagedLock.selection));
15
+ }));
16
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/commands/selection/hash.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,8CAAuD;AACvD,iDAAiE;AACjE,uDAAwD;AACxD,6CAAqD;AAMxC,QAAA,oBAAoB,GAAG,IAAA,6BAAe,EAAC,IAAI,mBAAO,CAAC,MAAM,CAAC,CAAC;KACrE,WAAW,CAAC,0FAA0F,CAAC;KACvG,MAAM,CAAC,IAAA,0BAAiB,EAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;IAC3D,MAAM,SAAS,GAAG,IAAA,2BAAgB,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAA,oBAAS,EAAC,SAAS,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAA,yBAAiB,EAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC,CAAC"}
@@ -17,5 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./add-script"), exports);
18
18
  __exportStar(require("./set"), exports);
19
19
  __exportStar(require("./run-script"), exports);
20
+ __exportStar(require("./hash"), exports);
20
21
  __exportStar(require("./show"), exports);
21
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/selection/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,wCAAsB;AACtB,+CAA6B;AAC7B,yCAAuB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/selection/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,wCAAsB;AACtB,+CAA6B;AAC7B,yCAAuB;AACvB,yCAAuB"}
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ engineCommand.addCommand(engine_1.editDefinitionCommand);
30
30
  engineCommand.addCommand(engine_1.addAssetCommand);
31
31
  engineCommand.addCommand(engine_1.removePieceTypeCommand);
32
32
  engineCommand.addCommand(engine_1.removeAssetCommand);
33
+ engineCommand.addCommand(engine_1.addOfficialSelectionCommand);
33
34
  engineCommand.addCommand(engine_1.engineShowCommand);
34
35
  commander_1.program.addCommand(engineCommand);
35
36
  const rosterCommand = new commander_1.Command("roster").description("Edit the staged lock's rosters (pieces)");
@@ -45,6 +46,7 @@ const selectionCommand = new commander_1.Command("selection").description("Edit
45
46
  selectionCommand.addCommand(selection_1.addScriptCommand);
46
47
  selectionCommand.addCommand(selection_1.selectionSetCommand);
47
48
  selectionCommand.addCommand(selection_1.runScriptCommand);
49
+ selectionCommand.addCommand(selection_1.selectionHashCommand);
48
50
  selectionCommand.addCommand(selection_1.selectionShowCommand);
49
51
  commander_1.program.addCommand(selectionCommand);
50
52
  const pieceMetaCommand = new commander_1.Command("piece-meta").description("Edit the staged lock's piece meta (custom per-piece fields)");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeImageFile = encodeImageFile;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const shared_1 = require("@roster-lock/shared");
7
+ const MIME_BY_EXTENSION = {
8
+ ".png": "image/png",
9
+ ".jpg": "image/jpeg",
10
+ ".jpeg": "image/jpeg",
11
+ ".gif": "image/gif",
12
+ ".webp": "image/webp",
13
+ ".svg": "image/svg+xml",
14
+ };
15
+ function encodeImageFile(path) {
16
+ const mimeType = MIME_BY_EXTENSION[(0, node_path_1.extname)(path).toLowerCase()];
17
+ if (!mimeType) {
18
+ throw new Error(`Unsupported image extension "${(0, node_path_1.extname)(path)}"; expected one of ${Object.keys(MIME_BY_EXTENSION).join(", ")}`);
19
+ }
20
+ const dataURI = `data:${mimeType};base64,${(0, node_fs_1.readFileSync)(path).toString("base64")}`;
21
+ (0, shared_1.validateImageDataURI)(dataURI);
22
+ return dataURI;
23
+ }
24
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/lib/image.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AACvC,yCAAoC;AACpC,gDAA2D;AAE3D,MAAM,iBAAiB,GAA2B;IAChD,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;CACxB,CAAC;AAKF,yBAAgC,IAAY;IAC1C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAA,mBAAO,EAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAChE,IAAG,CAAC,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAA,mBAAO,EAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClI,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,QAAQ,WAAW,IAAA,sBAAY,EAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnF,IAAA,6BAAoB,EAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = "0.0.1";
4
+ exports.VERSION = "0.1.0";
5
5
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roster-lock/config-editor-cli",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "A cli tool to build roster lock configs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,10 +21,10 @@
21
21
  "ajv": "^8.17.1",
22
22
  "commander": "^14.0.3",
23
23
  "zod": "^4.4.3",
24
- "@roster-lock/plugin-runtime": "0.1.0",
25
- "@roster-lock/shared": "0.1.0",
26
- "@roster-lock/types": "1.0.0",
27
- "@roster-lock/utils": "1.0.0"
24
+ "@roster-lock/shared": "0.2.0",
25
+ "@roster-lock/types": "1.1.0",
26
+ "@roster-lock/utils": "1.0.0",
27
+ "@roster-lock/plugin-runtime": "0.2.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.14.1",
@@ -4,4 +4,5 @@ export * from "./edit-definition";
4
4
  export * from "./add-asset";
5
5
  export * from "./remove-piece-type";
6
6
  export * from "./remove-asset";
7
+ export * from "./official-selection";
7
8
  export * from "./show";
@@ -0,0 +1,42 @@
1
+ import { Command } from "commander";
2
+ import { ROSTERLOCK_V1_CASTER_JSONSCHEMA } from "@roster-lock/shared";
3
+ import { createShaFromJSON } from "@roster-lock/utils";
4
+ import { resolveDraftPath, readDraft, writeDraft } from "../../lib/draft-io";
5
+ import { withDraftOption } from "../../lib/cli-options";
6
+ import { withErrorHandling } from "../../lib/errors";
7
+
8
+ export const addOfficialSelectionCommand = withDraftOption(new Command("add-official-selection"))
9
+ .description("Register a selection config hash under a tag the engine's own UI can recognise")
10
+ .argument("<tag>", "the tag the engine matches to one of its selection screens, e.g. \"single\" or \"3v3-tag\"")
11
+ .option(
12
+ "--hash <sha256>",
13
+ "the selection config's hash (from \"selection hash\"); defaults to hashing the draft's current selection"
14
+ )
15
+ .action(withErrorHandling(async (tag: string, opts: { draft?: string, hash?: string }) => {
16
+ const draftPath = resolveDraftPath(opts.draft);
17
+ const draft = readDraft(draftPath);
18
+
19
+ // Registering by explicit --hash is the normal case for an engine offering
20
+ // several selection configs: each one lives in its own published lock, so
21
+ // every lock has to list all of the hashes, not just the one it carries.
22
+ const hash = opts.hash ?? await createShaFromJSON(draft.stagedLock.selection);
23
+
24
+ const list = draft.stagedLock.engine.officialSelections ??= [];
25
+ const existing = list.find((entry) => entry.hash === hash);
26
+ if(existing){
27
+ if(existing.tag === tag){
28
+ console.log(`Already registered: ${tag} ${hash}`);
29
+ return;
30
+ }
31
+ throw new Error(
32
+ `Hash ${hash} is already registered under tag "${existing.tag}"; ` +
33
+ "a selection config can only carry one tag"
34
+ );
35
+ }
36
+
37
+ list.push({ tag, hash });
38
+ ROSTERLOCK_V1_CASTER_JSONSCHEMA.cast(draft.stagedLock);
39
+
40
+ writeDraft(draftPath, draft);
41
+ console.log(`Registered official selection: ${tag} ${hash}`);
42
+ }));
@@ -7,6 +7,7 @@ import { parseKeyValueList } from "../../lib/parse";
7
7
  import { readJsonInput } from "../../lib/json-input";
8
8
  import { pieceOverridesSchema } from "../../lib/schemas";
9
9
  import { describeSchemaShape } from "../../lib/schema-help";
10
+ import { encodeImageFile } from "../../lib/image";
10
11
 
11
12
  function collect(value: string, previous: Array<string>){
12
13
  previous.push(value);
@@ -20,7 +21,7 @@ export const editPieceCommand = withDraftOption(new Command("edit-piece"))
20
21
  .option("--name <name>", "human-readable name")
21
22
  .option("--author <author>", "author name")
22
23
  .option("--url <url>", "info url")
23
- .option("--image <url>", "image url")
24
+ .option("--image <path>", "path to a local image file (png/jpg/gif/webp/svg) to embed, or \"-\" to remove it")
24
25
  .option("--add-download-source <url>", "download source url to add (repeatable)", collect, [] as Array<string>)
25
26
  .option("--remove-download-source <url>", "download source url to remove (repeatable)", collect, [] as Array<string>)
26
27
  .option("--path-variables <k=v,...>", "path variable values to set (existing keys not mentioned are left alone)")
@@ -72,7 +73,10 @@ export const editPieceCommand = withDraftOption(new Command("edit-piece"))
72
73
  if(opts.name !== undefined) piece.humanInfo.name = opts.name;
73
74
  if(opts.author !== undefined) piece.humanInfo.author = opts.author;
74
75
  if(opts.url !== undefined) piece.humanInfo.url = opts.url;
75
- if(opts.image !== undefined) piece.humanInfo.image = opts.image;
76
+ if(opts.image !== undefined){
77
+ if(opts.image === "-") delete piece.humanInfo.image;
78
+ else piece.humanInfo.image = encodeImageFile(opts.image);
79
+ }
76
80
 
77
81
  for(const source of opts.addDownloadSource){
78
82
  if(!piece.downloadSources.includes(source)) piece.downloadSources.push(source);
@@ -0,0 +1,17 @@
1
+ import { Command } from "commander";
2
+ import { createShaFromJSON } from "@roster-lock/utils";
3
+ import { resolveDraftPath, readDraft } from "../../lib/draft-io";
4
+ import { withDraftOption } from "../../lib/cli-options";
5
+ import { withErrorHandling } from "../../lib/errors";
6
+
7
+ // The identity of a selection config, as referenced by
8
+ // engine.officialSelections. Hashed over the canonical form of the selection
9
+ // subtree alone, so it doesn't move when the roster or engine around it does -
10
+ // two locks that differ only in their pieces still share a selection hash.
11
+ export const selectionHashCommand = withDraftOption(new Command("hash"))
12
+ .description("Print the sha256 of the staged lock's selection config (its officialSelections identity)")
13
+ .action(withErrorHandling(async (opts: { draft?: string }) => {
14
+ const draftPath = resolveDraftPath(opts.draft);
15
+ const draft = readDraft(draftPath);
16
+ console.log(await createShaFromJSON(draft.stagedLock.selection));
17
+ }));
@@ -1,4 +1,5 @@
1
1
  export * from "./add-script";
2
2
  export * from "./set";
3
3
  export * from "./run-script";
4
+ export * from "./hash";
4
5
  export * from "./show";
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  addAssetCommand,
10
10
  removePieceTypeCommand,
11
11
  removeAssetCommand,
12
+ addOfficialSelectionCommand,
12
13
  engineShowCommand,
13
14
  } from "./commands/engine";
14
15
  import {
@@ -24,6 +25,7 @@ import {
24
25
  addScriptCommand,
25
26
  selectionSetCommand,
26
27
  runScriptCommand,
28
+ selectionHashCommand,
27
29
  selectionShowCommand,
28
30
  } from "./commands/selection";
29
31
  import {
@@ -57,6 +59,7 @@ engineCommand.addCommand(editDefinitionCommand);
57
59
  engineCommand.addCommand(addAssetCommand);
58
60
  engineCommand.addCommand(removePieceTypeCommand);
59
61
  engineCommand.addCommand(removeAssetCommand);
62
+ engineCommand.addCommand(addOfficialSelectionCommand);
60
63
  engineCommand.addCommand(engineShowCommand);
61
64
  program.addCommand(engineCommand);
62
65
 
@@ -74,6 +77,7 @@ const selectionCommand = new Command("selection").description("Edit the staged l
74
77
  selectionCommand.addCommand(addScriptCommand);
75
78
  selectionCommand.addCommand(selectionSetCommand);
76
79
  selectionCommand.addCommand(runScriptCommand);
80
+ selectionCommand.addCommand(selectionHashCommand);
77
81
  selectionCommand.addCommand(selectionShowCommand);
78
82
  program.addCommand(selectionCommand);
79
83
 
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { extname } from "node:path";
3
+ import { validateImageDataURI } from "@roster-lock/shared";
4
+
5
+ const MIME_BY_EXTENSION: Record<string, string> = {
6
+ ".png": "image/png",
7
+ ".jpg": "image/jpeg",
8
+ ".jpeg": "image/jpeg",
9
+ ".gif": "image/gif",
10
+ ".webp": "image/webp",
11
+ ".svg": "image/svg+xml",
12
+ };
13
+
14
+ // Reads a local image file and embeds it as a "data:image/<type>;base64,..." URI -
15
+ // roster-lock files embed piece images rather than linking them, so they're available
16
+ // at selection time without depending on an external host being reachable.
17
+ export function encodeImageFile(path: string): string {
18
+ const mimeType = MIME_BY_EXTENSION[extname(path).toLowerCase()];
19
+ if(!mimeType) {
20
+ throw new Error(`Unsupported image extension "${extname(path)}"; expected one of ${Object.keys(MIME_BY_EXTENSION).join(", ")}`);
21
+ }
22
+
23
+ const dataURI = `data:${mimeType};base64,${readFileSync(path).toString("base64")}`;
24
+ validateImageDataURI(dataURI);
25
+ return dataURI;
26
+ }