@crowdedkingdoms/crowdyjs 17.13.0-dev.1 → 17.14.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.
Files changed (62) hide show
  1. package/MIGRATION.md +72 -1
  2. package/README.md +72 -7
  3. package/dist/crowdy-studio/controller.d.ts +38 -11
  4. package/dist/crowdy-studio/controller.d.ts.map +1 -1
  5. package/dist/crowdy-studio/controller.js +237 -46
  6. package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
  7. package/dist/crowdy-studio/dom-shell.js +3 -1
  8. package/dist/crowdy-studio/embed/hud-layer.d.ts +2 -1
  9. package/dist/crowdy-studio/embed/hud-layer.d.ts.map +1 -1
  10. package/dist/crowdy-studio/embed/panel.d.ts +7 -6
  11. package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
  12. package/dist/crowdy-studio/starter-projects.d.ts +8 -0
  13. package/dist/crowdy-studio/starter-projects.d.ts.map +1 -1
  14. package/dist/crowdy-studio/starter-projects.js +79 -5
  15. package/dist/domains/exec.d.ts +162 -15
  16. package/dist/domains/exec.d.ts.map +1 -1
  17. package/dist/domains/exec.js +180 -18
  18. package/dist/domains/marketplace.d.ts +15 -3
  19. package/dist/domains/marketplace.d.ts.map +1 -1
  20. package/dist/domains/marketplace.js +17 -3
  21. package/dist/generated/graphql.d.ts +349 -0
  22. package/dist/generated/graphql.d.ts.map +1 -1
  23. package/dist/generated/graphql.js +17 -8
  24. package/dist/grid-mods/exec-client-halves.d.ts +140 -0
  25. package/dist/grid-mods/exec-client-halves.d.ts.map +1 -0
  26. package/dist/grid-mods/exec-client-halves.js +341 -0
  27. package/dist/grid-mods/grid-host-calls.d.ts +3 -1
  28. package/dist/grid-mods/grid-host-calls.d.ts.map +1 -1
  29. package/dist/grid-mods/grid-host-calls.js +3 -1
  30. package/dist/grid-mods/index.d.ts +1 -0
  31. package/dist/grid-mods/index.d.ts.map +1 -1
  32. package/dist/grid-mods/index.js +1 -0
  33. package/dist/grid-mods/mod-runtime.d.ts +10 -2
  34. package/dist/grid-mods/mod-runtime.d.ts.map +1 -1
  35. package/dist/grid-mods/mod-runtime.js +2 -0
  36. package/dist/grid-scope.d.ts +1 -0
  37. package/dist/grid-scope.d.ts.map +1 -1
  38. package/dist/grid-scope.js +1 -0
  39. package/dist/index.d.ts +4 -4
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +4 -3
  42. package/dist/kit/npcs.d.ts.map +1 -1
  43. package/dist/kit/social.d.ts.map +1 -1
  44. package/dist/live-coding/rust-analysis.js +13 -1
  45. package/dist/player-runtime/glue-runtime.d.ts +19 -6
  46. package/dist/player-runtime/glue-runtime.d.ts.map +1 -1
  47. package/dist/player-runtime/glue-runtime.js +40 -16
  48. package/dist/player-runtime/player-code-broker.d.ts +29 -0
  49. package/dist/player-runtime/player-code-broker.d.ts.map +1 -1
  50. package/dist/player-runtime/player-code-broker.js +41 -8
  51. package/dist/player-runtime/player-glue-worker.d.ts +2 -1
  52. package/dist/player-runtime/player-glue-worker.d.ts.map +1 -1
  53. package/dist/player-runtime/player-glue-worker.js +3 -1
  54. package/dist/stores/actors.d.ts +12 -2
  55. package/dist/stores/actors.d.ts.map +1 -1
  56. package/dist/stores/actors.js +43 -18
  57. package/dist/stores/chunks.d.ts +12 -0
  58. package/dist/stores/chunks.d.ts.map +1 -1
  59. package/dist/stores/chunks.js +112 -39
  60. package/dist/stores/durable.d.ts.map +1 -1
  61. package/dist/stores/durable.js +2 -1
  62. package/package.json +1 -1
@@ -1,4 +1,5 @@
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';
@@ -204,6 +205,7 @@ export class CrowdyStudioController {
204
205
  ...options,
205
206
  ...this.scope(),
206
207
  ...(modStarter ? { modStarter } : {}),
208
+ engine: this.state.serverEngine,
207
209
  });
208
210
  const project = await this.options.projectProvider.createProject(input);
209
211
  this.installProject(project);
@@ -982,8 +984,10 @@ export class CrowdyStudioController {
982
984
  message: `Submitting ${name}`,
983
985
  },
984
986
  });
