@crowdedkingdoms/crowdyjs 17.13.0-dev.1 → 18.0.0-dev.1
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/MIGRATION.md +163 -1
- package/README.md +142 -146
- package/dist/crowdy-client.d.ts +12 -31
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +15 -37
- package/dist/crowdy-dsh/bridge.d.ts.map +1 -1
- package/dist/crowdy-dsh/bridge.js +3 -6
- package/dist/crowdy-studio/controller.d.ts +59 -57
- package/dist/crowdy-studio/controller.d.ts.map +1 -1
- package/dist/crowdy-studio/controller.js +268 -206
- package/dist/crowdy-studio/diagnostics.d.ts +3 -12
- package/dist/crowdy-studio/diagnostics.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.d.ts +2 -4
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.js +16 -47
- package/dist/crowdy-studio/embed/hud-layer.d.ts +1 -1
- package/dist/crowdy-studio/embed/panel.d.ts +3 -12
- package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
- package/dist/crowdy-studio/embed/panel.js +3 -6
- package/dist/crowdy-studio/index.d.ts +1 -3
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/crowdy-studio/index.js +0 -2
- package/dist/crowdy-studio/models.d.ts +3 -4
- package/dist/crowdy-studio/models.d.ts.map +1 -1
- package/dist/crowdy-studio/starter-projects.d.ts +8 -4
- package/dist/crowdy-studio/starter-projects.d.ts.map +1 -1
- package/dist/crowdy-studio/starter-projects.js +83 -100
- package/dist/domains/appAccess.d.ts +14 -1
- package/dist/domains/appAccess.d.ts.map +1 -1
- package/dist/domains/appAccess.js +37 -1
- package/dist/domains/exec.d.ts +162 -15
- package/dist/domains/exec.d.ts.map +1 -1
- package/dist/domains/exec.js +180 -18
- package/dist/domains/host.d.ts +3 -3
- package/dist/domains/host.js +3 -3
- package/dist/domains/marketplace.d.ts +9 -58
- package/dist/domains/marketplace.d.ts.map +1 -1
- package/dist/domains/marketplace.js +9 -106
- package/dist/domains/playerWallet.d.ts +6 -12
- package/dist/domains/playerWallet.d.ts.map +1 -1
- package/dist/domains/playerWallet.js +6 -21
- package/dist/errors.d.ts +7 -13
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -10
- package/dist/generated/graphql.d.ts +1384 -7977
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +22 -321
- package/dist/grid-mods/exec-client-halves.d.ts +156 -0
- package/dist/grid-mods/exec-client-halves.d.ts.map +1 -0
- package/dist/grid-mods/exec-client-halves.js +356 -0
- package/dist/grid-mods/grid-host-calls.d.ts +29 -15
- package/dist/grid-mods/grid-host-calls.d.ts.map +1 -1
- package/dist/grid-mods/grid-host-calls.js +40 -44
- package/dist/grid-mods/index.d.ts +1 -0
- package/dist/grid-mods/index.d.ts.map +1 -1
- package/dist/grid-mods/index.js +1 -0
- package/dist/grid-mods/mod-runtime.d.ts +21 -6
- package/dist/grid-mods/mod-runtime.d.ts.map +1 -1
- package/dist/grid-mods/mod-runtime.js +6 -2
- package/dist/grid-scope.d.ts +0 -188
- package/dist/grid-scope.d.ts.map +1 -1
- package/dist/grid-scope.js +0 -69
- package/dist/index.d.ts +12 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -16
- package/dist/kit/actions.d.ts +5 -9
- package/dist/kit/actions.d.ts.map +1 -1
- package/dist/kit/actions.js +5 -9
- package/dist/kit/index.d.ts +2 -33
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +1 -32
- package/dist/kit/kit.d.ts +8 -208
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +5 -163
- package/dist/kit/social.d.ts +1 -3
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/kit/social.js +1 -3
- package/dist/kit/wire.d.ts +16 -5
- package/dist/kit/wire.d.ts.map +1 -1
- package/dist/kit/wire.js +19 -5
- package/dist/live-coding/assets/browser-authoring-index.json +1 -1
- package/dist/live-coding/assets/manifest.json +1 -1
- package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -1
- package/dist/live-coding/browser-authoring-index.generated.js +1496 -4386
- package/dist/live-coding/rust-analysis.d.ts.map +1 -1
- package/dist/live-coding/rust-analysis.js +31 -23
- package/dist/player-runtime/client-host-calls.d.ts +8 -0
- package/dist/player-runtime/client-host-calls.d.ts.map +1 -0
- package/dist/player-runtime/client-host-calls.js +28 -0
- package/dist/player-runtime/glue-runtime.d.ts +27 -10
- package/dist/player-runtime/glue-runtime.d.ts.map +1 -1
- package/dist/player-runtime/glue-runtime.js +40 -45
- package/dist/player-runtime/glue-sab.d.ts +2 -2
- package/dist/player-runtime/glue-sab.js +2 -2
- package/dist/player-runtime/player-code-broker.d.ts +80 -24
- package/dist/player-runtime/player-code-broker.d.ts.map +1 -1
- package/dist/player-runtime/player-code-broker.js +169 -41
- package/dist/player-runtime/player-glue-worker.d.ts +8 -8
- package/dist/player-runtime/player-glue-worker.d.ts.map +1 -1
- package/dist/player-runtime/player-glue-worker.js +26 -9
- package/dist/stores/actors.d.ts +12 -2
- package/dist/stores/actors.d.ts.map +1 -1
- package/dist/stores/actors.js +43 -18
- package/dist/stores/chunks.d.ts +12 -0
- package/dist/stores/chunks.d.ts.map +1 -1
- package/dist/stores/chunks.js +112 -39
- package/dist/stores/durable.d.ts.map +1 -1
- package/dist/stores/durable.js +2 -1
- package/dist/stores/inbox.d.ts +1 -1
- package/dist/stores/inbox.d.ts.map +1 -1
- package/dist/stores/index.d.ts +0 -11
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +0 -4
- package/dist/stores/session.d.ts +0 -2
- package/dist/stores/session.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/crowdy-studio/model-lint-log.d.ts +0 -76
- package/dist/crowdy-studio/model-lint-log.d.ts.map +0 -1
- package/dist/crowdy-studio/model-lint-log.js +0 -93
- package/dist/crowdy-studio/model-lint.d.ts +0 -61
- package/dist/crowdy-studio/model-lint.d.ts.map +0 -1
- package/dist/crowdy-studio/model-lint.js +0 -45
- package/dist/domains/compute.d.ts +0 -208
- package/dist/domains/compute.d.ts.map +0 -1
- package/dist/domains/compute.js +0 -274
- package/dist/domains/controlPlane.d.ts +0 -38
- package/dist/domains/controlPlane.d.ts.map +0 -1
- package/dist/domains/controlPlane.js +0 -43
- package/dist/domains/gameModel.d.ts +0 -1174
- package/dist/domains/gameModel.d.ts.map +0 -1
- package/dist/domains/gameModel.js +0 -1333
- package/dist/domains/playerCompute.d.ts +0 -91
- package/dist/domains/playerCompute.d.ts.map +0 -1
- package/dist/domains/playerCompute.js +0 -136
- package/dist/domains/playerModel.d.ts +0 -20
- package/dist/domains/playerModel.d.ts.map +0 -1
- package/dist/domains/playerModel.js +0 -54
- package/dist/kit/abilities.d.ts +0 -66
- package/dist/kit/abilities.d.ts.map +0 -1
- package/dist/kit/abilities.js +0 -71
- package/dist/kit/blueprints/combat.d.ts +0 -81
- package/dist/kit/blueprints/combat.d.ts.map +0 -1
- package/dist/kit/blueprints/combat.js +0 -357
- package/dist/kit/blueprints/core.d.ts +0 -222
- package/dist/kit/blueprints/core.d.ts.map +0 -1
- package/dist/kit/blueprints/core.js +0 -185
- package/dist/kit/blueprints/decks.d.ts +0 -50
- package/dist/kit/blueprints/decks.d.ts.map +0 -1
- package/dist/kit/blueprints/decks.js +0 -163
- package/dist/kit/blueprints/economy.d.ts +0 -88
- package/dist/kit/blueprints/economy.d.ts.map +0 -1
- package/dist/kit/blueprints/economy.js +0 -533
- package/dist/kit/blueprints/guild.d.ts +0 -51
- package/dist/kit/blueprints/guild.d.ts.map +0 -1
- package/dist/kit/blueprints/guild.js +0 -50
- package/dist/kit/blueprints/index.d.ts +0 -23
- package/dist/kit/blueprints/index.d.ts.map +0 -1
- package/dist/kit/blueprints/index.js +0 -22
- package/dist/kit/blueprints/inventory.d.ts +0 -84
- package/dist/kit/blueprints/inventory.d.ts.map +0 -1
- package/dist/kit/blueprints/inventory.js +0 -257
- package/dist/kit/blueprints/leaderboards.d.ts +0 -49
- package/dist/kit/blueprints/leaderboards.d.ts.map +0 -1
- package/dist/kit/blueprints/leaderboards.js +0 -126
- package/dist/kit/blueprints/liveops.d.ts +0 -42
- package/dist/kit/blueprints/liveops.d.ts.map +0 -1
- package/dist/kit/blueprints/liveops.js +0 -170
- package/dist/kit/blueprints/locks.d.ts +0 -82
- package/dist/kit/blueprints/locks.d.ts.map +0 -1
- package/dist/kit/blueprints/locks.js +0 -155
- package/dist/kit/blueprints/loot.d.ts +0 -90
- package/dist/kit/blueprints/loot.d.ts.map +0 -1
- package/dist/kit/blueprints/loot.js +0 -229
- package/dist/kit/blueprints/matches.d.ts +0 -84
- package/dist/kit/blueprints/matches.d.ts.map +0 -1
- package/dist/kit/blueprints/matches.js +0 -349
- package/dist/kit/blueprints/moderation.d.ts +0 -32
- package/dist/kit/blueprints/moderation.d.ts.map +0 -1
- package/dist/kit/blueprints/moderation.js +0 -140
- package/dist/kit/blueprints/npcs.d.ts +0 -78
- package/dist/kit/blueprints/npcs.d.ts.map +0 -1
- package/dist/kit/blueprints/npcs.js +0 -125
- package/dist/kit/blueprints/plots.d.ts +0 -63
- package/dist/kit/blueprints/plots.d.ts.map +0 -1
- package/dist/kit/blueprints/plots.js +0 -151
- package/dist/kit/blueprints/progression.d.ts +0 -68
- package/dist/kit/blueprints/progression.d.ts.map +0 -1
- package/dist/kit/blueprints/progression.js +0 -324
- package/dist/kit/blueprints/quests.d.ts +0 -72
- package/dist/kit/blueprints/quests.d.ts.map +0 -1
- package/dist/kit/blueprints/quests.js +0 -285
- package/dist/kit/blueprints/worldsim.d.ts +0 -91
- package/dist/kit/blueprints/worldsim.d.ts.map +0 -1
- package/dist/kit/blueprints/worldsim.js +0 -468
- package/dist/kit/combat.d.ts +0 -141
- package/dist/kit/combat.d.ts.map +0 -1
- package/dist/kit/combat.js +0 -196
- package/dist/kit/decks.d.ts +0 -157
- package/dist/kit/decks.d.ts.map +0 -1
- package/dist/kit/decks.js +0 -186
- package/dist/kit/director.d.ts +0 -88
- package/dist/kit/director.d.ts.map +0 -1
- package/dist/kit/director.js +0 -86
- package/dist/kit/economy.d.ts +0 -289
- package/dist/kit/economy.d.ts.map +0 -1
- package/dist/kit/economy.js +0 -427
- package/dist/kit/engine.d.ts +0 -48
- package/dist/kit/engine.d.ts.map +0 -1
- package/dist/kit/engine.js +0 -113
- package/dist/kit/features.d.ts +0 -60
- package/dist/kit/features.d.ts.map +0 -1
- package/dist/kit/features.js +0 -65
- package/dist/kit/instances.d.ts +0 -52
- package/dist/kit/instances.d.ts.map +0 -1
- package/dist/kit/instances.js +0 -60
- package/dist/kit/inventory.d.ts +0 -129
- package/dist/kit/inventory.d.ts.map +0 -1
- package/dist/kit/inventory.js +0 -200
- package/dist/kit/leaderboards.d.ts +0 -86
- package/dist/kit/leaderboards.d.ts.map +0 -1
- package/dist/kit/leaderboards.js +0 -133
- package/dist/kit/liveops.d.ts +0 -112
- package/dist/kit/liveops.d.ts.map +0 -1
- package/dist/kit/liveops.js +0 -183
- package/dist/kit/loot.d.ts +0 -128
- package/dist/kit/loot.d.ts.map +0 -1
- package/dist/kit/loot.js +0 -160
- package/dist/kit/matches.d.ts +0 -301
- package/dist/kit/matches.d.ts.map +0 -1
- package/dist/kit/matches.js +0 -458
- package/dist/kit/matchmaking.d.ts +0 -57
- package/dist/kit/matchmaking.d.ts.map +0 -1
- package/dist/kit/matchmaking.js +0 -59
- package/dist/kit/minigames.d.ts +0 -30
- package/dist/kit/minigames.d.ts.map +0 -1
- package/dist/kit/minigames.js +0 -38
- package/dist/kit/mobs.d.ts +0 -90
- package/dist/kit/mobs.d.ts.map +0 -1
- package/dist/kit/mobs.js +0 -98
- package/dist/kit/moderation.d.ts +0 -73
- package/dist/kit/moderation.d.ts.map +0 -1
- package/dist/kit/moderation.js +0 -103
- package/dist/kit/movement.d.ts +0 -78
- package/dist/kit/movement.d.ts.map +0 -1
- package/dist/kit/movement.js +0 -103
- package/dist/kit/notifications.d.ts +0 -45
- package/dist/kit/notifications.d.ts.map +0 -1
- package/dist/kit/notifications.js +0 -67
- package/dist/kit/npcs.d.ts +0 -226
- package/dist/kit/npcs.d.ts.map +0 -1
- package/dist/kit/npcs.js +0 -141
- package/dist/kit/objects.d.ts +0 -116
- package/dist/kit/objects.d.ts.map +0 -1
- package/dist/kit/objects.js +0 -119
- package/dist/kit/pets.d.ts +0 -85
- package/dist/kit/pets.d.ts.map +0 -1
- package/dist/kit/pets.js +0 -96
- package/dist/kit/plots.d.ts +0 -85
- package/dist/kit/plots.d.ts.map +0 -1
- package/dist/kit/plots.js +0 -113
- package/dist/kit/progression.d.ts +0 -181
- package/dist/kit/progression.d.ts.map +0 -1
- package/dist/kit/progression.js +0 -265
- package/dist/kit/quests.d.ts +0 -171
- package/dist/kit/quests.d.ts.map +0 -1
- package/dist/kit/quests.js +0 -237
- package/dist/kit/racing.d.ts +0 -85
- package/dist/kit/racing.d.ts.map +0 -1
- package/dist/kit/racing.js +0 -99
- package/dist/kit/shared.d.ts +0 -73
- package/dist/kit/shared.d.ts.map +0 -1
- package/dist/kit/shared.js +0 -101
- package/dist/kit/telemetry.d.ts +0 -66
- package/dist/kit/telemetry.d.ts.map +0 -1
- package/dist/kit/telemetry.js +0 -133
- package/dist/kit/territory.d.ts +0 -97
- package/dist/kit/territory.d.ts.map +0 -1
- package/dist/kit/territory.js +0 -114
- package/dist/kit/worldsim.d.ts +0 -263
- package/dist/kit/worldsim.d.ts.map +0 -1
- package/dist/kit/worldsim.js +0 -268
- package/dist/stores/model.d.ts +0 -81
- package/dist/stores/model.d.ts.map +0 -1
- package/dist/stores/model.js +0 -163
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { PlayerCodeBroker, } from '../player-runtime/player-code-broker.js';
|
|
2
|
+
import { CrowdyError, CrowdyGraphQLError } from '../errors.js';
|
|
2
3
|
import { digestCanonicalJson, sha256Digest, } from '../player-host/json-schema.js';
|
|
3
4
|
import { parseRustcDiagnostics } from './diagnostics.js';
|
|
4
5
|
import { githubNewRepositoryUrl, githubRepositorySlug } from './github/new-repo.js';
|
|
5
6
|
import { cloneCrowdyStudioProject, crowdyStudioFileKey, normalizeCrowdyStudioPath, projectTargets, CrowdyStudioOfflineError, CrowdyStudioRevisionConflictError, } from './models.js';
|
|
6
|
-
import { parseClientTickIntervalMs } from './client-tick-interval.js';
|
|
7
7
|
import { createCrowdyStudioStarterProject, } from './starter-projects.js';
|
|
8
8
|
/** As ck-exec's mod names. */
|
|
9
9
|
const MOD_NAME = /^[a-z0-9_-]{1,48}$/;
|
|
10
10
|
/** As a ck-exec build's crate names. */
|
|
11
11
|
const CRATE_NAME = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
12
|
+
/** ck-exec's server log levels (`ExecLogLine.level`); a CLIENT half's are crowdy-client-sdk's. */
|
|
12
13
|
const LOG_LEVELS = ['error', 'warn', 'info', 'debug'];
|
|
14
|
+
const PREVIEW_LOG_LINES_KEPT = 100;
|
|
13
15
|
class OperationCancelledError extends Error {
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
@@ -21,7 +23,6 @@ export class CrowdyStudioController {
|
|
|
21
23
|
constructor(options) {
|
|
22
24
|
this.options = options;
|
|
23
25
|
this.state = {
|
|
24
|
-
serverEngine: 'player-compute',
|
|
25
26
|
projects: [],
|
|
26
27
|
project: null,
|
|
27
28
|
personalLibraryFiles: [],
|
|
@@ -38,9 +39,7 @@ export class CrowdyStudioController {
|
|
|
38
39
|
buildOutput: '',
|
|
39
40
|
authoritativeDiagnostics: [],
|
|
40
41
|
localDiagnostics: [],
|
|
41
|
-
runs: [],
|
|
42
42
|
logs: [],
|
|
43
|
-
usage: null,
|
|
44
43
|
wallet: null,
|
|
45
44
|
invokeResult: null,
|
|
46
45
|
};
|
|
@@ -60,14 +59,15 @@ export class CrowdyStudioController {
|
|
|
60
59
|
this.pageVisible = true;
|
|
61
60
|
this.destroyed = false;
|
|
62
61
|
this.modConnection = null;
|
|
62
|
+
this.modLogLines = [];
|
|
63
|
+
this.previewLogLines = [];
|
|
64
|
+
this.previewLogSeq = 0;
|
|
63
65
|
// ----- GitHub repository card ------------------------------------------
|
|
64
66
|
this.githubStatusGeneration = 0;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
throw new Error("serverEngine 'ck-exec' needs the mods option (client.exec)");
|
|
67
|
+
if (!options.mods) {
|
|
68
|
+
throw new Error('Crowdy Studio needs mods (client.exec): the SERVER target runs as a ck-exec mod');
|
|
68
69
|
}
|
|
69
|
-
this.mods =
|
|
70
|
-
this.state = { ...this.state, serverEngine };
|
|
70
|
+
this.mods = options.mods;
|
|
71
71
|
if (options.onStateChange)
|
|
72
72
|
this.listeners.add(options.onStateChange);
|
|
73
73
|
}
|
|
@@ -197,7 +197,7 @@ export class CrowdyStudioController {
|
|
|
197
197
|
if (this.state.project && !(await this.saveNow())) {
|
|
198
198
|
throw new Error('Resolve or retry the current project save before creating another');
|
|
199
199
|
}
|
|
200
|
-
const modStarter =
|
|
200
|
+
const modStarter = projectTargets(options.kind).includes('SERVER')
|
|
201
201
|
? await this.mods.modStarter(this.options.appId)
|
|
202
202
|
: undefined;
|
|
203
203
|
const input = createCrowdyStudioStarterProject({
|
|
@@ -293,8 +293,7 @@ export class CrowdyStudioController {
|
|
|
293
293
|
buildOutput: '',
|
|
294
294
|
authoritativeDiagnostics: [],
|
|
295
295
|
localDiagnostics: [],
|
|
296
|
-
|
|
297
|
-
logs: [],
|
|
296
|
+
logs: this.clearLogLines(),
|
|
298
297
|
invokeResult: null,
|
|
299
298
|
github: null,
|
|
300
299
|
githubMessage: undefined,
|
|
@@ -431,13 +430,10 @@ export class CrowdyStudioController {
|
|
|
431
430
|
project.metadata = {
|
|
432
431
|
...project.metadata,
|
|
433
432
|
...patch,
|
|
434
|
-
pairingPreference:
|
|
433
|
+
pairingPreference: project.metadata.pairingPreference,
|
|
435
434
|
};
|
|
436
435
|
this.markEdited();
|
|
437
436
|
}
|
|
438
|
-
setPairingPreference(preference) {
|
|
439
|
-
this.updateSettings({ pairingPreference: preference });
|
|
440
|
-
}
|
|
441
437
|
setLocalDiagnostics(diagnostics) {
|
|
442
438
|
this.update({ localDiagnostics: [...diagnostics] });
|
|
443
439
|
}
|
|
@@ -864,7 +860,7 @@ export class CrowdyStudioController {
|
|
|
864
860
|
try {
|
|
865
861
|
if (targets.length === 1) {
|
|
866
862
|
const target = targets[0];
|
|
867
|
-
const compiled = await this.compileTarget(project, target,
|
|
863
|
+
const compiled = await this.compileTarget(project, target, operation);
|
|
868
864
|
if (!compiled) {
|
|
869
865
|
return {
|
|
870
866
|
deployment: draft ? 'DRAFT' : 'LIVE',
|
|
@@ -883,8 +879,8 @@ export class CrowdyStudioController {
|
|
|
883
879
|
}
|
|
884
880
|
else {
|
|
885
881
|
// Compile the client first so a client failure never publishes a new
|
|
886
|
-
// server version
|
|
887
|
-
const client = await this.compileTarget(project, 'CLIENT',
|
|
882
|
+
// server version.
|
|
883
|
+
const client = await this.compileTarget(project, 'CLIENT', operation);
|
|
888
884
|
if (!client) {
|
|
889
885
|
return {
|
|
890
886
|
deployment: draft ? 'DRAFT' : 'LIVE',
|
|
@@ -894,7 +890,7 @@ export class CrowdyStudioController {
|
|
|
894
890
|
message: this.state.runtime.message ?? 'Client compilation failed',
|
|
895
891
|
};
|
|
896
892
|
}
|
|
897
|
-
const server = await this.compileTarget(project, 'SERVER',
|
|
893
|
+
const server = await this.compileTarget(project, 'SERVER', operation);
|
|
898
894
|
if (!server) {
|
|
899
895
|
return {
|
|
900
896
|
deployment: draft ? 'DRAFT' : 'LIVE',
|
|
@@ -906,17 +902,6 @@ export class CrowdyStudioController {
|
|
|
906
902
|
}
|
|
907
903
|
this.checkOperation(operation);
|
|
908
904
|
// A mod has no client pairing: its players call it by name.
|
|
909
|
-
if (!this.mods) {
|
|
910
|
-
const requiredClientName = project.metadata.pairingPreference === 'REQUIRED'
|
|
911
|
-
? client.name
|
|
912
|
-
: null;
|
|
913
|
-
await this.options.playerCompute.setRequires({
|
|
914
|
-
...this.scope(),
|
|
915
|
-
serverName: server.name,
|
|
916
|
-
requiredClientName,
|
|
917
|
-
});
|
|
918
|
-
this.checkOperation(operation);
|
|
919
|
-
}
|
|
920
905
|
await this.enableServer(server.name, operation);
|
|
921
906
|
await this.runClient(client, operation);
|
|
922
907
|
}
|
|
@@ -967,7 +952,7 @@ export class CrowdyStudioController {
|
|
|
967
952
|
}
|
|
968
953
|
}
|
|
969
954
|
}
|
|
970
|
-
async compileTarget(project, target,
|
|
955
|
+
async compileTarget(project, target, operation) {
|
|
971
956
|
if (!this.canTarget(target, 'write')) {
|
|
972
957
|
throw new Error(`${target} authoring is unavailable on this grid`);
|
|
973
958
|
}
|
|
@@ -982,39 +967,76 @@ export class CrowdyStudioController {
|
|
|
982
967
|
message: `Submitting ${name}`,
|
|
983
968
|
},
|
|
984
969
|
});
|
|
985
|
-
|
|
986
|
-
|
|
970
|
+
return target === 'SERVER'
|
|
971
|
+
? this.buildMod(name, files, operation)
|
|
972
|
+
: this.buildClientHalf(name, files, operation);
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* The SERVER target as a ck-exec mod: the project's server crate files, built on the
|
|
976
|
+
* platform, then deployed to this grid (switched off until {@link enableServer}). Other
|
|
977
|
+
* project files, such as grid program assets, are not part of the crate.
|
|
978
|
+
*/
|
|
979
|
+
async buildMod(name, files, operation) {
|
|
980
|
+
const mods = this.mods;
|
|
981
|
+
const problem = modNameProblem(this.requireProject());
|
|
982
|
+
if (problem)
|
|
983
|
+
throw new Error(problem);
|
|
984
|
+
const { appId, gridId } = this.scope();
|
|
985
|
+
const queued = await mods.modBuild(appId, {
|
|
986
|
+
name: crateName(name),
|
|
987
|
+
files: crateFiles(files),
|
|
988
|
+
});
|
|
989
|
+
this.checkOperation(operation);
|
|
990
|
+
const built = await this.awaitModBuild('SERVER', name, queued.buildId, operation);
|
|
991
|
+
if (!built)
|
|
992
|
+
return null;
|
|
993
|
+
const mod = await mods.modDeploy(appId, gridId, name, built.buildId);
|
|
994
|
+
this.checkOperation(operation);
|
|
995
|
+
return { target: 'SERVER', name, versionId: String(mod.version) };
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* The CLIENT target as a ck-exec mod's CLIENT half: the project's `crowdy-client-sdk` crate,
|
|
999
|
+
* built on the platform (`modClientBuild`, a build of `kind` `client`). It is attached to the
|
|
1000
|
+
* project's mod when the project runs ({@link attachClientHalf}).
|
|
1001
|
+
*/
|
|
1002
|
+
async buildClientHalf(name, files, operation) {
|
|
1003
|
+
const problem = modNameProblem(this.requireProject());
|
|
1004
|
+
if (problem)
|
|
1005
|
+
throw new Error(problem);
|
|
1006
|
+
const cargo = files.find((file) => file.path === 'Cargo.toml')?.content ?? '';
|
|
1007
|
+
if (/^\s*crowdy-compute-sdk\s*=/m.test(cargo)) {
|
|
1008
|
+
this.recordBuild('CLIENT', LEGACY_CLIENT_CRATE);
|
|
1009
|
+
this.update({
|
|
1010
|
+
runtime: {
|
|
1011
|
+
phase: 'COMPILE_FAILED',
|
|
1012
|
+
target: 'CLIENT',
|
|
1013
|
+
message: `${name} is a legacy player compute crate; a CLIENT half builds on crowdy-client-sdk`,
|
|
1014
|
+
},
|
|
1015
|
+
});
|
|
1016
|
+
return null;
|
|
987
1017
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
const deployed = await this.options.playerCompute.deploy({
|
|
992
|
-
...this.scope(),
|
|
993
|
-
projectId: project.projectId,
|
|
994
|
-
name,
|
|
995
|
-
target: target,
|
|
996
|
-
...(project.github?.sha ? { commitSha: project.github.sha } : {}),
|
|
997
|
-
tickHz: target === 'SERVER' ? 1 : undefined,
|
|
998
|
-
draft,
|
|
1018
|
+
const queued = await this.mods.modClientBuild(this.options.appId, {
|
|
1019
|
+
name: crateName(name),
|
|
1020
|
+
files: crateFiles(files),
|
|
999
1021
|
});
|
|
1000
1022
|
this.checkOperation(operation);
|
|
1023
|
+
const built = await this.awaitModBuild('CLIENT', name, queued.buildId, operation);
|
|
1024
|
+
return built ? { target: 'CLIENT', name, versionId: built.buildId } : null;
|
|
1025
|
+
}
|
|
1026
|
+
/** Polls a mod build, a mod's or a CLIENT half's, recording its log; null when it did not succeed. */
|
|
1027
|
+
async awaitModBuild(target, name, buildId, operation) {
|
|
1028
|
+
const mods = this.mods;
|
|
1001
1029
|
const limit = this.options.compilePollLimit ?? 60;
|
|
1002
1030
|
const pollMs = this.options.compilePollMs ?? 1500;
|
|
1003
1031
|
for (let attempt = 0; attempt < limit; attempt++) {
|
|
1004
|
-
const
|
|
1005
|
-
...this.scope(),
|
|
1006
|
-
name,
|
|
1007
|
-
});
|
|
1032
|
+
const b = await mods.modBuildStatus(this.options.appId, buildId);
|
|
1008
1033
|
this.checkOperation(operation);
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
this.recordBuild(target, version?.compileLog ?? '');
|
|
1013
|
-
return { target, name, versionId: deployed.versionId };
|
|
1034
|
+
if (b.status === 'succeeded') {
|
|
1035
|
+
this.recordBuild(target, b.log ?? '');
|
|
1036
|
+
return b;
|
|
1014
1037
|
}
|
|
1015
|
-
if (status === 'failed'
|
|
1016
|
-
|
|
1017
|
-
this.recordBuild(target, log);
|
|
1038
|
+
if (b.status === 'failed') {
|
|
1039
|
+
this.recordBuild(target, b.log ?? 'Compilation failed without output');
|
|
1018
1040
|
this.update({
|
|
1019
1041
|
runtime: {
|
|
1020
1042
|
phase: 'COMPILE_FAILED',
|
|
@@ -1035,54 +1057,98 @@ export class CrowdyStudioController {
|
|
|
1035
1057
|
return null;
|
|
1036
1058
|
}
|
|
1037
1059
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1060
|
+
* Attaches a built CLIENT half to the project's mod, consents to it as its author (the API
|
|
1061
|
+
* serves a CLIENT half only to a player who consented or trusts its author, the author too) and
|
|
1062
|
+
* fetches the served module for this browser's preview. A CLIENT-only project first makes sure
|
|
1063
|
+
* the mod it rides is the player's and switched on.
|
|
1041
1064
|
*/
|
|
1042
|
-
async
|
|
1065
|
+
async attachClientHalf(compiled, operation) {
|
|
1043
1066
|
const mods = this.mods;
|
|
1044
|
-
if (!MOD_NAME.test(name)) {
|
|
1045
|
-
throw new Error(`The server module name '${name}' must be 1-48 lowercase letters, digits, - or _ to run as a mod`);
|
|
1046
|
-
}
|
|
1047
1067
|
const { appId, gridId } = this.scope();
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1068
|
+
const project = this.requireProject();
|
|
1069
|
+
const modName = projectModName(project);
|
|
1070
|
+
if (!projectTargets(project.kind).includes('SERVER')) {
|
|
1071
|
+
await this.ensureClientOnlyMod(modName, operation);
|
|
1072
|
+
}
|
|
1073
|
+
this.update({
|
|
1074
|
+
runtime: { phase: 'ENABLING', target: 'CLIENT', message: `Attaching ${compiled.name} to ${modName}` },
|
|
1053
1075
|
});
|
|
1076
|
+
const attached = await mods.modClientDeploy(appId, gridId, modName, compiled.versionId);
|
|
1054
1077
|
this.checkOperation(operation);
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1078
|
+
await mods.consentClientMod(appId, attached.modId, attached.capabilityHash);
|
|
1079
|
+
this.checkOperation(operation);
|
|
1080
|
+
this.recordNote('CLIENT', `Attached to mod '${modName}' as CLIENT version ${attached.clientVersion} (capabilities ` +
|
|
1081
|
+
`${attached.capabilityHash}; ticks every ${attached.tickIntervalMs} ms). Visitors of grid ` +
|
|
1082
|
+
`${gridId} run it once they consent to it or trust you; you consented to it as its author.`);
|
|
1083
|
+
let artifact;
|
|
1084
|
+
try {
|
|
1085
|
+
artifact = await mods.modClientArtifactBytes(appId, attached.modId);
|
|
1086
|
+
}
|
|
1087
|
+
catch (error) {
|
|
1088
|
+
if (error instanceof CrowdyGraphQLError && error.code === 'NOT_FOUND') {
|
|
1089
|
+
throw new CrowdyError({
|
|
1090
|
+
message: `${compiled.name} is attached to mod '${modName}', but its preview did not load: the ` +
|
|
1091
|
+
'API serves a CLIENT half only while its mod is switched on and not held, to a player ' +
|
|
1092
|
+
`with run_client_code who stands in grid ${gridId}`,
|
|
1093
|
+
cause: error,
|
|
1094
|
+
});
|
|
1065
1095
|
}
|
|
1066
|
-
if (
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
target: 'SERVER',
|
|
1072
|
-
message: `${name} failed to compile`,
|
|
1073
|
-
},
|
|
1096
|
+
if (error instanceof CrowdyGraphQLError && error.code === 'RATE_LIMITED') {
|
|
1097
|
+
throw new CrowdyError({
|
|
1098
|
+
message: `${compiled.name} is attached to mod '${modName}', but its preview was fetched too ` +
|
|
1099
|
+
'often (12 a minute); deploy again in a minute',
|
|
1100
|
+
cause: error,
|
|
1074
1101
|
});
|
|
1075
|
-
return null;
|
|
1076
1102
|
}
|
|
1077
|
-
|
|
1103
|
+
throw error;
|
|
1104
|
+
}
|
|
1105
|
+
this.checkOperation(operation);
|
|
1106
|
+
if (artifact.digest !== attached.digest || artifact.clientVersion !== attached.clientVersion) {
|
|
1107
|
+
throw new Error('The served CLIENT half is not the one just attached; deploy again');
|
|
1108
|
+
}
|
|
1109
|
+
return artifact;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* A CLIENT half rides a mod: without a mod of this name running as the player on the grid,
|
|
1113
|
+
* the mod starter's server half is deployed under it first, and the log says so. The mod is
|
|
1114
|
+
* switched on, since only a running mod's CLIENT half is served.
|
|
1115
|
+
*/
|
|
1116
|
+
async ensureClientOnlyMod(name, operation) {
|
|
1117
|
+
const mods = this.mods;
|
|
1118
|
+
const { appId, gridId } = this.scope();
|
|
1119
|
+
const mine = (await mods.myMods(appId)).find((mod) => String(mod.gridId) === gridId && mod.name === name);
|
|
1120
|
+
this.checkOperation(operation);
|
|
1121
|
+
if (!mine) {
|
|
1122
|
+
if (!this.canTarget('SERVER', 'write') || !this.canTarget('SERVER', 'run')) {
|
|
1123
|
+
throw new Error(`A CLIENT half rides a mod, and grid ${gridId} has no mod '${name}' of yours; deploying one needs SERVER write and run permissions here`);
|
|
1124
|
+
}
|
|
1125
|
+
this.update({
|
|
1126
|
+
runtime: { phase: 'COMPILING', target: 'SERVER', message: `Deploying the mod starter as ${name}` },
|
|
1127
|
+
});
|
|
1128
|
+
const starter = await mods.modStarter(appId);
|
|
1078
1129
|
this.checkOperation(operation);
|
|
1130
|
+
const queued = await mods.modBuild(appId, { name: crateName(name), files: starter.files });
|
|
1131
|
+
this.checkOperation(operation);
|
|
1132
|
+
const built = await this.awaitModBuild('SERVER', name, queued.buildId, operation);
|
|
1133
|
+
if (!built) {
|
|
1134
|
+
throw new Error(`The mod starter did not build, so the CLIENT half has no mod '${name}' to ride`);
|
|
1135
|
+
}
|
|
1136
|
+
await mods.modDeploy(appId, gridId, name, built.buildId);
|
|
1137
|
+
this.checkOperation(operation);
|
|
1138
|
+
this.recordNote('SERVER', `Grid ${gridId} had no mod '${name}' of yours, and a CLIENT half rides a mod: deployed the ` +
|
|
1139
|
+
`ck-exec mod starter (${starter.crate}) as '${name}', its server half.`);
|
|
1079
1140
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1141
|
+
if (!mine?.enabled) {
|
|
1142
|
+
await mods.modSetEnabled(appId, gridId, name, true);
|
|
1143
|
+
this.checkOperation(operation);
|
|
1144
|
+
if (mine)
|
|
1145
|
+
this.recordNote('SERVER', `Switched mod '${name}' on, so its CLIENT half is served.`);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
recordNote(target, note) {
|
|
1082
1149
|
this.update({
|
|
1083
|
-
|
|
1150
|
+
buildOutput: [this.state.buildOutput, `## ${target}\n${note}`].filter(Boolean).join('\n\n'),
|
|
1084
1151
|
});
|
|
1085
|
-
return null;
|
|
1086
1152
|
}
|
|
1087
1153
|
recordBuild(target, log) {
|
|
1088
1154
|
const section = `## ${target}\n${log || 'Compiled successfully.'}`;
|
|
@@ -1106,44 +1172,35 @@ export class CrowdyStudioController {
|
|
|
1106
1172
|
this.checkOperation(operation);
|
|
1107
1173
|
}
|
|
1108
1174
|
async setServerEnabled(name, enabled) {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
await this.mods.modSetEnabled(appId, gridId, name, enabled);
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1114
|
-
await this.options.playerCompute.setEnabled({
|
|
1115
|
-
...this.scope(),
|
|
1116
|
-
name,
|
|
1117
|
-
enabled,
|
|
1118
|
-
});
|
|
1175
|
+
const { appId, gridId } = this.scope();
|
|
1176
|
+
await this.mods.modSetEnabled(appId, gridId, name, enabled);
|
|
1119
1177
|
}
|
|
1120
1178
|
async runClient(compiled, operation) {
|
|
1121
1179
|
if (!this.canTarget('CLIENT', 'run')) {
|
|
1122
1180
|
throw new Error(`${compiled.name} compiled successfully, but run_client_code is unavailable on this grid`);
|
|
1123
1181
|
}
|
|
1124
1182
|
const runtime = this.clientRuntimeOptions();
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
name: compiled.name,
|
|
1128
|
-
versionId: compiled.versionId,
|
|
1129
|
-
});
|
|
1130
|
-
this.checkOperation(operation);
|
|
1131
|
-
if (artifact.versionId !== compiled.versionId ||
|
|
1132
|
-
!artifact.artifactHash ||
|
|
1133
|
-
artifact.bytes.byteLength === 0) {
|
|
1134
|
-
throw new Error('Client artifact did not match the compiled project version');
|
|
1135
|
-
}
|
|
1183
|
+
const half = await this.attachClientHalf(compiled, operation);
|
|
1184
|
+
let broker = null;
|
|
1136
1185
|
const brokerOptions = {
|
|
1137
1186
|
...runtime,
|
|
1138
|
-
|
|
1139
|
-
|
|
1187
|
+
engine: 'ck-exec',
|
|
1188
|
+
moduleName: half.name,
|
|
1189
|
+
artifactHash: half.digest,
|
|
1190
|
+
fuelPerDispatch: half.fuelPerDispatch,
|
|
1191
|
+
consentedHostCalls: half.capabilitySummary.hostFunctions,
|
|
1140
1192
|
onPresentation: this.options.onPresentation,
|
|
1141
|
-
|
|
1142
|
-
|
|
1193
|
+
// Only the preview running now logs into the project's Logs.
|
|
1194
|
+
onLog: (line) => {
|
|
1195
|
+
if (broker && this.broker === broker)
|
|
1196
|
+
this.recordPreviewLog(compiled.name, line);
|
|
1197
|
+
},
|
|
1198
|
+
tickIntervalMs: this.options.clientTickIntervalMs ?? half.tickIntervalMs,
|
|
1143
1199
|
};
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1200
|
+
broker =
|
|
1201
|
+
this.options.brokerFactory?.(brokerOptions) ??
|
|
1202
|
+
new PlayerCodeBroker(brokerOptions);
|
|
1203
|
+
await broker.start(half.bytes);
|
|
1147
1204
|
this.checkOperation(operation);
|
|
1148
1205
|
const previous = this.broker;
|
|
1149
1206
|
this.broker = broker;
|
|
@@ -1170,15 +1227,15 @@ export class CrowdyStudioController {
|
|
|
1170
1227
|
this.broker = null;
|
|
1171
1228
|
}
|
|
1172
1229
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
}
|
|
1230
|
+
// A CLIENT-only project's CLIENT half rides a mod too: switched off, it is no longer served
|
|
1231
|
+
// to visitors.
|
|
1232
|
+
serverStopped = false;
|
|
1233
|
+
try {
|
|
1234
|
+
await this.setServerEnabled(projectModName(project), false);
|
|
1235
|
+
serverStopped = true;
|
|
1236
|
+
}
|
|
1237
|
+
catch (error) {
|
|
1238
|
+
failures.push(`Server: ${errorMessage(error)}`);
|
|
1182
1239
|
}
|
|
1183
1240
|
const result = { serverStopped, clientStopped, failures };
|
|
1184
1241
|
this.update({
|
|
@@ -1201,18 +1258,7 @@ export class CrowdyStudioController {
|
|
|
1201
1258
|
if (!projectTargets(project.kind).includes('SERVER')) {
|
|
1202
1259
|
throw new Error('Invoke requires a SERVER target');
|
|
1203
1260
|
}
|
|
1204
|
-
|
|
1205
|
-
const result = await this.callMod(moduleNameFor(project, 'SERVER'), exportName.trim() || 'state', paramsJson);
|
|
1206
|
-
this.checkAgentOperation(agentOperation);
|
|
1207
|
-
this.update({ invokeResult: result });
|
|
1208
|
-
return result;
|
|
1209
|
-
}
|
|
1210
|
-
const result = await this.options.playerCompute.invoke({
|
|
1211
|
-
...this.scope(),
|
|
1212
|
-
moduleName: moduleNameFor(project, 'SERVER'),
|
|
1213
|
-
exportName: exportName.trim() || 'invoke',
|
|
1214
|
-
paramsJson: paramsJson?.trim() || null,
|
|
1215
|
-
});
|
|
1261
|
+
const result = await this.callMod(moduleNameFor(project, 'SERVER'), exportName.trim() || 'state', paramsJson);
|
|
1216
1262
|
this.checkAgentOperation(agentOperation);
|
|
1217
1263
|
this.update({ invokeResult: result });
|
|
1218
1264
|
return result;
|
|
@@ -1279,54 +1325,47 @@ export class CrowdyStudioController {
|
|
|
1279
1325
|
this.modConnection = null;
|
|
1280
1326
|
void open?.connection.then((connection) => connection.close(), () => { });
|
|
1281
1327
|
}
|
|
1328
|
+
clearLogLines() {
|
|
1329
|
+
this.modLogLines = [];
|
|
1330
|
+
this.previewLogLines = [];
|
|
1331
|
+
return [];
|
|
1332
|
+
}
|
|
1333
|
+
/** The mod's lines and the preview's, newest first. */
|
|
1334
|
+
mergedLogLines() {
|
|
1335
|
+
return [...this.previewLogLines, ...this.modLogLines].sort((a, b) => (Date.parse(b.at) || 0) - (Date.parse(a.at) || 0));
|
|
1336
|
+
}
|
|
1337
|
+
/** A `crowdy::log` line of the CLIENT half this browser previews; the last 100 are kept. */
|
|
1338
|
+
recordPreviewLog(moduleName, line) {
|
|
1339
|
+
if (this.destroyed)
|
|
1340
|
+
return;
|
|
1341
|
+
this.previewLogSeq += 1;
|
|
1342
|
+
this.previewLogLines = [
|
|
1343
|
+
{
|
|
1344
|
+
id: `preview-${this.previewLogSeq}`,
|
|
1345
|
+
source: 'preview',
|
|
1346
|
+
moduleName,
|
|
1347
|
+
level: line.level,
|
|
1348
|
+
at: new Date().toISOString(),
|
|
1349
|
+
text: line.message,
|
|
1350
|
+
},
|
|
1351
|
+
...this.previewLogLines,
|
|
1352
|
+
].slice(0, PREVIEW_LOG_LINES_KEPT);
|
|
1353
|
+
this.update({ logs: this.mergedLogLines() });
|
|
1354
|
+
}
|
|
1282
1355
|
async refreshSurface(surface) {
|
|
1283
1356
|
if (!this.state.project)
|
|
1284
1357
|
return;
|
|
1285
|
-
const serverName = this.state.project.metadata.serverModuleName;
|
|
1286
|
-
if (this.mods && surface !== 'usage') {
|
|
1287
|
-
// ck-exec records no runs; a mod's log is its own `ctx.log` lines.
|
|
1288
|
-
if (surface === 'runs') {
|
|
1289
|
-
this.update({ runs: [] });
|
|
1290
|
-
return;
|
|
1291
|
-
}
|
|
1292
|
-
const lines = serverName?.trim()
|
|
1293
|
-
? await this.mods.modLogs(this.options.appId, this.options.gridId, serverName.trim(), {
|
|
1294
|
-
limit: 50,
|
|
1295
|
-
})
|
|
1296
|
-
: [];
|
|
1297
|
-
this.update({ logs: lines.map((line) => modLogRow(serverName.trim(), line)) });
|
|
1298
|
-
return;
|
|
1299
|
-
}
|
|
1300
|
-
if (surface === 'runs') {
|
|
1301
|
-
this.update({
|
|
1302
|
-
runs: await this.options.playerCompute.runs({
|
|
1303
|
-
...this.scope(),
|
|
1304
|
-
...(serverName ? { moduleName: serverName } : {}),
|
|
1305
|
-
limit: 50,
|
|
1306
|
-
offset: 0,
|
|
1307
|
-
}),
|
|
1308
|
-
});
|
|
1309
|
-
return;
|
|
1310
|
-
}
|
|
1311
1358
|
if (surface === 'logs') {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
});
|
|
1359
|
+
// The `ctx.log` lines of the project's mod, which a CLIENT-only project's CLIENT half rides.
|
|
1360
|
+
const name = projectModNameOrNull(this.state.project);
|
|
1361
|
+
const lines = name
|
|
1362
|
+
? await this.mods.modLogs(this.options.appId, this.options.gridId, name, { limit: 50 })
|
|
1363
|
+
: [];
|
|
1364
|
+
this.modLogLines = lines.map((line) => modLogLine(name, line));
|
|
1365
|
+
this.update({ logs: this.mergedLogLines() });
|
|
1319
1366
|
return;
|
|
1320
1367
|
}
|
|
1321
|
-
|
|
1322
|
-
const legacyUsage = !this.mods || projectTargets(this.state.project.kind).includes('CLIENT');
|
|
1323
|
-
const [usage, wallet] = await Promise.all([
|
|
1324
|
-
legacyUsage
|
|
1325
|
-
? this.options.playerCompute.usage({ appId: this.options.appId })
|
|
1326
|
-
: Promise.resolve(null),
|
|
1327
|
-
this.options.playerWallet?.balance() ?? Promise.resolve(null),
|
|
1328
|
-
]);
|
|
1329
|
-
this.update({ usage: usage ? normalizeUsage(usage) : null, wallet });
|
|
1368
|
+
this.update({ wallet: (await this.options.playerWallet?.balance()) ?? null });
|
|
1330
1369
|
}
|
|
1331
1370
|
destroy() {
|
|
1332
1371
|
if (this.destroyed)
|
|
@@ -1593,18 +1632,53 @@ function isModCrateFile(path) {
|
|
|
1593
1632
|
path === 'README.md' ||
|
|
1594
1633
|
(path.startsWith('src/') && path.endsWith('.rs')));
|
|
1595
1634
|
}
|
|
1596
|
-
function
|
|
1597
|
-
|
|
1635
|
+
function crateFiles(files) {
|
|
1636
|
+
return files
|
|
1637
|
+
.filter((file) => isModCrateFile(file.path))
|
|
1638
|
+
.map((file) => ({ path: file.path, content: file.content }));
|
|
1639
|
+
}
|
|
1640
|
+
/** A build's crate name for a module: its own when it is one, else `mod-<name>`. */
|
|
1641
|
+
function crateName(name) {
|
|
1642
|
+
return CRATE_NAME.test(name) ? name : `mod-${name}`;
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* The mod a ck-exec project runs as: its SERVER module's name, or for a CLIENT-only project the
|
|
1646
|
+
* CLIENT module's, which names the mod its CLIENT half rides.
|
|
1647
|
+
*/
|
|
1648
|
+
function projectModName(project) {
|
|
1649
|
+
return moduleNameFor(project, projectTargets(project.kind).includes('SERVER') ? 'SERVER' : 'CLIENT');
|
|
1650
|
+
}
|
|
1651
|
+
function projectModNameOrNull(project) {
|
|
1652
|
+
try {
|
|
1653
|
+
return projectModName(project);
|
|
1654
|
+
}
|
|
1655
|
+
catch {
|
|
1656
|
+
return null;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
/** Why a ck-exec project's mod name cannot be a mod's, or null. */
|
|
1660
|
+
function modNameProblem(project) {
|
|
1661
|
+
const name = projectModName(project);
|
|
1662
|
+
if (MOD_NAME.test(name))
|
|
1663
|
+
return null;
|
|
1664
|
+
return projectTargets(project.kind).includes('SERVER')
|
|
1665
|
+
? `The server module name '${name}' must be 1-48 lowercase letters, digits, - or _ to run as a mod`
|
|
1666
|
+
: `The CLIENT module name '${name}' names the mod its CLIENT half rides, so it must be 1-48 lowercase letters, digits, - or _`;
|
|
1667
|
+
}
|
|
1668
|
+
const LEGACY_CLIENT_CRATE = 'This CLIENT crate depends on crowdy-compute-sdk, legacy player compute. On ck-exec a CLIENT ' +
|
|
1669
|
+
'target is a mod\u2019s CLIENT half, one crowdy-client-sdk crate: in Cargo.toml replace the ' +
|
|
1670
|
+
'crowdy-compute-sdk line with crowdy-client-sdk = "0.1.0", and in src/ use crowdy_client_sdk ' +
|
|
1671
|
+
'in place of crowdy_compute_sdk. Its host calls are the same less the Game Model, sessions and ' +
|
|
1672
|
+
'grid state (grid_state_get / grid_state_set): the mod\u2019s server half, a hub keyed by the ' +
|
|
1673
|
+
'grid, holds grid state now.';
|
|
1674
|
+
function modLogLine(moduleName, line) {
|
|
1598
1675
|
return {
|
|
1599
|
-
|
|
1676
|
+
id: line.id,
|
|
1677
|
+
source: 'mod',
|
|
1600
1678
|
moduleName,
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
fuelUsed: '0',
|
|
1605
|
-
success: level !== 'error',
|
|
1606
|
-
errorMessage: line.text,
|
|
1607
|
-
level,
|
|
1679
|
+
level: LOG_LEVELS[line.level] ?? 'debug',
|
|
1680
|
+
at: line.at,
|
|
1681
|
+
text: line.text,
|
|
1608
1682
|
};
|
|
1609
1683
|
}
|
|
1610
1684
|
function moduleNameFor(project, target) {
|
|
@@ -1647,18 +1721,6 @@ function upsertReference(files, next) {
|
|
|
1647
1721
|
...files.filter((file) => file.source !== next.source || file.id !== next.id),
|
|
1648
1722
|
];
|
|
1649
1723
|
}
|
|
1650
|
-
function normalizeUsage(value) {
|
|
1651
|
-
return {
|
|
1652
|
-
hourUnitsUsed: String(value.hourUnitsUsed),
|
|
1653
|
-
dayUnitsUsed: String(value.dayUnitsUsed),
|
|
1654
|
-
unitsPerHour: value.unitsPerHour == null ? null : String(value.unitsPerHour),
|
|
1655
|
-
unitsPerDay: value.unitsPerDay == null ? null : String(value.unitsPerDay),
|
|
1656
|
-
compilesThisHour: value.compilesThisHour,
|
|
1657
|
-
maxCompilesPerHour: value.maxCompilesPerHour,
|
|
1658
|
-
gateStatus: value.gateStatus,
|
|
1659
|
-
gateReason: value.gateReason ?? null,
|
|
1660
|
-
};
|
|
1661
|
-
}
|
|
1662
1724
|
function applyValidatedPatch(baseline, input) {
|
|
1663
1725
|
if (input.changes.length < 1 || input.changes.length > 16) {
|
|
1664
1726
|
throw new Error('Atomic patch must contain 1 to 16 file changes');
|