fvtt-world-cli 1.1.2 → 1.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/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { readFileSync as readFileSync2 } from "node:fs";
|
|
|
10
10
|
import { createHash as createHash2, randomBytes as randomBytes2, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
11
11
|
|
|
12
12
|
// ../protocol/src/constants.js
|
|
13
|
-
var PROTOCOL_VERSION = "1.
|
|
13
|
+
var PROTOCOL_VERSION = "1.2.0";
|
|
14
14
|
var PROTOCOL_COMPONENTS = Object.freeze({
|
|
15
15
|
MODULE: "module",
|
|
16
16
|
CLI_DAEMON: "cli-daemon",
|
|
@@ -174,6 +174,7 @@ var ERROR_CODES = Object.freeze({
|
|
|
174
174
|
TILE_NOT_FOUND: "TILE_NOT_FOUND",
|
|
175
175
|
SOUND_NOT_FOUND: "SOUND_NOT_FOUND",
|
|
176
176
|
WALL_NOT_FOUND: "WALL_NOT_FOUND",
|
|
177
|
+
LEVEL_NOT_FOUND: "LEVEL_NOT_FOUND",
|
|
177
178
|
NOTE_NOT_FOUND: "NOTE_NOT_FOUND",
|
|
178
179
|
DRAWING_NOT_FOUND: "DRAWING_NOT_FOUND",
|
|
179
180
|
LIGHT_NOT_FOUND: "LIGHT_NOT_FOUND",
|
|
@@ -299,7 +300,7 @@ var includeProperty = {
|
|
|
299
300
|
var actorIncludeProperty = {
|
|
300
301
|
include: {
|
|
301
302
|
type: "array",
|
|
302
|
-
items: { type: "string", enum: ["flags", "effects", "items.flags", "items.effects", "prepared"] }
|
|
303
|
+
items: { type: "string", enum: ["flags", "effects", "items", "items.flags", "items.effects", "prepared"] }
|
|
303
304
|
}
|
|
304
305
|
};
|
|
305
306
|
var batchIdsProperty = {
|
|
@@ -3153,6 +3154,68 @@ var executableBehaviorPatchSchema = {
|
|
|
3153
3154
|
additionalProperties: true,
|
|
3154
3155
|
minProperties: 1
|
|
3155
3156
|
};
|
|
3157
|
+
var nullableNumberSchema = { type: ["number", "null"] };
|
|
3158
|
+
var levelImageProperties = {
|
|
3159
|
+
src: nullableStringSchema,
|
|
3160
|
+
tint: { type: "string", minLength: 1 },
|
|
3161
|
+
alphaThreshold: { type: "number" }
|
|
3162
|
+
};
|
|
3163
|
+
var levelCreateSchema = {
|
|
3164
|
+
type: "object",
|
|
3165
|
+
required: ["name"],
|
|
3166
|
+
properties: {
|
|
3167
|
+
name: { type: "string", minLength: 1 },
|
|
3168
|
+
elevation: {
|
|
3169
|
+
type: "object",
|
|
3170
|
+
required: [],
|
|
3171
|
+
properties: { bottom: nullableNumberSchema, top: nullableNumberSchema },
|
|
3172
|
+
additionalProperties: false
|
|
3173
|
+
},
|
|
3174
|
+
background: {
|
|
3175
|
+
type: "object",
|
|
3176
|
+
required: [],
|
|
3177
|
+
properties: { color: { type: "string", minLength: 1 }, ...levelImageProperties },
|
|
3178
|
+
additionalProperties: false
|
|
3179
|
+
},
|
|
3180
|
+
foreground: {
|
|
3181
|
+
type: "object",
|
|
3182
|
+
required: [],
|
|
3183
|
+
properties: levelImageProperties,
|
|
3184
|
+
additionalProperties: false
|
|
3185
|
+
},
|
|
3186
|
+
fog: {
|
|
3187
|
+
type: "object",
|
|
3188
|
+
required: [],
|
|
3189
|
+
properties: { src: nullableStringSchema },
|
|
3190
|
+
additionalProperties: false
|
|
3191
|
+
},
|
|
3192
|
+
textures: {
|
|
3193
|
+
type: "object",
|
|
3194
|
+
required: [],
|
|
3195
|
+
properties: {
|
|
3196
|
+
anchorX: { type: "number" },
|
|
3197
|
+
anchorY: { type: "number" },
|
|
3198
|
+
offsetX: { type: "integer" },
|
|
3199
|
+
offsetY: { type: "integer" },
|
|
3200
|
+
fit: { type: "string", minLength: 1 },
|
|
3201
|
+
scaleX: { type: "number" },
|
|
3202
|
+
scaleY: { type: "number" },
|
|
3203
|
+
rotation: { type: "number" }
|
|
3204
|
+
},
|
|
3205
|
+
additionalProperties: false
|
|
3206
|
+
},
|
|
3207
|
+
visibility: {
|
|
3208
|
+
type: "object",
|
|
3209
|
+
required: [],
|
|
3210
|
+
properties: { levels: { type: "array", items: { type: "string", minLength: 1 } } },
|
|
3211
|
+
additionalProperties: false
|
|
3212
|
+
},
|
|
3213
|
+
sort: { type: "integer" },
|
|
3214
|
+
flags: freeformObjectSchema
|
|
3215
|
+
},
|
|
3216
|
+
additionalProperties: false
|
|
3217
|
+
};
|
|
3218
|
+
var levelPatchSchema = patchFrom(levelCreateSchema);
|
|
3156
3219
|
var sceneEmbeddedCommands = {
|
|
3157
3220
|
"scene.token.list": cmd({
|
|
3158
3221
|
type: "object",
|
|
@@ -3744,6 +3807,85 @@ var sceneEmbeddedCommands = {
|
|
|
3744
3807
|
createSchema: wallCreateSchema,
|
|
3745
3808
|
patchSchema: wallPatchSchema
|
|
3746
3809
|
}),
|
|
3810
|
+
"scene.level.list": cmd({
|
|
3811
|
+
type: "object",
|
|
3812
|
+
required: ["sceneId"],
|
|
3813
|
+
properties: {
|
|
3814
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3815
|
+
...paginationProperties
|
|
3816
|
+
},
|
|
3817
|
+
additionalProperties: false
|
|
3818
|
+
}),
|
|
3819
|
+
"scene.level.get": cmd({
|
|
3820
|
+
type: "object",
|
|
3821
|
+
required: ["sceneId", "levelId"],
|
|
3822
|
+
properties: {
|
|
3823
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3824
|
+
levelId: { type: "string", minLength: 1 }
|
|
3825
|
+
},
|
|
3826
|
+
additionalProperties: false
|
|
3827
|
+
}),
|
|
3828
|
+
"scene.level.create": cmd(
|
|
3829
|
+
{
|
|
3830
|
+
type: "object",
|
|
3831
|
+
required: ["sceneId", "data"],
|
|
3832
|
+
properties: {
|
|
3833
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3834
|
+
data: levelCreateSchema,
|
|
3835
|
+
...dryRunProperty,
|
|
3836
|
+
...idempotencyKeyProperty
|
|
3837
|
+
},
|
|
3838
|
+
additionalProperties: false
|
|
3839
|
+
},
|
|
3840
|
+
{ mutation: true }
|
|
3841
|
+
),
|
|
3842
|
+
"scene.level.update": cmd(
|
|
3843
|
+
{
|
|
3844
|
+
type: "object",
|
|
3845
|
+
required: ["sceneId", "levelId", "patch"],
|
|
3846
|
+
properties: {
|
|
3847
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3848
|
+
levelId: { type: "string", minLength: 1 },
|
|
3849
|
+
patch: levelPatchSchema,
|
|
3850
|
+
...dryRunProperty
|
|
3851
|
+
},
|
|
3852
|
+
additionalProperties: false
|
|
3853
|
+
},
|
|
3854
|
+
{ mutation: true }
|
|
3855
|
+
),
|
|
3856
|
+
"scene.level.delete": cmd(
|
|
3857
|
+
{
|
|
3858
|
+
type: "object",
|
|
3859
|
+
required: ["sceneId", "levelId"],
|
|
3860
|
+
properties: {
|
|
3861
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3862
|
+
levelId: { type: "string", minLength: 1 },
|
|
3863
|
+
...dryRunProperty
|
|
3864
|
+
},
|
|
3865
|
+
additionalProperties: false
|
|
3866
|
+
},
|
|
3867
|
+
{ mutation: true }
|
|
3868
|
+
),
|
|
3869
|
+
"scene.level.clone": cmd(
|
|
3870
|
+
{
|
|
3871
|
+
type: "object",
|
|
3872
|
+
required: ["sceneId", "levelId"],
|
|
3873
|
+
properties: {
|
|
3874
|
+
sceneId: { type: "string", minLength: 1 },
|
|
3875
|
+
levelId: { type: "string", minLength: 1 },
|
|
3876
|
+
patch: levelPatchSchema,
|
|
3877
|
+
...dryRunProperty,
|
|
3878
|
+
...idempotencyKeyProperty
|
|
3879
|
+
},
|
|
3880
|
+
additionalProperties: false
|
|
3881
|
+
},
|
|
3882
|
+
{ mutation: true }
|
|
3883
|
+
),
|
|
3884
|
+
...batchWriteCommands("scene.level", {
|
|
3885
|
+
scopeProperties: sceneScopeProperties,
|
|
3886
|
+
createSchema: levelCreateSchema,
|
|
3887
|
+
patchSchema: levelPatchSchema
|
|
3888
|
+
}),
|
|
3747
3889
|
"scene.note.list": cmd({
|
|
3748
3890
|
type: "object",
|
|
3749
3891
|
required: ["sceneId"],
|
|
@@ -4288,6 +4430,10 @@ var sceneBackgroundSchema = {
|
|
|
4288
4430
|
scaleX: { type: "number" },
|
|
4289
4431
|
scaleY: { type: "number" },
|
|
4290
4432
|
rotation: { type: "number" },
|
|
4433
|
+
anchorX: { type: "number" },
|
|
4434
|
+
anchorY: { type: "number" },
|
|
4435
|
+
fit: { type: "string", minLength: 1 },
|
|
4436
|
+
alphaThreshold: { type: "number" },
|
|
4291
4437
|
tint: { type: "string", minLength: 1 }
|
|
4292
4438
|
},
|
|
4293
4439
|
additionalProperties: false,
|
|
@@ -4299,15 +4445,12 @@ var sceneGridSchema = {
|
|
|
4299
4445
|
properties: {
|
|
4300
4446
|
type: { type: "number" },
|
|
4301
4447
|
size: { type: "number" },
|
|
4302
|
-
sizeX: { type: "number" },
|
|
4303
|
-
sizeY: { type: "number" },
|
|
4304
4448
|
distance: { type: "number" },
|
|
4305
4449
|
units: { type: "string" },
|
|
4306
4450
|
style: { type: "string" },
|
|
4307
4451
|
thickness: { type: "number" },
|
|
4308
4452
|
color: { type: "string", minLength: 1 },
|
|
4309
|
-
alpha: { type: "number" }
|
|
4310
|
-
diagonals: { type: "number" }
|
|
4453
|
+
alpha: { type: "number" }
|
|
4311
4454
|
},
|
|
4312
4455
|
additionalProperties: false,
|
|
4313
4456
|
minProperties: 1
|
|
@@ -4317,6 +4460,7 @@ var sceneCreateSchema = {
|
|
|
4317
4460
|
required: ["name"],
|
|
4318
4461
|
properties: {
|
|
4319
4462
|
name: { type: "string", minLength: 1 },
|
|
4463
|
+
folder: nullableStringSchema,
|
|
4320
4464
|
active: { type: "boolean" },
|
|
4321
4465
|
navigation: { type: "boolean" },
|
|
4322
4466
|
navOrder: { type: "number" },
|
|
@@ -4333,7 +4477,7 @@ var sceneCreateSchema = {
|
|
|
4333
4477
|
navName: nullableStringSchema,
|
|
4334
4478
|
thumb: nullableStringSchema,
|
|
4335
4479
|
sort: { type: "number" },
|
|
4336
|
-
|
|
4480
|
+
levels: { type: "array", minItems: 1, items: levelCreateSchema },
|
|
4337
4481
|
playlist: nullableStringSchema,
|
|
4338
4482
|
playlistSound: nullableStringSchema,
|
|
4339
4483
|
journal: nullableStringSchema,
|
|
@@ -4348,7 +4492,10 @@ var sceneCreateSchema = {
|
|
|
4348
4492
|
},
|
|
4349
4493
|
additionalProperties: false
|
|
4350
4494
|
};
|
|
4351
|
-
var scenePatchSchema = patchFrom(sceneCreateSchema
|
|
4495
|
+
var scenePatchSchema = patchFrom(sceneCreateSchema, {
|
|
4496
|
+
omit: ["levels"],
|
|
4497
|
+
prepend: { initialLevel: nullableStringSchema }
|
|
4498
|
+
});
|
|
4352
4499
|
var sceneCommands = {
|
|
4353
4500
|
"scene.list": cmd(nameFilteredListSchema),
|
|
4354
4501
|
"scene.get": cmd(sceneIdSchema),
|
|
@@ -4561,7 +4708,14 @@ var settingCommands = {
|
|
|
4561
4708
|
// ../protocol/src/schemas/system.js
|
|
4562
4709
|
var systemCommands = {
|
|
4563
4710
|
"system.ping": cmd(emptyObjectSchema),
|
|
4564
|
-
"system.info": cmd(
|
|
4711
|
+
"system.info": cmd({
|
|
4712
|
+
type: "object",
|
|
4713
|
+
required: [],
|
|
4714
|
+
properties: {
|
|
4715
|
+
include: { type: "array", items: { type: "string", enum: ["modules"] } }
|
|
4716
|
+
},
|
|
4717
|
+
additionalProperties: false
|
|
4718
|
+
}),
|
|
4565
4719
|
"system.reload": cmd(emptyObjectSchema)
|
|
4566
4720
|
};
|
|
4567
4721
|
|
|
@@ -5257,6 +5411,15 @@ var DEFAULT_COMMAND_PROFILE = deepFreeze({
|
|
|
5257
5411
|
"scene.wall.create-many": "allow",
|
|
5258
5412
|
"scene.wall.update-many": "allow",
|
|
5259
5413
|
"scene.wall.delete-many": "approve",
|
|
5414
|
+
"scene.level.list": "allow",
|
|
5415
|
+
"scene.level.get": "allow",
|
|
5416
|
+
"scene.level.create": "allow",
|
|
5417
|
+
"scene.level.update": "allow",
|
|
5418
|
+
"scene.level.delete": "approve",
|
|
5419
|
+
"scene.level.clone": "allow",
|
|
5420
|
+
"scene.level.create-many": "allow",
|
|
5421
|
+
"scene.level.update-many": "allow",
|
|
5422
|
+
"scene.level.delete-many": "approve",
|
|
5260
5423
|
"scene.note.list": "allow",
|
|
5261
5424
|
"scene.note.get": "allow",
|
|
5262
5425
|
"scene.note.create": "allow",
|
|
@@ -6119,11 +6282,22 @@ function createCliConfigStore(configPath = getDefaultCliConfigPath()) {
|
|
|
6119
6282
|
}
|
|
6120
6283
|
};
|
|
6121
6284
|
}
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6285
|
+
var DAEMON_OWNED_CONFIG_KEYS = ["version", "daemonUrl", "deviceCredential", "pairings"];
|
|
6286
|
+
function withDaemonOwnedKeys(config, owner) {
|
|
6287
|
+
const merged = { ...config };
|
|
6288
|
+
for (const key of DAEMON_OWNED_CONFIG_KEYS) {
|
|
6289
|
+
if (owner[key] === void 0) delete merged[key];
|
|
6290
|
+
else merged[key] = owner[key];
|
|
6291
|
+
}
|
|
6292
|
+
return merged;
|
|
6293
|
+
}
|
|
6294
|
+
function writeCliConfigUpdate(configStore, updates) {
|
|
6295
|
+
configStore.writeConfig(
|
|
6296
|
+
PersistedCliConfigSchema.parse({
|
|
6297
|
+
...configStore.readConfig() ?? createEmptyConfig(),
|
|
6298
|
+
...updates
|
|
6299
|
+
})
|
|
6300
|
+
);
|
|
6127
6301
|
}
|
|
6128
6302
|
function resolveRemoteCommandConfig({
|
|
6129
6303
|
flagDaemonUrl,
|
|
@@ -6169,8 +6343,8 @@ function readPendingApprovalDetails(envelope) {
|
|
|
6169
6343
|
var DaemonTransportError = class extends Error {
|
|
6170
6344
|
code;
|
|
6171
6345
|
details;
|
|
6172
|
-
constructor(code, message, details) {
|
|
6173
|
-
super(message);
|
|
6346
|
+
constructor(code, message, details, options) {
|
|
6347
|
+
super(message, options);
|
|
6174
6348
|
this.name = "DaemonTransportError";
|
|
6175
6349
|
this.code = code;
|
|
6176
6350
|
this.details = details;
|
|
@@ -6615,7 +6789,7 @@ var BridgeSessionStore = class {
|
|
|
6615
6789
|
ok: false,
|
|
6616
6790
|
error: createProtocolError({
|
|
6617
6791
|
code: ERROR_CODES.UNKNOWN_COMMAND,
|
|
6618
|
-
message: `Bridge session does not advertise support for ${request.command};
|
|
6792
|
+
message: `Bridge session does not advertise support for ${request.command}; details.supportedCommands lists the commands the connected bridge advertised, and \`fvtt-world-cli auth status\` reports them without the internal approval and policy commands; the Foundry module may be older than this CLI, or the GM page may need a reload`,
|
|
6619
6793
|
details: {
|
|
6620
6794
|
command: request.command,
|
|
6621
6795
|
supportedCommands: this.activeSession.commands
|
|
@@ -7161,11 +7335,9 @@ var BridgeDaemon = class {
|
|
|
7161
7335
|
}
|
|
7162
7336
|
persistConfig() {
|
|
7163
7337
|
if (!this.configStore) return;
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
...persisted?.uploadLimitBytes === void 0 ? {} : { uploadLimitBytes: persisted.uploadLimitBytes }
|
|
7168
|
-
});
|
|
7338
|
+
this.config = PersistedCliConfigSchema.parse(
|
|
7339
|
+
withDaemonOwnedKeys(this.configStore.readConfig() ?? this.config, this.config)
|
|
7340
|
+
);
|
|
7169
7341
|
this.configStore.writeConfig(this.config);
|
|
7170
7342
|
}
|
|
7171
7343
|
handlePairingRequest(socket, state, message) {
|
|
@@ -7972,23 +8144,35 @@ async function connectDaemonClient({
|
|
|
7972
8144
|
socket.send(JSON.stringify(createClientHello({ credential: deviceCredential ?? "" })));
|
|
7973
8145
|
});
|
|
7974
8146
|
socket.once("message", (data) => {
|
|
7975
|
-
const
|
|
7976
|
-
|
|
7977
|
-
|
|
8147
|
+
const decoded = decodeTransportFrame(data);
|
|
8148
|
+
if (!decoded.ok) {
|
|
8149
|
+
clearTimeout(timer);
|
|
8150
|
+
reject(decoded.error);
|
|
8151
|
+
socket.close();
|
|
8152
|
+
return;
|
|
8153
|
+
}
|
|
8154
|
+
const message = decoded.value;
|
|
8155
|
+
if (message.type !== MESSAGE_TYPES.CLIENT_HELLO_ACK) {
|
|
7978
8156
|
clearTimeout(timer);
|
|
7979
|
-
reject(
|
|
8157
|
+
reject(
|
|
8158
|
+
new DaemonTransportError(
|
|
8159
|
+
ERROR_CODES.INVALID_MESSAGE,
|
|
8160
|
+
"Daemon returned an unexpected message type",
|
|
8161
|
+
{
|
|
8162
|
+
reason: "unexpected_type"
|
|
8163
|
+
}
|
|
8164
|
+
)
|
|
8165
|
+
);
|
|
7980
8166
|
socket.close();
|
|
7981
8167
|
return;
|
|
7982
8168
|
}
|
|
7983
|
-
|
|
7984
|
-
const message = parsed.ok && validation.ok ? parsed.value : null;
|
|
7985
|
-
if (!message || message.type !== MESSAGE_TYPES.CLIENT_HELLO_ACK || !message.ok) {
|
|
8169
|
+
if (!message.ok) {
|
|
7986
8170
|
clearTimeout(timer);
|
|
7987
8171
|
reject(
|
|
7988
8172
|
new DaemonTransportError(
|
|
7989
|
-
message
|
|
7990
|
-
message
|
|
7991
|
-
message
|
|
8173
|
+
message.error?.code ?? ERROR_CODES.UNAUTHORIZED,
|
|
8174
|
+
message.error?.message ?? "Daemon rejected client authentication",
|
|
8175
|
+
message.error?.details
|
|
7992
8176
|
)
|
|
7993
8177
|
);
|
|
7994
8178
|
socket.close();
|
|
@@ -8003,7 +8187,8 @@ async function connectDaemonClient({
|
|
|
8003
8187
|
new DaemonTransportError(
|
|
8004
8188
|
ERROR_CODES.DAEMON_UNAVAILABLE,
|
|
8005
8189
|
error instanceof Error ? error.message : String(error),
|
|
8006
|
-
{ reason: "connect_error" }
|
|
8190
|
+
{ reason: "connect_error" },
|
|
8191
|
+
{ cause: error }
|
|
8007
8192
|
)
|
|
8008
8193
|
);
|
|
8009
8194
|
});
|
|
@@ -8523,23 +8708,21 @@ function parseCsvList(value, label) {
|
|
|
8523
8708
|
}
|
|
8524
8709
|
return items;
|
|
8525
8710
|
}
|
|
8526
|
-
|
|
8527
|
-
function parseIncludeFields(value) {
|
|
8711
|
+
function parseAllowedIncludeFields(value, allowed) {
|
|
8528
8712
|
const fields = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
8529
8713
|
if (fields.length === 0) {
|
|
8530
|
-
throw new InvalidArgumentError(
|
|
8531
|
-
`--include must name at least one field (allowed: ${INCLUDE_ALLOWED.join(", ")})`
|
|
8532
|
-
);
|
|
8714
|
+
throw new InvalidArgumentError(`--include must name at least one field (allowed: ${allowed.join(", ")})`);
|
|
8533
8715
|
}
|
|
8534
8716
|
for (const field of fields) {
|
|
8535
|
-
if (!
|
|
8536
|
-
throw new InvalidArgumentError(
|
|
8537
|
-
`--include only supports ${INCLUDE_ALLOWED.join(", ")}, received ${field}`
|
|
8538
|
-
);
|
|
8717
|
+
if (!allowed.includes(field)) {
|
|
8718
|
+
throw new InvalidArgumentError(`--include only supports ${allowed.join(", ")}, received ${field}`);
|
|
8539
8719
|
}
|
|
8540
8720
|
}
|
|
8541
8721
|
return fields;
|
|
8542
8722
|
}
|
|
8723
|
+
function parseIncludeFields(value) {
|
|
8724
|
+
return parseAllowedIncludeFields(value, ["flags", "effects"]);
|
|
8725
|
+
}
|
|
8543
8726
|
var OWNERSHIP_LEVELS = [-1, 0, 1, 2, 3];
|
|
8544
8727
|
var INTEGER_PATTERN = /^-?\d+$/;
|
|
8545
8728
|
function parseOwnershipLevel(value) {
|
|
@@ -8639,56 +8822,24 @@ function parseWhisperIds(value) {
|
|
|
8639
8822
|
}
|
|
8640
8823
|
return ids;
|
|
8641
8824
|
}
|
|
8642
|
-
var ACTOR_INCLUDE_ALLOWED = ["flags", "effects", "items.flags", "items.effects", "prepared"];
|
|
8643
8825
|
function parseActorIncludeFields(value) {
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
throw new InvalidArgumentError(
|
|
8653
|
-
`--include only supports ${ACTOR_INCLUDE_ALLOWED.join(", ")}, received ${field}`
|
|
8654
|
-
);
|
|
8655
|
-
}
|
|
8656
|
-
}
|
|
8657
|
-
return fields;
|
|
8826
|
+
return parseAllowedIncludeFields(value, [
|
|
8827
|
+
"flags",
|
|
8828
|
+
"effects",
|
|
8829
|
+
"items",
|
|
8830
|
+
"items.flags",
|
|
8831
|
+
"items.effects",
|
|
8832
|
+
"prepared"
|
|
8833
|
+
]);
|
|
8658
8834
|
}
|
|
8659
|
-
var TOKEN_INCLUDE_ALLOWED = ["prepared"];
|
|
8660
8835
|
function parseTokenIncludeFields(value) {
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
);
|
|
8666
|
-
}
|
|
8667
|
-
for (const field of fields) {
|
|
8668
|
-
if (!TOKEN_INCLUDE_ALLOWED.includes(field)) {
|
|
8669
|
-
throw new InvalidArgumentError(
|
|
8670
|
-
`--include only supports ${TOKEN_INCLUDE_ALLOWED.join(", ")}, received ${field}`
|
|
8671
|
-
);
|
|
8672
|
-
}
|
|
8673
|
-
}
|
|
8674
|
-
return fields;
|
|
8836
|
+
return parseAllowedIncludeFields(value, ["prepared"]);
|
|
8837
|
+
}
|
|
8838
|
+
function parseSystemInfoIncludeFields(value) {
|
|
8839
|
+
return parseAllowedIncludeFields(value, ["modules"]);
|
|
8675
8840
|
}
|
|
8676
|
-
var COMPENDIUM_INCLUDE_ALLOWED = ["effects"];
|
|
8677
8841
|
function parseCompendiumIncludeFields(value) {
|
|
8678
|
-
|
|
8679
|
-
if (fields.length === 0) {
|
|
8680
|
-
throw new InvalidArgumentError(
|
|
8681
|
-
`--include must name at least one field (allowed: ${COMPENDIUM_INCLUDE_ALLOWED.join(", ")})`
|
|
8682
|
-
);
|
|
8683
|
-
}
|
|
8684
|
-
for (const field of fields) {
|
|
8685
|
-
if (!COMPENDIUM_INCLUDE_ALLOWED.includes(field)) {
|
|
8686
|
-
throw new InvalidArgumentError(
|
|
8687
|
-
`--include only supports ${COMPENDIUM_INCLUDE_ALLOWED.join(", ")}, received ${field}`
|
|
8688
|
-
);
|
|
8689
|
-
}
|
|
8690
|
-
}
|
|
8691
|
-
return fields;
|
|
8842
|
+
return parseAllowedIncludeFields(value, ["effects"]);
|
|
8692
8843
|
}
|
|
8693
8844
|
function parseCompendiumFieldsList(value) {
|
|
8694
8845
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
@@ -8786,44 +8937,10 @@ function createItemUpdateParams(options) {
|
|
|
8786
8937
|
...options.include ? { include: options.include } : {}
|
|
8787
8938
|
};
|
|
8788
8939
|
}
|
|
8789
|
-
function createSceneUpdateParams(options) {
|
|
8790
|
-
return {
|
|
8791
|
-
sceneId: options.sceneId,
|
|
8792
|
-
patch: assertNonEmptyPatch({
|
|
8793
|
-
...stringField("name", options.name),
|
|
8794
|
-
...booleanField("active", options.active),
|
|
8795
|
-
...booleanField("navigation", options.navigation),
|
|
8796
|
-
...numberField("navOrder", options.navOrder),
|
|
8797
|
-
...numberField("width", options.width),
|
|
8798
|
-
...numberField("height", options.height),
|
|
8799
|
-
...jsonObjectField("grid", options.gridJson, "--grid-json"),
|
|
8800
|
-
...jsonObjectField("background", options.backgroundJson, "--background-json"),
|
|
8801
|
-
...booleanField("tokenVision", options.tokenVision),
|
|
8802
|
-
...truthyStringField("weather", options.weather),
|
|
8803
|
-
...numberField("padding", options.padding),
|
|
8804
|
-
...numberField("shiftX", options.shiftX),
|
|
8805
|
-
...numberField("shiftY", options.shiftY),
|
|
8806
|
-
...truthyStringField("navName", options.navName),
|
|
8807
|
-
...truthyStringField("thumb", options.thumb),
|
|
8808
|
-
...truthyStringField("foreground", options.foreground),
|
|
8809
|
-
...numberField("foregroundElevation", options.foregroundElevation),
|
|
8810
|
-
...numberField("sort", options.sort),
|
|
8811
|
-
...truthyStringField("initialLevel", options.initialLevel),
|
|
8812
|
-
...truthyStringField("playlist", options.playlist),
|
|
8813
|
-
...truthyStringField("playlistSound", options.playlistSound),
|
|
8814
|
-
...truthyStringField("journal", options.journal),
|
|
8815
|
-
...truthyStringField("journalEntryPage", options.journalEntryPage),
|
|
8816
|
-
...jsonObjectField("environment", options.environmentJson, "--environment-json"),
|
|
8817
|
-
...jsonObjectField("fog", options.fogJson, "--fog-json"),
|
|
8818
|
-
...jsonObjectField("initial", options.initialJson, "--initial-json"),
|
|
8819
|
-
...jsonObjectField("transition", options.transitionJson, "--transition-json"),
|
|
8820
|
-
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
8821
|
-
})
|
|
8822
|
-
};
|
|
8823
|
-
}
|
|
8824
8940
|
function buildScenePatch(options) {
|
|
8825
8941
|
return {
|
|
8826
8942
|
...stringField("name", options.name),
|
|
8943
|
+
...folderField(options),
|
|
8827
8944
|
...booleanField("active", options.active),
|
|
8828
8945
|
...booleanField("navigation", options.navigation),
|
|
8829
8946
|
...numberField("navOrder", options.navOrder),
|
|
@@ -8852,6 +8969,15 @@ function buildScenePatch(options) {
|
|
|
8852
8969
|
...jsonObjectField("transition", options.transitionJson, "--transition-json")
|
|
8853
8970
|
};
|
|
8854
8971
|
}
|
|
8972
|
+
function createSceneUpdateParams(options) {
|
|
8973
|
+
return {
|
|
8974
|
+
sceneId: options.sceneId,
|
|
8975
|
+
patch: assertNonEmptyPatch({
|
|
8976
|
+
...buildScenePatch(options),
|
|
8977
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
8978
|
+
})
|
|
8979
|
+
};
|
|
8980
|
+
}
|
|
8855
8981
|
function createSceneCreateParams(options) {
|
|
8856
8982
|
return {
|
|
8857
8983
|
data: {
|
|
@@ -9657,6 +9783,23 @@ function createSceneWallCloneParams(options) {
|
|
|
9657
9783
|
...optionalPatch(optionalJsonObject(options.patchJson, "--patch-json") ?? {})
|
|
9658
9784
|
};
|
|
9659
9785
|
}
|
|
9786
|
+
function createSceneLevelCreateParams(options) {
|
|
9787
|
+
return { sceneId: options.sceneId, data: optionalJsonObject(options.dataJson, "--data-json") ?? {} };
|
|
9788
|
+
}
|
|
9789
|
+
function createSceneLevelUpdateParams(options) {
|
|
9790
|
+
return {
|
|
9791
|
+
sceneId: options.sceneId,
|
|
9792
|
+
levelId: options.levelId,
|
|
9793
|
+
patch: assertNonEmptyPatch(optionalJsonObject(options.patchJson, "--patch-json") ?? {})
|
|
9794
|
+
};
|
|
9795
|
+
}
|
|
9796
|
+
function createSceneLevelCloneParams(options) {
|
|
9797
|
+
return {
|
|
9798
|
+
sceneId: options.sceneId,
|
|
9799
|
+
levelId: options.levelId,
|
|
9800
|
+
...optionalPatch(optionalJsonObject(options.patchJson, "--patch-json") ?? {})
|
|
9801
|
+
};
|
|
9802
|
+
}
|
|
9660
9803
|
function createSceneNoteCreateParams(options) {
|
|
9661
9804
|
return { sceneId: options.sceneId, data: optionalJsonObject(options.dataJson, "--data-json") ?? {} };
|
|
9662
9805
|
}
|
|
@@ -10369,7 +10512,7 @@ function renderActorDetails(actor) {
|
|
|
10369
10512
|
if (actor && Object.hasOwn(actor, "prepared")) {
|
|
10370
10513
|
lines.push(`prepared: ${Object.keys(actor.prepared ?? {}).join(", ")} (use --json for values)`);
|
|
10371
10514
|
}
|
|
10372
|
-
lines.push(`items: ${items.length}`);
|
|
10515
|
+
lines.push(`items: ${actor?.itemCount ?? items.length}`);
|
|
10373
10516
|
items.forEach((item) => {
|
|
10374
10517
|
lines.push(`item: ${renderItemSummaryLine(item)}`);
|
|
10375
10518
|
});
|
|
@@ -11128,16 +11271,23 @@ function renderSceneDetails(scene) {
|
|
|
11128
11271
|
const lines = [
|
|
11129
11272
|
`id: ${scene?.id}`,
|
|
11130
11273
|
`name: ${scene?.name}`,
|
|
11274
|
+
`folder: ${scene?.folder ?? ""}`,
|
|
11131
11275
|
`active: ${String(Boolean(scene?.active))}`,
|
|
11132
11276
|
`navigation: ${String(Boolean(scene?.navigation))}`,
|
|
11133
11277
|
`nav order: ${scene?.navOrder ?? 0}`,
|
|
11134
11278
|
`size: ${scene?.width}x${scene?.height}`,
|
|
11135
11279
|
`grid: ${JSON.stringify(scene?.grid ?? null)}`,
|
|
11136
|
-
`background: ${JSON.stringify(scene
|
|
11280
|
+
...scene && Object.hasOwn(scene, "background") ? [`background: ${JSON.stringify(scene.background ?? null)}`] : [],
|
|
11137
11281
|
`token vision: ${String(Boolean(scene?.tokenVision))}`,
|
|
11138
11282
|
`weather: ${scene?.weather ?? ""}`,
|
|
11139
11283
|
`playlist: ${scene?.playlist ?? ""}`
|
|
11140
11284
|
];
|
|
11285
|
+
if (scene && Object.hasOwn(scene, "initialLevel")) {
|
|
11286
|
+
lines.push(`initial level: ${scene.initialLevel ?? "(first level)"}`);
|
|
11287
|
+
}
|
|
11288
|
+
for (const level of Array.isArray(scene?.levels) ? scene.levels : []) {
|
|
11289
|
+
lines.push(`level: ${renderLevelRow(level)}`);
|
|
11290
|
+
}
|
|
11141
11291
|
lines.push(...renderCompendiumSourceLines(scene));
|
|
11142
11292
|
if (scene && Object.hasOwn(scene, "ownership")) {
|
|
11143
11293
|
lines.push(...renderOwnershipLines(scene.ownership));
|
|
@@ -11149,6 +11299,20 @@ function renderSceneDetails(scene) {
|
|
|
11149
11299
|
}
|
|
11150
11300
|
return lines.join("\n");
|
|
11151
11301
|
}
|
|
11302
|
+
function levelMembership(placeable) {
|
|
11303
|
+
if (placeable && Object.hasOwn(placeable, "level")) return ["level", String(placeable.level)];
|
|
11304
|
+
if (placeable && Object.hasOwn(placeable, "levels"))
|
|
11305
|
+
return ["levels", placeable.levels.join(",") || "(all)"];
|
|
11306
|
+
return null;
|
|
11307
|
+
}
|
|
11308
|
+
function levelMembershipLines(placeable) {
|
|
11309
|
+
const membership = levelMembership(placeable);
|
|
11310
|
+
return membership ? [`${membership[0]}: ${membership[1]}`] : [];
|
|
11311
|
+
}
|
|
11312
|
+
function levelMembershipCell(placeable) {
|
|
11313
|
+
const membership = levelMembership(placeable);
|
|
11314
|
+
return membership ? ` ${membership[0]}=${membership[1]}` : "";
|
|
11315
|
+
}
|
|
11152
11316
|
function renderTokenDetails(sceneId, token) {
|
|
11153
11317
|
const lines = [
|
|
11154
11318
|
`scene: ${sceneId}`,
|
|
@@ -11158,6 +11322,7 @@ function renderTokenDetails(sceneId, token) {
|
|
|
11158
11322
|
`actorLink: ${String(Boolean(token?.actorLink))}`,
|
|
11159
11323
|
`position: (${token?.x ?? 0}, ${token?.y ?? 0})`,
|
|
11160
11324
|
`elevation: ${token?.elevation ?? 0}`,
|
|
11325
|
+
...levelMembershipLines(token),
|
|
11161
11326
|
`rotation: ${token?.rotation ?? 0}`,
|
|
11162
11327
|
`hidden: ${String(Boolean(token?.hidden))}`,
|
|
11163
11328
|
`disposition: ${token?.disposition ?? ""}`,
|
|
@@ -11206,6 +11371,7 @@ function renderTileDetails(sceneId, tile) {
|
|
|
11206
11371
|
`size: ${tile?.width}x${tile?.height}`,
|
|
11207
11372
|
`rotation: ${tile?.rotation ?? 0}`,
|
|
11208
11373
|
`elevation: ${tile?.elevation ?? 0}`,
|
|
11374
|
+
...levelMembershipLines(tile),
|
|
11209
11375
|
`sort: ${tile?.sort ?? 0}`,
|
|
11210
11376
|
`hidden: ${String(Boolean(tile?.hidden))}`,
|
|
11211
11377
|
`locked: ${String(Boolean(tile?.locked))}`,
|
|
@@ -11219,6 +11385,7 @@ function renderSoundDetails(sceneId, sound) {
|
|
|
11219
11385
|
`path: ${sound?.path ?? ""}`,
|
|
11220
11386
|
`position: (${sound?.x ?? 0}, ${sound?.y ?? 0})`,
|
|
11221
11387
|
`radius: ${sound?.radius ?? 0}`,
|
|
11388
|
+
...levelMembershipLines(sound),
|
|
11222
11389
|
`volume: ${sound?.volume ?? ""}`,
|
|
11223
11390
|
`walls: ${String(Boolean(sound?.walls))}`,
|
|
11224
11391
|
`easing: ${String(Boolean(sound?.easing))}`,
|
|
@@ -11226,11 +11393,30 @@ function renderSoundDetails(sceneId, sound) {
|
|
|
11226
11393
|
`hidden: ${String(Boolean(sound?.hidden))}`
|
|
11227
11394
|
].join("\n");
|
|
11228
11395
|
}
|
|
11396
|
+
function renderLevelRow(level) {
|
|
11397
|
+
const elevation = level?.elevation ?? {};
|
|
11398
|
+
return `${level?.id} ${level?.name ?? ""} elevation=${elevation.bottom ?? "-inf"}..${elevation.top ?? "+inf"} sort=${level?.sort ?? 0}`;
|
|
11399
|
+
}
|
|
11400
|
+
function renderLevelDetails(sceneId, level) {
|
|
11401
|
+
return [
|
|
11402
|
+
`scene: ${sceneId}`,
|
|
11403
|
+
`id: ${level?.id}`,
|
|
11404
|
+
`name: ${level?.name ?? ""}`,
|
|
11405
|
+
`elevation: ${JSON.stringify(level?.elevation ?? null)}`,
|
|
11406
|
+
`sort: ${level?.sort ?? 0}`,
|
|
11407
|
+
`background: ${JSON.stringify(level?.background ?? null)}`,
|
|
11408
|
+
`foreground: ${JSON.stringify(level?.foreground ?? null)}`,
|
|
11409
|
+
`fog: ${JSON.stringify(level?.fog ?? null)}`,
|
|
11410
|
+
`textures: ${JSON.stringify(level?.textures ?? null)}`,
|
|
11411
|
+
`visibility: ${JSON.stringify(level?.visibility ?? null)}`
|
|
11412
|
+
].join("\n");
|
|
11413
|
+
}
|
|
11229
11414
|
function renderWallDetails(sceneId, wall) {
|
|
11230
11415
|
return [
|
|
11231
11416
|
`scene: ${sceneId}`,
|
|
11232
11417
|
`id: ${wall?.id}`,
|
|
11233
11418
|
`c: ${JSON.stringify(wall?.c ?? null)}`,
|
|
11419
|
+
...levelMembershipLines(wall),
|
|
11234
11420
|
`door: ${wall?.door ?? 0}`,
|
|
11235
11421
|
`ds: ${wall?.ds ?? 0}`,
|
|
11236
11422
|
`doorSound: ${wall?.doorSound ?? ""}`,
|
|
@@ -11253,6 +11439,7 @@ function renderNoteDetails(sceneId, note) {
|
|
|
11253
11439
|
`texture: ${JSON.stringify(note?.texture ?? null)}`,
|
|
11254
11440
|
`iconSize: ${note?.iconSize ?? ""}`,
|
|
11255
11441
|
`elevation: ${note?.elevation ?? 0}`,
|
|
11442
|
+
...levelMembershipLines(note),
|
|
11256
11443
|
`sort: ${note?.sort ?? 0}`,
|
|
11257
11444
|
`global: ${String(Boolean(note?.global))}`
|
|
11258
11445
|
].join("\n");
|
|
@@ -11268,6 +11455,7 @@ function renderDrawingDetails(sceneId, drawing) {
|
|
|
11268
11455
|
`shape: ${JSON.stringify(drawing?.shape ?? null)}`,
|
|
11269
11456
|
`rotation: ${drawing?.rotation ?? 0}`,
|
|
11270
11457
|
`elevation: ${drawing?.elevation ?? 0}`,
|
|
11458
|
+
...levelMembershipLines(drawing),
|
|
11271
11459
|
`sort: ${drawing?.sort ?? 0}`,
|
|
11272
11460
|
`fillColor: ${drawing?.fillColor ?? ""}`,
|
|
11273
11461
|
`strokeColor: ${drawing?.strokeColor ?? ""}`,
|
|
@@ -11282,6 +11470,7 @@ function renderLightDetails(sceneId, light) {
|
|
|
11282
11470
|
`name: ${light?.name ?? ""}`,
|
|
11283
11471
|
`position: (${light?.x ?? 0}, ${light?.y ?? 0})`,
|
|
11284
11472
|
`elevation: ${light?.elevation ?? 0}`,
|
|
11473
|
+
...levelMembershipLines(light),
|
|
11285
11474
|
`rotation: ${light?.rotation ?? 0}`,
|
|
11286
11475
|
`walls: ${String(Boolean(light?.walls))}`,
|
|
11287
11476
|
`vision: ${String(Boolean(light?.vision))}`,
|
|
@@ -11312,6 +11501,7 @@ function renderRegionDetails(sceneId, region) {
|
|
|
11312
11501
|
`color: ${region?.color ?? ""}`,
|
|
11313
11502
|
`visibility: ${region?.visibility ?? ""}`,
|
|
11314
11503
|
`elevation: ${JSON.stringify(region?.elevation ?? null)}`,
|
|
11504
|
+
...levelMembershipLines(region),
|
|
11315
11505
|
`shapes: ${JSON.stringify(region?.shapes ?? [])}`,
|
|
11316
11506
|
`behaviors: ${JSON.stringify(region?.behaviors ?? [])}`,
|
|
11317
11507
|
`locked: ${String(Boolean(region?.locked))}`
|
|
@@ -11614,10 +11804,12 @@ var RENDERERS = registerRenderers([
|
|
|
11614
11804
|
`world: ${result.world?.title ?? "Unknown World"} [${result.world?.id ?? "unknown-world"}]`,
|
|
11615
11805
|
`user: ${result.user?.name ?? "Unknown User"} [${result.user?.id ?? "unknown-user"}] GM=${String(Boolean(result.user?.isGM))}`,
|
|
11616
11806
|
`bridge: ${result.bridge?.status ?? "unknown"}`,
|
|
11617
|
-
`modules: ${
|
|
11807
|
+
`modules: ${result.moduleCount ?? "unknown"} installed, ${result.activeModuleCount ?? "unknown"} active`,
|
|
11808
|
+
...(result.modules ?? []).map(
|
|
11809
|
+
(module) => ` ${module.id} ${module.version ?? "unknown"} ${module.active ? "active" : "inactive"}`
|
|
11810
|
+
),
|
|
11618
11811
|
`limits.uploadBytes: ${result.limits?.uploadBytes ?? "unknown"} (source: ${result.limits?.uploadSource ?? "unknown"})`,
|
|
11619
|
-
`limits.wsMaxPayloadBytes: ${result.limits?.wsMaxPayloadBytes ?? "unknown"}
|
|
11620
|
-
`commands: ${(result.commands ?? []).join(", ")}`
|
|
11812
|
+
`limits.wsMaxPayloadBytes: ${result.limits?.wsMaxPayloadBytes ?? "unknown"}`
|
|
11621
11813
|
].join("\n")
|
|
11622
11814
|
),
|
|
11623
11815
|
detailRenderer(
|
|
@@ -12348,7 +12540,7 @@ var RENDERERS = registerRenderers([
|
|
|
12348
12540
|
empty: "No tokens found.",
|
|
12349
12541
|
heading: "Tokens",
|
|
12350
12542
|
prefix: scenePrefix,
|
|
12351
|
-
row: (token) => `${token.id} ${token.name} actor=${token.actorId ?? "-"} linked=${String(Boolean(token.actorLink))} (${token.x},${token.y})`
|
|
12543
|
+
row: (token) => `${token.id} ${token.name} actor=${token.actorId ?? "-"} linked=${String(Boolean(token.actorLink))} (${token.x},${token.y})${levelMembershipCell(token)}`
|
|
12352
12544
|
}),
|
|
12353
12545
|
detailRenderer(
|
|
12354
12546
|
["scene.token.get", "scene.token.create", "scene.token.update", "scene.token.clone"],
|
|
@@ -12372,7 +12564,7 @@ var RENDERERS = registerRenderers([
|
|
|
12372
12564
|
empty: "No tiles found.",
|
|
12373
12565
|
heading: "Tiles",
|
|
12374
12566
|
prefix: scenePrefix,
|
|
12375
|
-
row: (tile) => `${tile.id} (${tile.x},${tile.y}) ${tile.width}x${tile.height} hidden=${String(Boolean(tile.hidden))}`
|
|
12567
|
+
row: (tile) => `${tile.id} (${tile.x},${tile.y}) ${tile.width}x${tile.height} hidden=${String(Boolean(tile.hidden))}${levelMembershipCell(tile)}`
|
|
12376
12568
|
}),
|
|
12377
12569
|
detailRenderer(
|
|
12378
12570
|
["scene.tile.get", "scene.tile.create", "scene.tile.update", "scene.tile.clone"],
|
|
@@ -12384,7 +12576,7 @@ var RENDERERS = registerRenderers([
|
|
|
12384
12576
|
empty: "No sounds found.",
|
|
12385
12577
|
heading: "Sounds",
|
|
12386
12578
|
prefix: scenePrefix,
|
|
12387
|
-
row: (sound) => `${sound.id} ${sound.path ?? ""} (${sound.x},${sound.y}) r=${sound.radius} hidden=${String(Boolean(sound.hidden))}`
|
|
12579
|
+
row: (sound) => `${sound.id} ${sound.path ?? ""} (${sound.x},${sound.y}) r=${sound.radius} hidden=${String(Boolean(sound.hidden))}${levelMembershipCell(sound)}`
|
|
12388
12580
|
}),
|
|
12389
12581
|
detailRenderer(
|
|
12390
12582
|
["scene.sound.get", "scene.sound.create", "scene.sound.update", "scene.sound.clone"],
|
|
@@ -12396,20 +12588,32 @@ var RENDERERS = registerRenderers([
|
|
|
12396
12588
|
empty: "No walls found.",
|
|
12397
12589
|
heading: "Walls",
|
|
12398
12590
|
prefix: scenePrefix,
|
|
12399
|
-
row: (wall) => `${wall.id} ${wall.door ?? 0}/${wall.ds ?? 0}/${wall.doorSound ?? ""} c=[${(wall.c ?? []).join(",")}]`
|
|
12591
|
+
row: (wall) => `${wall.id} ${wall.door ?? 0}/${wall.ds ?? 0}/${wall.doorSound ?? ""} c=[${(wall.c ?? []).join(",")}]${levelMembershipCell(wall)}`
|
|
12400
12592
|
}),
|
|
12401
12593
|
detailRenderer(
|
|
12402
12594
|
["scene.wall.get", "scene.wall.create", "scene.wall.update", "scene.wall.clone"],
|
|
12403
12595
|
(result) => renderWallDetails(result.sceneId, result.wall)
|
|
12404
12596
|
),
|
|
12405
12597
|
deleteRenderer("scene.wall.delete", "wall", { suffix: sceneSuffix }),
|
|
12598
|
+
listRenderer("scene.level.list", {
|
|
12599
|
+
key: "levels",
|
|
12600
|
+
empty: "No levels found.",
|
|
12601
|
+
heading: "Levels",
|
|
12602
|
+
prefix: scenePrefix,
|
|
12603
|
+
row: (level) => renderLevelRow(level)
|
|
12604
|
+
}),
|
|
12605
|
+
detailRenderer(
|
|
12606
|
+
["scene.level.get", "scene.level.create", "scene.level.update", "scene.level.clone"],
|
|
12607
|
+
(result) => renderLevelDetails(result.sceneId, result.level)
|
|
12608
|
+
),
|
|
12609
|
+
deleteRenderer("scene.level.delete", "level", { suffix: sceneSuffix }),
|
|
12406
12610
|
detailRenderer(BATCH_WRITE_COMMANDS, (result, command) => renderBatchWriteResult(command, result)),
|
|
12407
12611
|
listRenderer("scene.note.list", {
|
|
12408
12612
|
key: "notes",
|
|
12409
12613
|
empty: "No notes found.",
|
|
12410
12614
|
heading: "Notes",
|
|
12411
12615
|
prefix: scenePrefix,
|
|
12412
|
-
row: (note) => `${note.id} ${note.text ?? ""} (${note.x},${note.y}) ${note.texture?.src ?? ""} ${note.iconSize ?? ""}`
|
|
12616
|
+
row: (note) => `${note.id} ${note.text ?? ""} (${note.x},${note.y}) ${note.texture?.src ?? ""} ${note.iconSize ?? ""}${levelMembershipCell(note)}`
|
|
12413
12617
|
}),
|
|
12414
12618
|
detailRenderer(
|
|
12415
12619
|
["scene.note.get", "scene.note.create", "scene.note.update", "scene.note.clone"],
|
|
@@ -12421,7 +12625,7 @@ var RENDERERS = registerRenderers([
|
|
|
12421
12625
|
empty: "No drawings found.",
|
|
12422
12626
|
heading: "Drawings",
|
|
12423
12627
|
prefix: scenePrefix,
|
|
12424
|
-
row: (drawing) => `${drawing.id} ${drawing.text ?? ""} (${drawing.x},${drawing.y}) ${drawing.shape?.type ?? ""} ${String(Boolean(drawing.hidden))} ${drawing.name ?? "(no name)"}`
|
|
12628
|
+
row: (drawing) => `${drawing.id} ${drawing.text ?? ""} (${drawing.x},${drawing.y}) ${drawing.shape?.type ?? ""} ${String(Boolean(drawing.hidden))} ${drawing.name ?? "(no name)"}${levelMembershipCell(drawing)}`
|
|
12425
12629
|
}),
|
|
12426
12630
|
detailRenderer(
|
|
12427
12631
|
["scene.drawing.get", "scene.drawing.create", "scene.drawing.update", "scene.drawing.clone"],
|
|
@@ -12433,7 +12637,7 @@ var RENDERERS = registerRenderers([
|
|
|
12433
12637
|
empty: "No lights found.",
|
|
12434
12638
|
heading: "Lights",
|
|
12435
12639
|
prefix: scenePrefix,
|
|
12436
|
-
row: (light) => `${light.id} (${light.x},${light.y}) ${light.config?.dim ?? ""}/${light.config?.bright ?? ""} ${String(Boolean(light.hidden))} ${light.name ?? "(no name)"}`
|
|
12640
|
+
row: (light) => `${light.id} (${light.x},${light.y}) ${light.config?.dim ?? ""}/${light.config?.bright ?? ""} ${String(Boolean(light.hidden))} ${light.name ?? "(no name)"}${levelMembershipCell(light)}`
|
|
12437
12641
|
}),
|
|
12438
12642
|
detailRenderer(
|
|
12439
12643
|
["scene.light.get", "scene.light.create", "scene.light.update", "scene.light.clone"],
|
|
@@ -12457,7 +12661,7 @@ var RENDERERS = registerRenderers([
|
|
|
12457
12661
|
empty: "No regions found.",
|
|
12458
12662
|
heading: "Regions",
|
|
12459
12663
|
prefix: scenePrefix,
|
|
12460
|
-
row: (region) => `${region.id} ${region.name ?? ""} ${region.visibility ?? ""} shapes=${region.shapesCount ?? 0} behaviors=${region.behaviorsCount ?? 0}`
|
|
12664
|
+
row: (region) => `${region.id} ${region.name ?? ""} ${region.visibility ?? ""} shapes=${region.shapesCount ?? 0} behaviors=${region.behaviorsCount ?? 0}${levelMembershipCell(region)}`
|
|
12461
12665
|
}),
|
|
12462
12666
|
detailRenderer(
|
|
12463
12667
|
["scene.region.get", "scene.region.create", "scene.region.update", "scene.region.clone"],
|
|
@@ -12856,11 +13060,17 @@ function addReservedIncludeOption(command, presence) {
|
|
|
12856
13060
|
function addActorIncludeOption(command) {
|
|
12857
13061
|
return command.option(
|
|
12858
13062
|
"--include <fields>",
|
|
12859
|
-
"Comma-separated extra fields (items.flags
|
|
13063
|
+
"Comma-separated extra fields (items adds the owned items, which items.flags and items.effects also imply; prepared adds derived data; flags/effects are always present, so those two have no effect)",
|
|
12860
13064
|
parseActorIncludeFields
|
|
12861
13065
|
);
|
|
12862
13066
|
}
|
|
13067
|
+
var INITIAL_LEVEL_FIELD = {
|
|
13068
|
+
flag: "--initial-level <initialLevel>",
|
|
13069
|
+
help: "Initial level id (Foundry v14)"
|
|
13070
|
+
};
|
|
12863
13071
|
var SCENE_FIELDS = [
|
|
13072
|
+
FOLDER_ID_FIELD,
|
|
13073
|
+
CLEAR_FOLDER_FIELD,
|
|
12864
13074
|
{ flag: "--active <active>", help: "Scene active state", parser: parseBoolean },
|
|
12865
13075
|
{ flag: "--navigation <navigation>", help: "Scene navigation visibility", parser: parseBoolean },
|
|
12866
13076
|
{ flag: "--nav-order <navOrder>", help: "Scene navigation order", parser: parseNumber },
|
|
@@ -12873,14 +13083,14 @@ var SCENE_FIELDS = [
|
|
|
12873
13083
|
{ flag: "--shift-y <shiftY>", help: "Background Y shift", parser: parseNumber },
|
|
12874
13084
|
{ flag: "--nav-name <navName>", help: "Navigation label" },
|
|
12875
13085
|
{ flag: "--thumb <thumb>", help: "Thumbnail image path" },
|
|
12876
|
-
{ flag: "--foreground <foreground>", help: "Foreground image path" },
|
|
13086
|
+
{ flag: "--foreground <foreground>", help: "Foreground image path (Foundry v13)" },
|
|
12877
13087
|
{
|
|
12878
13088
|
flag: "--foreground-elevation <foregroundElevation>",
|
|
12879
|
-
help: "Foreground image elevation",
|
|
13089
|
+
help: "Foreground image elevation (Foundry v13)",
|
|
12880
13090
|
parser: parseNumber
|
|
12881
13091
|
},
|
|
12882
13092
|
{ flag: "--sort <sort>", help: "Sort order", parser: parseNumber },
|
|
12883
|
-
|
|
13093
|
+
INITIAL_LEVEL_FIELD,
|
|
12884
13094
|
{ flag: "--playlist <playlistId>", help: "Linked playlist id" },
|
|
12885
13095
|
{ flag: "--playlist-sound <playlistSoundId>", help: "Linked playlist sound id" },
|
|
12886
13096
|
{ flag: "--journal <journalId>", help: "Linked journal id" },
|
|
@@ -12900,14 +13110,15 @@ var SCENE_FIELDS = [
|
|
|
12900
13110
|
{
|
|
12901
13111
|
flag: "--background-json <json>",
|
|
12902
13112
|
help: {
|
|
12903
|
-
create: "Scene background as JSON object",
|
|
12904
|
-
update: "Scene background patch as JSON object",
|
|
12905
|
-
clone: "Scene background override as JSON object"
|
|
13113
|
+
create: "Scene background as JSON object (Foundry v13)",
|
|
13114
|
+
update: "Scene background patch as JSON object (Foundry v13)",
|
|
13115
|
+
clone: "Scene background override as JSON object (Foundry v13)"
|
|
12906
13116
|
}
|
|
12907
13117
|
}
|
|
12908
13118
|
];
|
|
12909
13119
|
function addSceneFieldOptions(command, verb) {
|
|
12910
|
-
|
|
13120
|
+
const specs = verb === "create" ? SCENE_FIELDS.filter((spec) => spec !== INITIAL_LEVEL_FIELD) : SCENE_FIELDS;
|
|
13121
|
+
return addFieldOptions(command, verb, specs);
|
|
12911
13122
|
}
|
|
12912
13123
|
var TOKEN_NAME_FIELD = {
|
|
12913
13124
|
flag: "--name <name>",
|
|
@@ -14351,7 +14562,9 @@ function createDaemonControlRunner(dependencies) {
|
|
|
14351
14562
|
`);
|
|
14352
14563
|
else if (response.ok) write(dependencies.stdout, `${JSON.stringify(response.result, null, 2)}
|
|
14353
14564
|
`);
|
|
14354
|
-
else
|
|
14565
|
+
else write(dependencies.stderr, `${renderProtocolError(response.error)}
|
|
14566
|
+
`);
|
|
14567
|
+
if (!response.ok)
|
|
14355
14568
|
throw new CommanderError4(
|
|
14356
14569
|
exitCodeForErrorCode(response.error?.code),
|
|
14357
14570
|
"fvtt-world-cli.remoteError",
|
|
@@ -14684,11 +14897,9 @@ function recordSkillInstalls(dependencies, roots, { remove = false } = {}) {
|
|
|
14684
14897
|
else current.add(root);
|
|
14685
14898
|
}
|
|
14686
14899
|
const skillInstalls = [...current].sort();
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
skillInstalls.length > 0 ? { skillInstalls } : { skillInstalls: void 0 }
|
|
14691
|
-
)
|
|
14900
|
+
writeCliConfigUpdate(
|
|
14901
|
+
dependencies.configStore,
|
|
14902
|
+
skillInstalls.length > 0 ? { skillInstalls } : { skillInstalls: void 0 }
|
|
14692
14903
|
);
|
|
14693
14904
|
} catch (error) {
|
|
14694
14905
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -15547,12 +15758,7 @@ function registerConfig({ program, dependencies }) {
|
|
|
15547
15758
|
});
|
|
15548
15759
|
config.command("set-upload-limit").description("Persist the file.upload size limit (raw bytes, pre-base64) for the daemon and CLI").argument("<size>", "Upload size limit as bytes or a size like 100MiB (max 512MiB)").action(function setUploadLimit(size) {
|
|
15549
15760
|
const uploadLimitBytes = parseUploadLimitBytes(size);
|
|
15550
|
-
|
|
15551
|
-
const nextConfig = mergePersistedCliConfig(persistedConfig, {
|
|
15552
|
-
daemonUrl: persistedConfig?.daemonUrl ?? DEFAULT_DAEMON_URL,
|
|
15553
|
-
uploadLimitBytes
|
|
15554
|
-
});
|
|
15555
|
-
dependencies.configStore.writeConfig(nextConfig);
|
|
15761
|
+
writeCliConfigUpdate(dependencies.configStore, { uploadLimitBytes });
|
|
15556
15762
|
const payload = {
|
|
15557
15763
|
configPath: dependencies.configStore.getConfigPath(),
|
|
15558
15764
|
uploadLimitBytes,
|
|
@@ -16680,6 +16886,12 @@ function registerPlaylist({ program, dependencies }) {
|
|
|
16680
16886
|
|
|
16681
16887
|
// src/commands/scene.ts
|
|
16682
16888
|
import { Option as Option11 } from "commander";
|
|
16889
|
+
function addSceneLevelScopeOption(command) {
|
|
16890
|
+
return command.requiredOption("--scene-id <sceneId>", "Scene id");
|
|
16891
|
+
}
|
|
16892
|
+
function addSceneLevelTargetOptions(command, levelDescription = "Level id") {
|
|
16893
|
+
return addSceneLevelScopeOption(command).requiredOption("--level-id <levelId>", levelDescription);
|
|
16894
|
+
}
|
|
16683
16895
|
function registerScene({ program, dependencies }) {
|
|
16684
16896
|
const { registerOwnershipSet, registerCompendiumImport, registerBatchWriteCommands } = createSharedRegistrars(dependencies);
|
|
16685
16897
|
const scene = program.command("scene").description("Foundry scene commands");
|
|
@@ -17255,6 +17467,58 @@ function registerScene({ program, dependencies }) {
|
|
|
17255
17467
|
});
|
|
17256
17468
|
});
|
|
17257
17469
|
registerBatchWriteCommands(sceneWall, { prefix: "scene.wall", noun: "wall" });
|
|
17470
|
+
const sceneLevel = scene.command("level").description("Scene level commands (Foundry v14)");
|
|
17471
|
+
addPaginationOptions(addSceneLevelScopeOption(sceneLevel.command("list"))).action(
|
|
17472
|
+
async function listSceneLevels(options) {
|
|
17473
|
+
await executeRemoteCommand({
|
|
17474
|
+
commandName: "scene.level.list",
|
|
17475
|
+
params: { sceneId: options.sceneId, ...paginationParams(options) },
|
|
17476
|
+
command: this,
|
|
17477
|
+
dependencies
|
|
17478
|
+
});
|
|
17479
|
+
}
|
|
17480
|
+
);
|
|
17481
|
+
addSceneLevelTargetOptions(sceneLevel.command("get")).action(async function getSceneLevel(options) {
|
|
17482
|
+
await executeRemoteCommand({
|
|
17483
|
+
commandName: "scene.level.get",
|
|
17484
|
+
params: { sceneId: options.sceneId, levelId: options.levelId },
|
|
17485
|
+
command: this,
|
|
17486
|
+
dependencies
|
|
17487
|
+
});
|
|
17488
|
+
});
|
|
17489
|
+
addSceneLevelScopeOption(addIdempotencyKeyOption(sceneLevel.command("create"))).option("--data-json <json>", "Level data as a JSON object (name is required; e.g. elevation/background)").action(async function createSceneLevel(options) {
|
|
17490
|
+
await executeRemoteCommand({
|
|
17491
|
+
commandName: "scene.level.create",
|
|
17492
|
+
params: createSceneLevelCreateParams(options),
|
|
17493
|
+
command: this,
|
|
17494
|
+
dependencies
|
|
17495
|
+
});
|
|
17496
|
+
});
|
|
17497
|
+
addSceneLevelTargetOptions(sceneLevel.command("update")).option("--patch-json <json>", "Level patch as a JSON object (e.g. background/foreground/elevation)").action(async function updateSceneLevel(options) {
|
|
17498
|
+
await executeRemoteCommand({
|
|
17499
|
+
commandName: "scene.level.update",
|
|
17500
|
+
params: createSceneLevelUpdateParams(options),
|
|
17501
|
+
command: this,
|
|
17502
|
+
dependencies
|
|
17503
|
+
});
|
|
17504
|
+
});
|
|
17505
|
+
addSceneLevelTargetOptions(addIdempotencyKeyOption(sceneLevel.command("clone")), "Source level id").option("--patch-json <json>", "Override fields for the clone as a JSON object").action(async function cloneSceneLevel(options) {
|
|
17506
|
+
await executeRemoteCommand({
|
|
17507
|
+
commandName: "scene.level.clone",
|
|
17508
|
+
params: createSceneLevelCloneParams(options),
|
|
17509
|
+
command: this,
|
|
17510
|
+
dependencies
|
|
17511
|
+
});
|
|
17512
|
+
});
|
|
17513
|
+
addSceneLevelTargetOptions(sceneLevel.command("delete")).action(async function deleteSceneLevel(options) {
|
|
17514
|
+
await executeRemoteCommand({
|
|
17515
|
+
commandName: "scene.level.delete",
|
|
17516
|
+
params: { sceneId: options.sceneId, levelId: options.levelId },
|
|
17517
|
+
command: this,
|
|
17518
|
+
dependencies
|
|
17519
|
+
});
|
|
17520
|
+
});
|
|
17521
|
+
registerBatchWriteCommands(sceneLevel, { prefix: "scene.level", noun: "level" });
|
|
17258
17522
|
const sceneNote = scene.command("note").description("Scene-embedded note (map pin) commands");
|
|
17259
17523
|
addPaginationOptions(sceneNote.command("list").requiredOption("--scene-id <sceneId>", "Scene id")).action(
|
|
17260
17524
|
async function listSceneNotes(options) {
|
|
@@ -18009,7 +18273,7 @@ function registerSystem({ program, dependencies }) {
|
|
|
18009
18273
|
const system = program.command("system").description("Foundry bridge system commands");
|
|
18010
18274
|
system.addHelpText(
|
|
18011
18275
|
"after",
|
|
18012
|
-
"\nResult key (--json): .result.pong + .result.bridge (ping); .result.foundry.* / .result.system.* / .result.world.* / .result.module.* / .result.modules[] / .result.bridge.* / .result.limits.*
|
|
18276
|
+
"\nResult key (--json): .result.pong + .result.bridge (ping); .result.foundry.* / .result.system.* / .result.world.* / .result.module.* / .result.moduleCount / .result.activeModuleCount / .result.modules[] (with --include modules) / .result.bridge.* / .result.limits.* (info)."
|
|
18013
18277
|
);
|
|
18014
18278
|
system.command("ping").action(async function ping() {
|
|
18015
18279
|
await executeRemoteCommand({
|
|
@@ -18019,10 +18283,14 @@ function registerSystem({ program, dependencies }) {
|
|
|
18019
18283
|
dependencies
|
|
18020
18284
|
});
|
|
18021
18285
|
});
|
|
18022
|
-
system.command("info").
|
|
18286
|
+
system.command("info").option(
|
|
18287
|
+
"--include <fields>",
|
|
18288
|
+
"Comma-separated extra fields (modules adds the installed module list)",
|
|
18289
|
+
parseSystemInfoIncludeFields
|
|
18290
|
+
).action(async function info(options) {
|
|
18023
18291
|
await executeRemoteCommand({
|
|
18024
18292
|
commandName: "system.info",
|
|
18025
|
-
params: {},
|
|
18293
|
+
params: options.include ? { include: options.include } : {},
|
|
18026
18294
|
command: this,
|
|
18027
18295
|
dependencies
|
|
18028
18296
|
});
|
package/docs/commands.md
CHANGED
|
@@ -29,6 +29,7 @@ Use these families to narrow your search, then check their help for supported op
|
|
|
29
29
|
| Edit world content | `actor`, `item`, `journal`, `scene`, `macro`, `playlist`, `table`, `cards` |
|
|
30
30
|
| Edit embedded content | Nested families such as `actor.item`, `playlist.sound`, `table.result`, and `*.effect` |
|
|
31
31
|
| Edit scene placeables | `scene.token`, `scene.wall`, `scene.region`, and related families |
|
|
32
|
+
| Edit scene levels (v14) | `scene.level` |
|
|
32
33
|
| Manage encounters | `combat`, `combat.combatant`, `combat.group` |
|
|
33
34
|
| Organize content and access | `folder`, `*.ownership.set`, `user` |
|
|
34
35
|
| Manage chat and settings | `chat`, `setting` |
|
|
@@ -63,6 +64,29 @@ fvtt-world-cli scene token list --scene-id <sceneId> --json
|
|
|
63
64
|
fvtt-world-cli scene token get --scene-id <sceneId> --token-id <tokenId> --json
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
### Build a scene with levels
|
|
68
|
+
|
|
69
|
+
On Foundry v14 a scene's maps live on its levels. Pass the levels when you create the scene:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
fvtt-world-cli scene create --name "Tower" --json \
|
|
73
|
+
--data-json '{"levels":[{"name":"Ground","background":{"src":"worlds/<worldId>/maps/ground.webp"}},
|
|
74
|
+
{"name":"Roof","elevation":{"bottom":20,"top":40}}]}'
|
|
75
|
+
fvtt-world-cli scene level list --scene-id <sceneId> --json
|
|
76
|
+
fvtt-world-cli scene level update --scene-id <sceneId> --level-id <levelId> \
|
|
77
|
+
--patch-json '{"foreground":{"src":"worlds/<worldId>/maps/roof.webp"}}' --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The first supplied level becomes the initial one. To start players on another level, run `scene
|
|
81
|
+
update --scene-id <sceneId> --initial-level <levelId>`; `--patch-json '{"initialLevel":null}'` goes
|
|
82
|
+
back to the first level. A scene keeps at least one level, so `scene level delete` and `delete-many`
|
|
83
|
+
refuse to remove the last one.
|
|
84
|
+
|
|
85
|
+
Deleting a level also deletes its tokens and every placeable that exists only on that level. A dry
|
|
86
|
+
run does not list them, so read the scene's placeables before deleting a level.
|
|
87
|
+
|
|
88
|
+
[Compatibility](compatibility.md) lists the scene map fields each Foundry version accepts.
|
|
89
|
+
|
|
66
90
|
### Send a batch of commands
|
|
67
91
|
|
|
68
92
|
Save these lines as `requests.ndjson`:
|
|
@@ -131,6 +155,9 @@ List rows contain fewer fields than `get` results. Read the target with `get` be
|
|
|
131
155
|
update. Reads return authored state; some commands accept `include` options for derived or expensive
|
|
132
156
|
data. Check the command's help for available projections and filters.
|
|
133
157
|
|
|
158
|
+
Actor results carry `itemCount` in place of the owned items; `actor get` and `actor get-many`
|
|
159
|
+
return the items with `--include items`. `system info --include modules` lists installed modules.
|
|
160
|
+
|
|
134
161
|
### Updates and merge semantics
|
|
135
162
|
|
|
136
163
|
Use JSON flags such as `--data-json` and `--patch-json` for structured values. Updates are patches:
|
|
@@ -207,7 +234,7 @@ inspect `auth pending`, then use `auth approve <code> --yes` for the selected re
|
|
|
207
234
|
|
|
208
235
|
| Command | Effect |
|
|
209
236
|
|---|---|
|
|
210
|
-
| `auth status` | Show bridge state and public profile metadata |
|
|
237
|
+
| `auth status` | Show bridge state, the commands the connected bridge advertised, and public profile metadata |
|
|
211
238
|
| `auth pending` | List pending codes, expiry, and browser/world/GM identity |
|
|
212
239
|
| `auth approve [code] [--yes]` | Approve a selected request; omit the code only when exactly one is pending |
|
|
213
240
|
| `auth deny <code>` | Reject a pending request |
|
package/docs/compatibility.md
CHANGED
|
@@ -6,6 +6,8 @@ The bridge supports Foundry VTT v13 and v14. Check your connected version with
|
|
|
6
6
|
| Area | v13 | v14 | What to do |
|
|
7
7
|
|---|---|---|---|
|
|
8
8
|
| Measured templates | Available | Removed from core | Use `scene.template` commands on v13. They are unavailable on v14. |
|
|
9
|
+
| Scene maps | One map per scene: `background`, `backgroundColor`, `foreground`, `foregroundElevation` and `fog.overlay` on the scene | Each level has its own map; the scene has `levels` and `initialLevel` | On v14, set maps through `levels` in `scene.create` or with `scene.level` commands. The scene-level map fields, including `fog.overlay`, are refused on v14, and `scene.level`, `levels` and `initialLevel` are refused on v13. |
|
|
10
|
+
| Placeable levels | Placeables have no level fields | A token sits on one `level`; tiles, walls, lights, sounds, notes, drawings and regions have a `levels` list, where an empty list means every level | On v14, read `level` or `levels` from placeable results to see what a level holds before deleting it. Placeable writes that set `level` or `levels` are refused on v13. |
|
|
9
11
|
| Scene thumbnail rendering | Renders the scene | Renders the scene's initial level by default | On v14, expect the initial level in the thumbnail. Check the returned dimensions and image. |
|
|
10
12
|
| Scene thumbnail files | Uses a stable scene-based filename | Uses a filename based on the image content | Use the returned path. On v14, a changed image can leave an older thumbnail file behind. |
|
|
11
13
|
| User permission names | `TEMPLATE_CREATE` | `REGION_CREATE` | Use the permission keys reported by the connected Foundry version when calling `user.permissions.set`. |
|
package/docs/protocol.md
CHANGED
|
@@ -178,7 +178,8 @@ The protocol package exports `REQUEST_SCHEMA` and `COMMAND_RESPONSE_SCHEMA` for
|
|
|
178
178
|
Document results use type-named keys and expose `id` as the public identifier. A source `_id`
|
|
179
179
|
mirror may accompany it. List responses use smaller projections than single-document reads;
|
|
180
180
|
filters apply before pagination. Previewed documents have no persistent identity, so an id
|
|
181
|
-
observed during a preview must not be reused.
|
|
181
|
+
observed during a preview must not be reused. Some result fields depend on the connected Foundry
|
|
182
|
+
version; [Foundry compatibility](compatibility.md) lists them.
|
|
182
183
|
|
|
183
184
|
Broadcast actions report `dispatched` and target users rather than a confirmed player-side result.
|
|
184
185
|
The active/inactive split is included where knowable.
|
|
@@ -341,8 +342,8 @@ The wait has two phases because the decision can outlast a normal request timeou
|
|
|
341
342
|
policy can change before dispatch.
|
|
342
343
|
|
|
343
344
|
The module supplies each opaque `approvalId`; callers do not construct one. Approval request schemas
|
|
344
|
-
are closed. `approval.await`, `approval.cancel`, and `policy.snapshot` do not appear in `commands
|
|
345
|
-
|
|
345
|
+
are closed. `approval.await`, `approval.cancel`, and `policy.snapshot` do not appear in `commands` or
|
|
346
|
+
bridge status. `schema <command>` still returns their schemas.
|
|
346
347
|
The bridge handshake advertises them because the daemon must forward them.
|
|
347
348
|
|
|
348
349
|
## Delivery states and retries
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fvtt-world-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Safe local CLI and authenticated bridge for automating live Foundry VTT worlds.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foundry-vtt",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"zod": "^3.24.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@fvtt-world-cli/protocol": "1.
|
|
59
|
+
"@fvtt-world-cli/protocol": "1.2.0"
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -75,6 +75,11 @@ A macro that throws fails `macro.execute` with a partial outcome — read what i
|
|
|
75
75
|
retrying — while a macro that catches its own errors still returns `null`, which proves nothing;
|
|
76
76
|
verify effects with reads, and treat `MACRO_TIMEOUT` as indeterminate — the macro may still be
|
|
77
77
|
running.
|
|
78
|
+
On Foundry v14 maps live on levels: pass `levels` in `scene.create`, then use `scene.level.*`;
|
|
79
|
+
level ids in a preview are provisional.
|
|
80
|
+
Deleting a level also deletes its tokens and every placeable only on that level, and the dry run
|
|
81
|
+
does not list them: read the scene's placeables (token `level`, others' `levels`) and tell the user
|
|
82
|
+
what the delete removes before running it.
|
|
78
83
|
`setting.set` cannot touch this module's own namespace (`SETTING_PROTECTED` is final; never retry).
|
|
79
84
|
When a setting write returns `requiresReload: true`, the change needs a GM-client reload to take
|
|
80
85
|
effect; `system.reload` performs it, drops the bridge, and requires a reconnect wait before the
|
|
@@ -135,7 +140,8 @@ details}}`, alongside `protocolVersion`, `type`, and the correlation `id` (echoi
|
|
|
135
140
|
Documents live under a type-named key inside `result` that varies between commands but is stable
|
|
136
141
|
for each one. `id` is the public identifier; a `_id` mirror may accompany it. Values requested
|
|
137
142
|
through `include` flags may be derived or version-dependent. Write them back only when the
|
|
138
|
-
update schema explicitly accepts them.
|
|
143
|
+
update schema explicitly accepts them. Actor reads return `itemCount` in place of owned items; add
|
|
144
|
+
`--include items` when the task needs them, or use `actor item list` and `actor item get`.
|
|
139
145
|
|
|
140
146
|
## Retry classification
|
|
141
147
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
248c52464e776236de6f937530e220dcb77b45a8b5cc754adbb4cfb4671a8c66
|