985
- if (target === 'SERVER' && this.mods) {
986
- return this.buildMod(name, files, operation);
987
+ if (this.mods) {
988
+ return target === 'SERVER'
989
+ ? this.buildMod(name, files, operation)
990
+ : this.buildClientHalf(name, files, operation);
987
991
  }
988
992
  // The server resolves the source from the project itself: the saved
989
993
  // files at the project revision, or — for a GITHUB project — the rust at
@@ -1041,34 +1045,69 @@ export class CrowdyStudioController {
1041
1045
  */
1042
1046
  async buildMod(name, files, operation) {
1043
1047
  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
- }
1048
+ const problem = modNameProblem(this.requireProject());
1049
+ if (problem)
1050
+ throw new Error(problem);
1047
1051
  const { appId, gridId } = this.scope();
1048
1052
  const queued = await mods.modBuild(appId, {
1049
- name: CRATE_NAME.test(name) ? name : `mod-${name}`,
1050
- files: files
1051
- .filter((file) => isModCrateFile(file.path))
1052
- .map((file) => ({ path: file.path, content: file.content })),
1053
+ name: crateName(name),
1054
+ files: crateFiles(files),
1055
+ });
1056
+ this.checkOperation(operation);
1057
+ const built = await this.awaitModBuild('SERVER', name, queued.buildId, operation);
1058
+ if (!built)
1059
+ return null;
1060
+ const mod = await mods.modDeploy(appId, gridId, name, built.buildId);
1061
+ this.checkOperation(operation);
1062
+ return { target: 'SERVER', name, versionId: String(mod.version) };
1063
+ }
1064
+ /**
1065
+ * The CLIENT target as a ck-exec mod's CLIENT half: the project's `crowdy-client-sdk` crate,
1066
+ * built on the platform (`modClientBuild`, a build of `kind` `client`). It is attached to the
1067
+ * project's mod when the project runs ({@link attachClientHalf}).
1068
+ */
1069
+ async buildClientHalf(name, files, operation) {
1070
+ const problem = modNameProblem(this.requireProject());
1071
+ if (problem)
1072
+ throw new Error(problem);
1073
+ const cargo = files.find((file) => file.path === 'Cargo.toml')?.content ?? '';
1074
+ if (/^\s*crowdy-compute-sdk\s*=/m.test(cargo)) {
1075
+ this.recordBuild('CLIENT', LEGACY_CLIENT_CRATE);
1076
+ this.update({
1077
+ runtime: {
1078
+ phase: 'COMPILE_FAILED',
1079
+ target: 'CLIENT',
1080
+ message: `${name} is a legacy player compute crate; a CLIENT half builds on crowdy-client-sdk`,
1081
+ },
1082
+ });
1083
+ return null;
1084
+ }
1085
+ const queued = await this.mods.modClientBuild(this.options.appId, {
1086
+ name: crateName(name),
1087
+ files: crateFiles(files),
1053
1088
  });
1054
1089
  this.checkOperation(operation);
1090
+ const built = await this.awaitModBuild('CLIENT', name, queued.buildId, operation);
1091
+ return built ? { target: 'CLIENT', name, versionId: built.buildId } : null;
1092
+ }
1093
+ /** Polls a mod build, a mod's or a CLIENT half's, recording its log; null when it did not succeed. */
1094
+ async awaitModBuild(target, name, buildId, operation) {
1095
+ const mods = this.mods;
1055
1096
  const limit = this.options.compilePollLimit ?? 60;
1056
1097
  const pollMs = this.options.compilePollMs ?? 1500;
1057
1098
  for (let attempt = 0; attempt < limit; attempt++) {
1058
- const b = await mods.modBuildStatus(appId, queued.buildId);
1099
+ const b = await mods.modBuildStatus(this.options.appId, buildId);
1059
1100
  this.checkOperation(operation);
1060
1101
  if (b.status === 'succeeded') {
1061
- this.recordBuild('SERVER', b.log ?? '');
1062
- const mod = await mods.modDeploy(appId, gridId, name, b.buildId);
1063
- this.checkOperation(operation);
1064
- return { target: 'SERVER', name, versionId: String(mod.version) };
1102
+ this.recordBuild(target, b.log ?? '');
1103
+ return b;
1065
1104
  }
1066
1105
  if (b.status === 'failed') {
1067
- this.recordBuild('SERVER', b.log ?? 'Compilation failed without output');
1106
+ this.recordBuild(target, b.log ?? 'Compilation failed without output');
1068
1107
  this.update({
1069
1108
  runtime: {
1070
1109
  phase: 'COMPILE_FAILED',
1071
- target: 'SERVER',
1110
+ target,
1072
1111
  message: `${name} failed to compile`,
1073
1112
  },
1074
1113
  });
@@ -1078,12 +1117,106 @@ export class CrowdyStudioController {
1078
1117
  this.checkOperation(operation);
1079
1118
  }
1080
1119
  const timeout = `Compilation timed out after ${limit} polls`;
1081
- this.recordBuild('SERVER', timeout);
1120
+ this.recordBuild(target, timeout);
1082
1121
  this.update({
1083
- runtime: { phase: 'COMPILE_FAILED', target: 'SERVER', message: timeout },
1122
+ runtime: { phase: 'COMPILE_FAILED', target, message: timeout },
1084
1123
  });
1085
1124
  return null;
1086
1125
  }
1126
+ /**
1127
+ * Attaches a built CLIENT half to the project's mod, consents to it as its author (the API
1128
+ * serves a CLIENT half only to a player who consented or trusts its author, the author too) and
1129
+ * fetches the served module for this browser's preview. A CLIENT-only project first makes sure
1130
+ * the mod it rides is the player's and switched on.
1131
+ */
1132
+ async attachClientHalf(compiled, operation) {
1133
+ const mods = this.mods;
1134
+ const { appId, gridId } = this.scope();
1135
+ const project = this.requireProject();
1136
+ const modName = projectModName(project);
1137
+ if (!projectTargets(project.kind).includes('SERVER')) {
1138
+ await this.ensureClientOnlyMod(modName, operation);
1139
+ }
1140
+ this.update({
1141
+ runtime: { phase: 'ENABLING', target: 'CLIENT', message: `Attaching ${compiled.name} to ${modName}` },
1142
+ });
1143
+ const attached = await mods.modClientDeploy(appId, gridId, modName, compiled.versionId);
1144
+ this.checkOperation(operation);
1145
+ await mods.consentClientMod(appId, attached.modId, attached.capabilityHash);
1146
+ this.checkOperation(operation);
1147
+ this.recordNote('CLIENT', `Attached to mod '${modName}' as CLIENT version ${attached.clientVersion} (capabilities ` +
1148
+ `${attached.capabilityHash}; ticks every ${attached.tickIntervalMs} ms). Visitors of grid ` +
1149
+ `${gridId} run it once they consent to it or trust you; you consented to it as its author.`);
1150
+ let artifact;
1151
+ try {
1152
+ artifact = await mods.modClientArtifactBytes(appId, attached.modId);
1153
+ }
1154
+ catch (error) {
1155
+ if (error instanceof CrowdyGraphQLError && error.code === 'NOT_FOUND') {
1156
+ throw new CrowdyError({
1157
+ message: `${compiled.name} is attached to mod '${modName}', but its preview did not load: the ` +
1158
+ 'API serves a CLIENT half only while its mod is switched on and not held, to a player ' +
1159
+ `with run_client_code who stands in grid ${gridId}`,
1160
+ cause: error,
1161
+ });
1162
+ }
1163
+ if (error instanceof CrowdyGraphQLError && error.code === 'RATE_LIMITED') {
1164
+ throw new CrowdyError({
1165
+ message: `${compiled.name} is attached to mod '${modName}', but its preview was fetched too ` +
1166
+ 'often (12 a minute); deploy again in a minute',
1167
+ cause: error,
1168
+ });
1169
+ }
1170
+ throw error;
1171
+ }
1172
+ this.checkOperation(operation);
1173
+ if (artifact.digest !== attached.digest || artifact.clientVersion !== attached.clientVersion) {
1174
+ throw new Error('The served CLIENT half is not the one just attached; deploy again');
1175
+ }
1176
+ return artifact;
1177
+ }
1178
+ /**
1179
+ * A CLIENT half rides a mod: without a mod of this name running as the player on the grid,
1180
+ * the mod starter's server half is deployed under it first, and the log says so. The mod is
1181
+ * switched on, since only a running mod's CLIENT half is served.
1182
+ */
1183
+ async ensureClientOnlyMod(name, operation) {
1184
+ const mods = this.mods;
1185
+ const { appId, gridId } = this.scope();
1186
+ const mine = (await mods.myMods(appId)).find((mod) => String(mod.gridId) === gridId && mod.name === name);
1187
+ this.checkOperation(operation);
1188
+ if (!mine) {
1189
+ if (!this.canTarget('SERVER', 'write') || !this.canTarget('SERVER', 'run')) {
1190
+ 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`);
1191
+ }
1192
+ this.update({
1193
+ runtime: { phase: 'COMPILING', target: 'SERVER', message: `Deploying the mod starter as ${name}` },
1194
+ });
1195
+ const starter = await mods.modStarter(appId);
1196
+ this.checkOperation(operation);
1197
+ const queued = await mods.modBuild(appId, { name: crateName(name), files: starter.files });
1198
+ this.checkOperation(operation);
1199
+ const built = await this.awaitModBuild('SERVER', name, queued.buildId, operation);
1200
+ if (!built) {
1201
+ throw new Error(`The mod starter did not build, so the CLIENT half has no mod '${name}' to ride`);
1202
+ }
1203
+ await mods.modDeploy(appId, gridId, name, built.buildId);
1204
+ this.checkOperation(operation);
1205
+ this.recordNote('SERVER', `Grid ${gridId} had no mod '${name}' of yours, and a CLIENT half rides a mod: deployed the ` +
1206
+ `ck-exec mod starter (${starter.crate}) as '${name}', its server half.`);
1207
+ }
1208
+ if (!mine?.enabled) {
1209
+ await mods.modSetEnabled(appId, gridId, name, true);
1210
+ this.checkOperation(operation);
1211
+ if (mine)
1212
+ this.recordNote('SERVER', `Switched mod '${name}' on, so its CLIENT half is served.`);
1213
+ }
1214
+ }
1215
+ recordNote(target, note) {
1216
+ this.update({
1217
+ buildOutput: [this.state.buildOutput, `## ${target}\n${note}`].filter(Boolean).join('\n\n'),
1218
+ });
1219
+ }
1087
1220
  recordBuild(target, log) {
1088
1221
  const section = `## ${target}\n${log || 'Compiled successfully.'}`;
1089
1222
  const authoritativeDiagnostics = [
@@ -1122,28 +1255,47 @@ export class CrowdyStudioController {
1122
1255
  throw new Error(`${compiled.name} compiled successfully, but run_client_code is unavailable on this grid`);
1123
1256
  }
1124
1257
  const runtime = this.clientRuntimeOptions();
1125
- const artifact = await this.options.playerCompute.artifactBytes({
1126
- ...this.scope(),
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
- }
1136
- const brokerOptions = {
1137
- ...runtime,
1138
- artifactHash: artifact.artifactHash,
1139
- fuelPerDispatch: artifact.fuelPerDispatch,
1140
- onPresentation: this.options.onPresentation,
1141
- tickIntervalMs: this.options.clientTickIntervalMs ??
1142
- parseClientTickIntervalMs(this.requireProject().files.find((file) => file.target === 'CLIENT' && file.path === 'Cargo.toml')?.content),
1143
- };
1258
+ let brokerOptions;
1259
+ let bytes;
1260
+ if (this.mods) {
1261
+ const half = await this.attachClientHalf(compiled, operation);
1262
+ bytes = half.bytes;
1263
+ brokerOptions = {
1264
+ ...runtime,
1265
+ engine: 'ck-exec',
1266
+ moduleName: half.name,
1267
+ artifactHash: half.digest,
1268
+ fuelPerDispatch: half.fuelPerDispatch,
1269
+ consentedHostCalls: half.capabilitySummary.hostFunctions,
1270
+ onPresentation: this.options.onPresentation,
1271
+ tickIntervalMs: this.options.clientTickIntervalMs ?? half.tickIntervalMs,
1272
+ };
1273
+ }
1274
+ else {
1275
+ const artifact = await this.options.playerCompute.artifactBytes({
1276
+ ...this.scope(),
1277
+ name: compiled.name,
1278
+ versionId: compiled.versionId,
1279
+ });
1280
+ this.checkOperation(operation);
1281
+ if (artifact.versionId !== compiled.versionId ||
1282
+ !artifact.artifactHash ||
1283
+ artifact.bytes.byteLength === 0) {
1284
+ throw new Error('Client artifact did not match the compiled project version');
1285
+ }
1286
+ bytes = artifact.bytes;
1287
+ brokerOptions = {
1288
+ ...runtime,
1289
+ artifactHash: artifact.artifactHash,
1290
+ fuelPerDispatch: artifact.fuelPerDispatch,
1291
+ onPresentation: this.options.onPresentation,
1292
+ tickIntervalMs: this.options.clientTickIntervalMs ??
1293
+ parseClientTickIntervalMs(this.requireProject().files.find((file) => file.target === 'CLIENT' && file.path === 'Cargo.toml')?.content),
1294
+ };
1295
+ }
1144
1296
  const broker = this.options.brokerFactory?.(brokerOptions) ??
1145
1297
  new PlayerCodeBroker(brokerOptions);
1146
- await broker.start(artifact.bytes);
1298
+ await broker.start(bytes);
1147
1299
  this.checkOperation(operation);
1148
1300
  const previous = this.broker;
1149
1301
  this.broker = broker;
@@ -1170,10 +1322,12 @@ export class CrowdyStudioController {
1170
1322
  this.broker = null;
1171
1323
  }
1172
1324
  }
1173
- if (projectTargets(project.kind).includes('SERVER')) {
1325
+ // On ck-exec a CLIENT-only project's CLIENT half rides a mod too: switched off, it is no
1326
+ // longer served to visitors.
1327
+ if (projectTargets(project.kind).includes('SERVER') || this.mods) {
1174
1328
  serverStopped = false;
1175
1329
  try {
1176
- await this.setServerEnabled(moduleNameFor(project, 'SERVER'), false);
1330
+ await this.setServerEnabled(this.mods ? projectModName(project) : moduleNameFor(project, 'SERVER'), false);
1177
1331
  serverStopped = true;
1178
1332
  }
1179
1333
  catch (error) {
@@ -1289,12 +1443,13 @@ export class CrowdyStudioController {
1289
1443
  this.update({ runs: [] });
1290
1444
  return;
1291
1445
  }
1292
- const lines = serverName?.trim()
1293
- ? await this.mods.modLogs(this.options.appId, this.options.gridId, serverName.trim(), {
1446
+ const modName = projectModNameOrNull(this.state.project);
1447
+ const lines = modName
1448
+ ? await this.mods.modLogs(this.options.appId, this.options.gridId, modName, {
1294
1449
  limit: 50,
1295
1450
  })
1296
1451
  : [];
1297
- this.update({ logs: lines.map((line) => modLogRow(serverName.trim(), line)) });
1452
+ this.update({ logs: lines.map((line) => modLogRow(modName, line)) });
1298
1453
  return;
1299
1454
  }
1300
1455
  if (surface === 'runs') {
@@ -1318,10 +1473,9 @@ export class CrowdyStudioController {
1318
1473
  });
1319
1474
  return;
1320
1475
  }
1321
- // Player compute's units and compile quota: with a mod, only a CLIENT target spends them.
1322
- const legacyUsage = !this.mods || projectTargets(this.state.project.kind).includes('CLIENT');
1476
+ // Player compute's units and compile quota, which nothing spends on ck-exec.
1323
1477
  const [usage, wallet] = await Promise.all([
1324
- legacyUsage
1478
+ !this.mods
1325
1479
  ? this.options.playerCompute.usage({ appId: this.options.appId })
1326
1480
  : Promise.resolve(null),
1327
1481
  this.options.playerWallet?.balance() ?? Promise.resolve(null),
@@ -1593,6 +1747,43 @@ function isModCrateFile(path) {
1593
1747
  path === 'README.md' ||
1594
1748
  (path.startsWith('src/') && path.endsWith('.rs')));
1595
1749
  }
1750
+ function crateFiles(files) {
1751
+ return files
1752
+ .filter((file) => isModCrateFile(file.path))
1753
+ .map((file) => ({ path: file.path, content: file.content }));
1754
+ }
1755
+ /** A build's crate name for a module: its own when it is one, else `mod-<name>`. */
1756
+ function crateName(name) {
1757
+ return CRATE_NAME.test(name) ? name : `mod-${name}`;
1758
+ }
1759
+ /**
1760
+ * The mod a ck-exec project runs as: its SERVER module's name, or for a CLIENT-only project the
1761
+ * CLIENT module's, which names the mod its CLIENT half rides.
1762
+ */
1763
+ function projectModName(project) {
1764
+ return moduleNameFor(project, projectTargets(project.kind).includes('SERVER') ? 'SERVER' : 'CLIENT');
1765
+ }
1766
+ function projectModNameOrNull(project) {
1767
+ try {
1768
+ return projectModName(project);
1769
+ }
1770
+ catch {
1771
+ return null;
1772
+ }
1773
+ }
1774
+ /** Why a ck-exec project's mod name cannot be a mod's, or null. */
1775
+ function modNameProblem(project) {
1776
+ const name = projectModName(project);
1777
+ if (MOD_NAME.test(name))
1778
+ return null;
1779
+ return projectTargets(project.kind).includes('SERVER')
1780
+ ? `The server module name '${name}' must be 1-48 lowercase letters, digits, - or _ to run as a mod`
1781
+ : `The CLIENT module name '${name}' names the mod its CLIENT half rides, so it must be 1-48 lowercase letters, digits, - or _`;
1782
+ }
1783
+ const LEGACY_CLIENT_CRATE = 'This CLIENT crate depends on crowdy-compute-sdk, legacy player compute. On ck-exec a CLIENT ' +
1784
+ 'target is a mod\u2019s CLIENT half, one crowdy-client-sdk crate: in Cargo.toml replace the ' +
1785
+ 'crowdy-compute-sdk line with crowdy-client-sdk = "0.1.0", and in src/ use crowdy_client_sdk ' +
1786
+ 'in place of crowdy_compute_sdk. Its host calls are the same, less the Game Model and sessions.';
1596
1787
  function modLogRow(moduleName, line) {
1597
1788
  const level = LOG_LEVELS[line.level] ?? 'debug';
1598
1789
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"dom-shell.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/dom-shell.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dom-shell.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/dom-shell.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,sBAAsB,EAIvB,MAAM,aAAa,CAAC;AAuCrB;;;;;;;GAOG;AACH;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,kDAAkD;IAClD,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/B,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,cAAc,CAAC;IAClD,qEAAqE;IACrE,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC5D;AAED,qBAAa,oBAAoB;IAkE7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAlE/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAc;IAC5C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmB;IACvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAc;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2C;IACxE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8C;IAC1E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+C;IACzE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAa;IAC/C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,QAAQ,CAAS;gBAGvB,IAAI,EAAE,WAAW,EACA,UAAU,EAAE,sBAAsB,EAClC,YAAY,GAAE,2BAAgC;IA8VjE,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAsCtC,OAAO,IAAI,IAAI;IAiBf,OAAO,CAAC,UAAU;IAmBlB;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAgBhC,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,WAAW;IAsCnB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,UAAU;IA2DlB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,aAAa;IAWrB,wEAAwE;IACxE,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,eAAe;IAyBvB,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,cAAc;IA6CtB,OAAO,CAAC,cAAc;IAuDtB,OAAO,CAAC,kBAAkB;IAyD1B,OAAO,CAAC,gBAAgB;IA4DxB,OAAO,CAAC,UAAU;IA4ClB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,cAAc;IAqDtB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,iBAAiB;YAmBX,GAAG;CAQlB"}
@@ -903,7 +903,9 @@ export class CrowdyStudioDomShell {
903
903
  setInputUnlessFocused(this.clientModuleName, project.metadata.clientModuleName ?? '');
904
904
  this.serverModuleName.disabled = !projectTargets(project.kind).includes('SERVER');
905
905
  this.clientModuleName.disabled = !projectTargets(project.kind).includes('CLIENT');
906
- this.pairing.disabled = project.kind !== 'FULL_STACK';
906
+ // A mod has no pairing: its CLIENT half rides it.
907
+ this.pairing.disabled =
908
+ project.kind !== 'FULL_STACK' || state.serverEngine === 'ck-exec';
907
909
  this.pairing.value = project.metadata.pairingPreference;
908
910
  }
909
911
  renderProblems(state) {
@@ -1,5 +1,6 @@
1
1
  /**
2
- * A persistent, game-owned HUD layer for player-compute CLIENT mods. A
2
+ * A persistent, game-owned HUD layer for CLIENT mods (ck-exec CLIENT halves
3
+ * and legacy player-compute CLIENT modules). A
3
4
  * running client mod never touches the game DOM; it emits `hud_set` payloads
4
5
  * that the broker forwards here. This layer lives outside the studio panel so
5
6
  * a mod's HUD survives panel re-renders and keeps rendering after the coding
@@ -1 +1 @@
1
- {"version":3,"file":"hud-layer.d.ts","sourceRoot":"","sources":["../../../src/crowdy-studio/embed/hud-layer.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,OAAO,CAAC,UAAU;IAUlB,+DAA+D;IAC/D,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAKtC,oEAAoE;IACpE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5B,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI;IAShE,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,SAAS;IAajB,mEAAmE;IACnE,OAAO,CAAC,QAAQ;CAQjB"}
1
+ {"version":3,"file":"hud-layer.d.ts","sourceRoot":"","sources":["../../../src/crowdy-studio/embed/hud-layer.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,OAAO,CAAC,UAAU;IAUlB,+DAA+D;IAC/D,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAKtC,oEAAoE;IACpE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5B,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI;IAShE,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,SAAS;IAajB,mEAAmE;IACnE,OAAO,CAAC,QAAQ;CAQjB"}
@@ -19,7 +19,7 @@ export interface CrowdyStudioEmbedServices {
19
19
  playerWallet?: CrowdyStudioPlayerWallet;
20
20
  /** GitHub repository loop; omission hides the card. `CrowdyClient` provides it. */
21
21
  crowdyStudioGitHub?: CrowdyStudioGitHubTransport;
22
- /** ck-exec, the default SERVER engine when present. `CrowdyClient` provides it. */
22
+ /** ck-exec, the default engine for both targets when present. `CrowdyClient` provides it. */
23
23
  exec?: CrowdyStudioMods;
24
24
  }
25
25
  export interface CrowdyStudioEmbedTargetPermission {
@@ -70,11 +70,12 @@ export interface CrowdyStudioEmbedOptions {
70
70
  */
71
71
  github?: CrowdyStudioGitHubTransport;
72
72
  /**
73
- * What runs the SERVER target: a ck-exec mod on the grid, built from the project's
74
- * `ckx-sdk` crate (`client.exec`), or legacy player compute, which the platform is
75
- * switching off. Defaults to `'ck-exec'` when the client has `exec` (every `CrowdyClient`
76
- * does), else `'player-compute'`. Pass `'player-compute'` to stay on the legacy engine
77
- * until it is removed.
73
+ * What runs the project: a ck-exec mod on the grid, built from the project's `ckx-sdk`
74
+ * crate, with the CLIENT target as its `crowdy-client-sdk` CLIENT half (`client.exec`), or
75
+ * legacy player compute for both targets, which the platform is switching off. Defaults to
76
+ * `'ck-exec'` when the client has `exec` (every `CrowdyClient` does), else
77
+ * `'player-compute'`. Pass `'player-compute'` to stay on the legacy engine until 18.0
78
+ * removes it.
78
79
  */
79
80
  serverEngine?: CrowdyStudioServerEngine;
80
81
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/crowdy-studio/embed/panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAKL,KAAK,4BAA4B,EAClC,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAO1D,MAAM,MAAM,4BAA4B,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,2BAA2B,CAAC;IAC1C,aAAa,EAAE,yBAAyB,CAAC;IACzC,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,2BAA2B,CAAC;IACjD,mFAAmF;IACnF,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kCAAkC;IACjD,MAAM,EAAE,iCAAiC,CAAC;IAC1C,MAAM,EAAE,iCAAiC,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;AAEpF,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAC/B,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8EAA8E;IAC9E,GAAG,CAAC,EAAE,2BAA2B,CAAC;IAClC;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,2BAA2B,CAAC;IACrC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC;;;OAGG;IACH,qBAAqB,CAAC,IAAI,MAAM,IAAI,CAAC;IACrC,sEAAsE;IACtE,cAAc,CAAC,IAAI,IAAI,CAAC;IACxB,sFAAsF;IACtF,cAAc,CAAC,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACvD,kBAAkB,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,gBAAgB,CAAC,IAAI,IAAI,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB,WAAW,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAC;IAClD,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACtD;AAED,6EAA6E;AAC7E,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,iBAAiB,EAAE,kCAAkC,CAAC;IACtD,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,UAAU,CAAC,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,wEAAwE;IACxE,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,mEAAmE;IACnE,cAAc,CAAC,CAAC,YAAY,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC5D,+DAA+D;IAC/D,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;CACnD;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAehB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAdpC,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,WAAW,CAA6C;IAChE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEhB,OAAO,EAAE,wBAAwB;IAS9D,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,IAAI,IAAI,4BAA4B,GAAG,IAAI,CAE9C;IAED,MAAM,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI;IAK/C,OAAO,IAAI,IAAI;IAKf,KAAK,IAAI,IAAI;IAqCb,OAAO,CAAC,IAAI;IA6DZ;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAqCd;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAmEd,OAAO,CAAC,YAAY;YAgBN,WAAW;IAkDzB,sEAAsE;YACxD,cAAc;IAoE5B,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAE7B;IAEF,OAAO,CAAC,iBAAiB;IAyCzB,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG9B;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAO5B;IAEF,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,OAAO;IAsBf,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAEhC;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAI5B;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAK9B;CACH;AAED,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,iBAAiB,CAEnB"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/crowdy-studio/embed/panel.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { CrowdyStudioServerEngine } from './controller.js';
1
2
  import { type CreateCrowdyStudioProjectInput, type CrowdyStudioProjectKind } from './models.js';
2
3
  /** ck-exec's mod starter crate (`client.exec.modStarter(appId)`). */
3
4
  export interface CrowdyStudioModStarter {
@@ -19,6 +20,13 @@ export interface CrowdyStudioNewProjectOptions {
19
20
  * client pairing, so a full-stack project records `NONE`.
20
21
  */
21
22
  modStarter?: CrowdyStudioModStarter;
23
+ /**
24
+ * `'ck-exec'`: the project is a ck-exec mod. Its SERVER target starts from `modStarter`
25
+ * (required with one), its CLIENT target from a `crowdy-client-sdk` crate, the mod's CLIENT
26
+ * half, and both module names fit a mod's. Default `'player-compute'`, where the CLIENT target
27
+ * is a legacy compute SDK crate.
28
+ */
29
+ engine?: CrowdyStudioServerEngine;
22
30
  }
23
31
  /** Create a compile-oriented starter without introducing a raw JSON source map. */
24
32
  export declare function createCrowdyStudioStarterProject(options: CrowdyStudioNewProjectOptions): CreateCrowdyStudioProjectInput;
@@ -1 +1 @@
1
- {"version":3,"file":"starter-projects.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/starter-projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,8BAA8B,EAEnC,KAAK,uBAAuB,EAG7B,MAAM,aAAa,CAAC;AAOrB,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,KAAK,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACrC;AAED,mFAAmF;AACnF,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,6BAA6B,GACrC,8BAA8B,CA+BhC"}
1
+ {"version":3,"file":"starter-projects.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/starter-projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAEL,KAAK,8BAA8B,EAEnC,KAAK,uBAAuB,EAG7B,MAAM,aAAa,CAAC;AASrB,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,KAAK,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED,mFAAmF;AACnF,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,6BAA6B,GACrC,8BAA8B,CAqChC"}
@@ -1,12 +1,18 @@
1
1
  import { projectTargets, } from './models.js';
2
2
  const SDK_VERSION = '0.1.8';
3
+ /** crowdy-client-sdk, what a ck-exec mod's CLIENT half builds on; the build points it at the platform's copy. */
4
+ const CLIENT_SDK_VERSION = '0.1.0';
3
5
  /** A mod's name is at most 48 characters, and the SERVER module name is `<base>-server`. */
4
6
  const MOD_BASE_MAX = 48 - '-server'.length;
5
7
  /** Create a compile-oriented starter without introducing a raw JSON source map. */
6
8
  export function createCrowdyStudioStarterProject(options) {
7
9
  const mod = options.modStarter;
8
- const base = mod ? modModuleBase(options.name) : moduleName(options.name);
10
+ const exec = options.engine === 'ck-exec';
9
11
  const targets = projectTargets(options.kind);
12
+ if (exec && targets.includes('SERVER') && !mod) {
13
+ throw new Error('A ck-exec SERVER target starts from the mod starter (client.exec.modStarter)');
14
+ }
15
+ const base = mod || exec ? modModuleBase(options.name) : moduleName(options.name);
10
16
  const metadata = {
11
17
  name: options.name.trim() || 'Untitled mod',
12
18
  ...(options.description?.trim()
@@ -18,7 +24,7 @@ export function createCrowdyStudioStarterProject(options) {
18
24
  ...(targets.includes('CLIENT')
19
25
  ? { clientModuleName: `${base}-client` }
20
26
  : {}),
21
- pairingPreference: options.kind === 'FULL_STACK' && !mod ? 'REQUIRED' : 'NONE',
27
+ pairingPreference: options.kind === 'FULL_STACK' && !mod && !exec ? 'REQUIRED' : 'NONE',
22
28
  };
23
29
  return {
24
30
  appId: options.appId,
@@ -29,9 +35,77 @@ export function createCrowdyStudioStarterProject(options) {
29
35
  ? mod
30
36
  ? modStarterFiles(mod, metadata.serverModuleName)
31
37
  : starterFiles(target, metadata.serverModuleName)
32
- : starterFiles(target, metadata.clientModuleName)),
38
+ : exec
39
+ ? clientHalfStarterFiles(metadata.clientModuleName)
40
+ : starterFiles(target, metadata.clientModuleName)),
33
41
  };
34
42
  }
43
+ /**
44
+ * A ck-exec mod's CLIENT half: one `crowdy-client-sdk` crate within the build's rules (only
45
+ * `[package]`, `[lib]` as a cdylib, the SDK and serde dependencies, and
46
+ * `[package.metadata.crowdy] tick_interval_ms`).
47
+ */
48
+ function clientHalfStarterFiles(name) {
49
+ return [
50
+ {
51
+ target: 'CLIENT',
52
+ path: 'Cargo.toml',
53
+ content: `[package]
54
+ name = "${name}"
55
+ version = "0.1.0"
56
+ edition = "2021"
57
+
58
+ [lib]
59
+ crate-type = ["cdylib"]
60
+
61
+ # How often visitors' browsers call tick (clamped 16–1000 ms).
62
+ # 1000 = HUD/text. 50 = physics minigames (pool). 16 = shooters, if a tick stays cheap.
63
+ [package.metadata.crowdy]
64
+ tick_interval_ms = 1000
65
+
66
+ [dependencies]
67
+ crowdy-client-sdk = "${CLIENT_SDK_VERSION}"
68
+ serde_json = "1"
69
+ `,
70
+ },
71
+ {
72
+ target: 'CLIENT',
73
+ path: 'src/lib.rs',
74
+ content: `use crowdy_client_sdk as crowdy;
75
+
76
+ fn init() {
77
+ // Runs once in each visitor's browser, after they consent to this CLIENT half
78
+ // (or trust you) and while they stand in this grid.
79
+ crowdy::log(1, "ready");
80
+ }
81
+
82
+ fn tick(_dt_ms: u32) {
83
+ // Every tick_interval_ms (Cargo.toml). The state blob lasts as long as the page's worker.
84
+ let ticks = u32::from_le_bytes(crowdy::state_get().try_into().unwrap_or([0; 4])).wrapping_add(1);
85
+ crowdy::state_set(&ticks.to_le_bytes());
86
+ // Host calls cross the page's broker as the visiting player, inside this grid: the HUD and
87
+ // overlay, chunk and actor reads, voxel writes, spatial and channel sends, grid events.
88
+ // Type "crowdy::api::" for the rest. The page's DOM and tokens are never reachable.
89
+ let _ = crowdy::api::hud_set(serde_json::json!({ "text": format!("Ticks here: {ticks}") }));
90
+ //
91
+ // Mouse (holodeck canvas only; Studio chrome is omitted). Drain every tick:
92
+ // let data = crowdy::api::pointer_clicks().unwrap_or(serde_json::json!({}));
93
+ // data["clicks"] = [{ "t": "down"|"up", "button": 0, "atMs", "heldMs", "nx", "ny" }]
94
+ }
95
+
96
+ fn invoke(payload: &[u8]) -> Vec<u8> {
97
+ payload.to_vec()
98
+ }
99
+
100
+ fn event(_payload: &[u8]) {
101
+ // Grid events from the other CLIENT halves on this page (crowdy::api::emit_event).
102
+ }
103
+
104
+ crowdy::register_module!(init: init, tick: tick, invoke: invoke, event: event);
105
+ `,
106
+ },
107
+ ];
108
+ }
35
109
  function modStarterFiles(starter, name) {
36
110
  const paths = new Set(starter.files.map((file) => file.path));
37
111
  if (!paths.has('Cargo.toml') || !paths.has('src/lib.rs')) {
@@ -66,8 +140,8 @@ function renamePackage(manifest, name) {
66
140
  .join('\n');
67
141
  }
68
142
  /**
69
- * A mod module base: short enough for `<base>-server` to be a mod name, and starting with a
70
- * letter, as a build's crate names must.
143
+ * A mod module base: short enough for `<base>-server` and `<base>-client` to be mod names, and
144
+ * starting with a letter, as a build's crate names must.
71
145
  */
72
146
  function modModuleBase(value) {
73
147
  const slug = slugModuleName(value);