@crowdedkingdoms/crowdyjs 9.0.0 → 10.0.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.
Files changed (72) hide show
  1. package/MIGRATION.md +56 -34
  2. package/README.md +83 -50
  3. package/dist/crowdy-client.d.ts +3 -0
  4. package/dist/crowdy-client.d.ts.map +1 -1
  5. package/dist/crowdy-client.js +2 -0
  6. package/dist/domains/playerCodeProjects.d.ts +25 -0
  7. package/dist/domains/playerCodeProjects.d.ts.map +1 -0
  8. package/dist/domains/playerCodeProjects.js +299 -0
  9. package/dist/domains/playerCompute.d.ts +1 -1
  10. package/dist/domains/playerCompute.js +1 -1
  11. package/dist/generated/graphql.d.ts +792 -7
  12. package/dist/generated/graphql.d.ts.map +1 -1
  13. package/dist/generated/graphql.js +57 -0
  14. package/dist/index.d.ts +3 -5
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -5
  17. package/dist/kit/npcs.d.ts.map +1 -1
  18. package/dist/kit/social.d.ts.map +1 -1
  19. package/dist/live-coding/rust-analysis.d.ts.map +1 -1
  20. package/dist/live-coding/rust-analysis.js +64 -1
  21. package/dist/live-coding/worker-transport.d.ts +3 -0
  22. package/dist/live-coding/worker-transport.d.ts.map +1 -1
  23. package/dist/live-coding/worker-transport.js +13 -0
  24. package/dist/mod-studio/controller.d.ts +188 -0
  25. package/dist/mod-studio/controller.d.ts.map +1 -0
  26. package/dist/mod-studio/controller.js +915 -0
  27. package/dist/mod-studio/diagnostics.d.ts +22 -0
  28. package/dist/mod-studio/diagnostics.d.ts.map +1 -0
  29. package/dist/mod-studio/diagnostics.js +141 -0
  30. package/dist/mod-studio/dom-shell.d.ts +55 -0
  31. package/dist/mod-studio/dom-shell.d.ts.map +1 -0
  32. package/dist/mod-studio/dom-shell.js +527 -0
  33. package/dist/mod-studio/editor.d.ts +17 -0
  34. package/dist/mod-studio/editor.d.ts.map +1 -0
  35. package/dist/mod-studio/editor.js +1 -0
  36. package/dist/mod-studio/index.d.ts +10 -0
  37. package/dist/mod-studio/index.d.ts.map +1 -0
  38. package/dist/mod-studio/index.js +9 -0
  39. package/dist/mod-studio/models.d.ts +149 -0
  40. package/dist/mod-studio/models.d.ts.map +1 -0
  41. package/dist/mod-studio/models.js +62 -0
  42. package/dist/mod-studio/monaco-editor.d.ts +16 -0
  43. package/dist/mod-studio/monaco-editor.d.ts.map +1 -0
  44. package/dist/mod-studio/monaco-editor.js +548 -0
  45. package/dist/mod-studio/mount.d.ts +17 -0
  46. package/dist/mod-studio/mount.d.ts.map +1 -0
  47. package/dist/mod-studio/mount.js +86 -0
  48. package/dist/mod-studio/starter-projects.d.ts +11 -0
  49. package/dist/mod-studio/starter-projects.d.ts.map +1 -0
  50. package/dist/mod-studio/starter-projects.js +102 -0
  51. package/dist/mod-studio/styles.d.ts +2 -0
  52. package/dist/mod-studio/styles.d.ts.map +1 -0
  53. package/dist/mod-studio/styles.js +14 -0
  54. package/dist/mod-studio/textarea-editor.d.ts +8 -0
  55. package/dist/mod-studio/textarea-editor.d.ts.map +1 -0
  56. package/dist/mod-studio/textarea-editor.js +71 -0
  57. package/package.json +4 -4
  58. package/dist/live-coding/ide.d.ts +0 -23
  59. package/dist/live-coding/ide.d.ts.map +0 -1
  60. package/dist/live-coding/ide.js +0 -514
  61. package/dist/live-coding/index.d.ts +0 -8
  62. package/dist/live-coding/index.d.ts.map +0 -1
  63. package/dist/live-coding/index.js +0 -7
  64. package/dist/live-coding/live-coding-controller.d.ts +0 -75
  65. package/dist/live-coding/live-coding-controller.d.ts.map +0 -1
  66. package/dist/live-coding/live-coding-controller.js +0 -141
  67. package/dist/live-coding/mount.d.ts +0 -26
  68. package/dist/live-coding/mount.d.ts.map +0 -1
  69. package/dist/live-coding/mount.js +0 -108
  70. package/dist/live-coding/templates.d.ts +0 -17
  71. package/dist/live-coding/templates.d.ts.map +0 -1
  72. package/dist/live-coding/templates.js +0 -59
@@ -0,0 +1,527 @@
1
+ import { projectTargets, } from './models.js';
2
+ import { MOD_STUDIO_STYLES } from './styles.js';
3
+ /** Modular DOM shell; editor implementations mount into `editorHost`. */
4
+ export class ModStudioDomShell {
5
+ constructor(host, controller) {
6
+ this.controller = controller;
7
+ this.panelButtons = new Map();
8
+ this.panels = new Map();
9
+ this.activePanel = 'problems';
10
+ this.disposed = false;
11
+ const style = document.createElement('style');
12
+ style.textContent = MOD_STUDIO_STYLES;
13
+ this.root = element('div', 'ck-mod-studio');
14
+ this.root.append(style);
15
+ const toolbar = element('div', 'ck-mod-studio-toolbar');
16
+ const projectTools = element('div', 'ck-mod-studio-project-tools');
17
+ this.projectSelect = document.createElement('select');
18
+ this.projectSelect.setAttribute('aria-label', 'Current project');
19
+ const newButton = button('New project');
20
+ this.saveBadge = element('span', 'ck-mod-studio-save');
21
+ this.saveAction = button('Retry save');
22
+ this.remoteAction = button('Use cloud version');
23
+ this.saveAction.hidden = true;
24
+ this.remoteAction.hidden = true;
25
+ projectTools.append(this.projectSelect, newButton, this.saveBadge, this.saveAction, this.remoteAction);
26
+ const runtimeTools = element('div', 'ck-mod-studio-runtime-tools');
27
+ this.testAction = button('Test draft');
28
+ this.deployAction = button('Deploy live');
29
+ const stop = button('Stop project');
30
+ this.runtimeStatus = element('span', 'ck-mod-studio-status');
31
+ this.budgetStatus = element('span', 'ck-mod-studio-status');
32
+ runtimeTools.append(this.testAction, this.deployAction, stop, this.runtimeStatus, this.budgetStatus);
33
+ toolbar.append(projectTools, runtimeTools);
34
+ this.newForm = document.createElement('form');
35
+ this.newForm.className = 'ck-mod-studio-new';
36
+ this.newForm.dataset.open = 'false';
37
+ this.newName = document.createElement('input');
38
+ this.newName.required = true;
39
+ this.newName.placeholder = 'Project name';
40
+ this.newName.setAttribute('aria-label', 'New project name');
41
+ this.newKind = select([
42
+ ['SERVER', 'Server'],
43
+ ['CLIENT', 'Client'],
44
+ ['FULL_STACK', 'Full stack'],
45
+ ]);
46
+ for (const option of Array.from(this.newKind.options ?? [])) {
47
+ option.disabled =
48
+ option.value === 'SERVER'
49
+ ? !this.controller.canTarget('SERVER', 'write')
50
+ : option.value === 'CLIENT'
51
+ ? !this.controller.canTarget('CLIENT', 'write')
52
+ : !this.controller.canTarget('SERVER', 'write') ||
53
+ !this.controller.canTarget('CLIENT', 'write');
54
+ }
55
+ this.newKind.setAttribute('aria-label', 'New project type');
56
+ const create = button('Create project', 'submit');
57
+ const cancel = button('Cancel');
58
+ this.newForm.append(this.newName, this.newKind, create, cancel);
59
+ const main = element('div', 'ck-mod-studio-main');
60
+ this.explorer = element('aside', 'ck-mod-studio-explorer');
61
+ const editorColumn = element('section', 'ck-mod-studio-editor-column');
62
+ this.tabs = element('div', 'ck-mod-studio-tabs');
63
+ this.editorHost = element('div', 'ck-mod-studio-editor');
64
+ editorColumn.append(this.tabs, this.editorHost);
65
+ const settings = element('aside', 'ck-mod-studio-settings');
66
+ const settingsTitle = element('h3');
67
+ settingsTitle.textContent = 'Project settings';
68
+ this.settingsName = input('Project name');
69
+ this.settingsDescription = input('Description');
70
+ this.serverModuleName = input('Server module name');
71
+ this.clientModuleName = input('Client module name');
72
+ this.pairing = select([
73
+ ['NONE', 'No pairing'],
74
+ ['OPTIONAL', 'Optional companion'],
75
+ ['REQUIRED', 'Require client companion'],
76
+ ]);
77
+ settings.append(settingsTitle, labeled('Name', this.settingsName), labeled('Description', this.settingsDescription), labeled('Server module', this.serverModuleName), labeled('Client module', this.clientModuleName), labeled('Pairing', this.pairing));
78
+ main.append(this.explorer, editorColumn, settings);
79
+ const bottom = element('section', 'ck-mod-studio-bottom');
80
+ const panelTabs = element('div', 'ck-mod-studio-panel-tabs');
81
+ this.problemsPanel = this.createPanel('problems', 'Problems', panelTabs);
82
+ this.buildPanel = this.createPanel('build', 'Build', panelTabs);
83
+ this.logsPanel = this.createPanel('logs', 'Logs', panelTabs);
84
+ this.runsPanel = this.createPanel('runs', 'Runs', panelTabs);
85
+ this.invokePanel = this.createPanel('invoke', 'Invoke', panelTabs);
86
+ const panelBody = element('div');
87
+ for (const panel of this.panels.values())
88
+ panelBody.append(panel);
89
+ bottom.append(panelTabs, panelBody);
90
+ this.invokeExport = input('Export name');
91
+ this.invokeExport.value = 'invoke';
92
+ this.invokeParams = document.createElement('textarea');
93
+ this.invokeParams.placeholder = '{"example": true}';
94
+ this.invokeParams.setAttribute('aria-label', 'Invoke JSON parameters');
95
+ const invokeButton = button('Invoke server export');
96
+ this.invokeResult = document.createElement('pre');
97
+ const invokeControls = element('div', 'ck-mod-studio-invoke');
98
+ invokeControls.append(this.invokeExport, this.invokeParams, invokeButton);
99
+ this.invokePanel.append(invokeControls, this.invokeResult);
100
+ this.root.append(toolbar, this.newForm, main, bottom);
101
+ host.appendChild(this.root);
102
+ newButton.addEventListener('click', () => {
103
+ this.newForm.dataset.open =
104
+ this.newForm.dataset.open === 'true' ? 'false' : 'true';
105
+ if (this.newForm.dataset.open === 'true')
106
+ this.newName.focus();
107
+ });
108
+ cancel.addEventListener('click', () => {
109
+ this.newForm.dataset.open = 'false';
110
+ });
111
+ this.newForm.addEventListener('submit', (event) => {
112
+ event.preventDefault();
113
+ void this.run(async () => {
114
+ await this.controller.createProject({
115
+ name: this.newName.value,
116
+ kind: this.newKind.value,
117
+ });
118
+ this.newName.value = '';
119
+ this.newForm.dataset.open = 'false';
120
+ });
121
+ });
122
+ this.projectSelect.addEventListener('change', () => {
123
+ void this.run(() => this.controller.switchProject(this.projectSelect.value));
124
+ });
125
+ this.testAction.addEventListener('click', () => void this.run(() => this.controller.testDraft()));
126
+ this.deployAction.addEventListener('click', () => void this.run(() => this.controller.deployLive()));
127
+ stop.addEventListener('click', () => void this.run(() => this.controller.stopProject()));
128
+ this.saveAction.addEventListener('click', () => {
129
+ void this.run(() => this.controller.getState().saveState === 'CONFLICT'
130
+ ? this.controller.overwriteConflict()
131
+ : this.controller.retrySave());
132
+ });
133
+ this.remoteAction.addEventListener('click', () => void this.run(() => this.controller.acceptRemoteConflict()));
134
+ this.settingsName.addEventListener('change', () => this.controller.updateSettings({ name: this.settingsName.value }));
135
+ this.settingsDescription.addEventListener('change', () => this.controller.updateSettings({
136
+ description: this.settingsDescription.value,
137
+ }));
138
+ this.serverModuleName.addEventListener('change', () => this.controller.updateSettings({
139
+ serverModuleName: this.serverModuleName.value,
140
+ }));
141
+ this.clientModuleName.addEventListener('change', () => this.controller.updateSettings({
142
+ clientModuleName: this.clientModuleName.value,
143
+ }));
144
+ this.pairing.addEventListener('change', () => this.controller.setPairingPreference(this.pairing.value));
145
+ invokeButton.addEventListener('click', () => {
146
+ void this.run(() => this.controller.invoke(this.invokeExport.value, this.invokeParams.value));
147
+ });
148
+ this.controller.setSurfaceVisible('usage', true);
149
+ this.activatePanel('problems');
150
+ }
151
+ render(state) {
152
+ if (this.disposed)
153
+ return;
154
+ this.renderProjects(state);
155
+ this.renderSaveState(state);
156
+ this.renderExplorer(state);
157
+ this.renderTabs(state);
158
+ this.renderSettings(state);
159
+ const projectTargetsAvailable = state.project
160
+ ? projectTargets(state.project.kind).every((target) => this.controller.canTarget(target, 'write'))
161
+ : false;
162
+ this.testAction.disabled = !projectTargetsAvailable;
163
+ this.deployAction.disabled = !projectTargetsAvailable;
164
+ this.renderProblems(state);
165
+ this.renderBuild(state);
166
+ this.renderRuntimeRows(this.logsPanel, state.logs);
167
+ this.renderRuntimeRows(this.runsPanel, state.runs);
168
+ this.invokeResult.textContent = state.invokeResult
169
+ ? formatInvokeResult(state.invokeResult)
170
+ : '';
171
+ this.runtimeStatus.textContent = [
172
+ state.runtime.phase,
173
+ state.runtime.target,
174
+ state.runtime.message,
175
+ ]
176
+ .filter(Boolean)
177
+ .join(' · ');
178
+ this.budgetStatus.textContent = budgetText(state);
179
+ }
180
+ dispose() {
181
+ if (this.disposed)
182
+ return;
183
+ this.disposed = true;
184
+ this.controller.setSurfaceVisible('usage', false);
185
+ this.controller.setSurfaceVisible('logs', false);
186
+ this.controller.setSurfaceVisible('runs', false);
187
+ this.root.remove();
188
+ }
189
+ createPanel(name, label, tabs) {
190
+ const tab = button(label);
191
+ tab.className = 'ck-mod-studio-panel-tab';
192
+ tab.addEventListener('click', () => this.activatePanel(name));
193
+ this.panelButtons.set(name, tab);
194
+ tabs.append(tab);
195
+ const panel = element('div', 'ck-mod-studio-panel');
196
+ panel.dataset.panel = name;
197
+ this.panels.set(name, panel);
198
+ return panel;
199
+ }
200
+ activatePanel(name) {
201
+ const previous = this.activePanel;
202
+ this.activePanel = name;
203
+ for (const [key, buttonElement] of this.panelButtons) {
204
+ buttonElement.dataset.active = String(key === name);
205
+ }
206
+ for (const [key, panel] of this.panels) {
207
+ panel.dataset.active = String(key === name);
208
+ }
209
+ const previousPoll = polledSurface(previous);
210
+ const nextPoll = polledSurface(name);
211
+ if (previousPoll && previousPoll !== nextPoll) {
212
+ this.controller.setSurfaceVisible(previousPoll, false);
213
+ }
214
+ if (nextPoll)
215
+ this.controller.setSurfaceVisible(nextPoll, true);
216
+ }
217
+ renderProjects(state) {
218
+ const selected = state.project?.projectId ?? '';
219
+ const options = state.projects.map((project) => {
220
+ const option = document.createElement('option');
221
+ option.value = project.projectId;
222
+ option.textContent = `${project.name} · ${project.kind
223
+ .toLowerCase()
224
+ .replace('_', ' ')}`;
225
+ return option;
226
+ });
227
+ if (options.length === 0) {
228
+ const empty = document.createElement('option');
229
+ empty.value = '';
230
+ empty.textContent = 'No projects yet';
231
+ options.push(empty);
232
+ }
233
+ this.projectSelect.replaceChildren(...options);
234
+ this.projectSelect.value = selected;
235
+ }
236
+ renderSaveState(state) {
237
+ const label = {
238
+ SAVING: 'Saving…',
239
+ SAVED: 'Saved',
240
+ CONFLICT: 'Conflict',
241
+ OFFLINE: 'Offline',
242
+ }[state.saveState];
243
+ this.saveBadge.dataset.state = state.saveState;
244
+ this.saveBadge.textContent = state.saveMessage
245
+ ? `${label}: ${state.saveMessage}`
246
+ : label;
247
+ this.saveAction.hidden = !['CONFLICT', 'OFFLINE'].includes(state.saveState);
248
+ this.saveAction.textContent =
249
+ state.saveState === 'CONFLICT' ? 'Keep my version' : 'Retry save';
250
+ this.remoteAction.hidden = state.saveState !== 'CONFLICT';
251
+ }
252
+ renderExplorer(state) {
253
+ this.explorer.replaceChildren();
254
+ if (!state.project) {
255
+ this.explorer.append(empty('Create a project to start authoring.'));
256
+ return;
257
+ }
258
+ for (const target of projectTargets(state.project.kind)) {
259
+ const files = state.project.files.filter((file) => file.target === target);
260
+ this.explorer.append(this.projectSection(target, files.map((file) => ({
261
+ source: 'PROJECT',
262
+ target: file.target,
263
+ path: file.path,
264
+ }))));
265
+ }
266
+ this.explorer.append(this.referenceSection('Personal library', state.personalLibraryFiles), this.referenceSection('Common files', state.commonFiles));
267
+ }
268
+ projectSection(target, refs) {
269
+ const section = element('section', 'ck-mod-studio-section');
270
+ const header = element('div', 'ck-mod-studio-section-header');
271
+ const title = document.createElement('span');
272
+ title.textContent = `${target} files`;
273
+ const add = button('+ File');
274
+ add.setAttribute('aria-label', `Add ${target} file`);
275
+ add.disabled = !this.controller.canTarget(target, 'write');
276
+ add.addEventListener('click', () => {
277
+ const path = window.prompt(`New ${target} file path`, 'src/new.rs');
278
+ if (!path)
279
+ return;
280
+ void this.run(() => Promise.resolve(this.controller.addFile(target, path)));
281
+ });
282
+ header.append(title, add);
283
+ section.append(header);
284
+ for (const ref of refs) {
285
+ section.append(this.projectFileRow(ref));
286
+ }
287
+ if (refs.length === 0)
288
+ section.append(empty('No files'));
289
+ return section;
290
+ }
291
+ projectFileRow(ref) {
292
+ const row = element('div', 'ck-mod-studio-file');
293
+ const open = button(ref.path);
294
+ open.title = `${ref.target}:${ref.path}`;
295
+ open.addEventListener('click', () => this.controller.openFile(ref));
296
+ const rename = button('✎');
297
+ rename.setAttribute('aria-label', `Rename ${ref.path}`);
298
+ rename.addEventListener('click', () => {
299
+ const next = window.prompt('Rename file', ref.path);
300
+ if (!next || !ref.target)
301
+ return;
302
+ void this.run(() => Promise.resolve(this.controller.renameFile(ref.target, ref.path, next)));
303
+ });
304
+ const remove = button('×');
305
+ remove.setAttribute('aria-label', `Delete ${ref.path}`);
306
+ remove.addEventListener('click', () => {
307
+ if (!ref.target ||
308
+ !window.confirm(`Delete ${ref.target}:${ref.path}?`)) {
309
+ return;
310
+ }
311
+ void this.run(() => Promise.resolve(this.controller.deleteFile(ref.target, ref.path)));
312
+ });
313
+ const library = button('Library');
314
+ library.setAttribute('aria-label', `Save ${ref.path} to My Library`);
315
+ library.addEventListener('click', () => {
316
+ if (!ref.target)
317
+ return;
318
+ const title = window.prompt('Library file title', ref.path.split('/').at(-1) ?? ref.path);
319
+ if (title == null)
320
+ return;
321
+ void this.run(() => this.controller.saveProjectFileToLibrary(ref.target, ref.path, title));
322
+ });
323
+ row.append(open, library, rename, remove);
324
+ return row;
325
+ }
326
+ referenceSection(titleText, files) {
327
+ const section = element('section', 'ck-mod-studio-section');
328
+ const header = element('div', 'ck-mod-studio-section-header');
329
+ header.textContent = titleText;
330
+ section.append(header);
331
+ for (const file of files) {
332
+ const ref = {
333
+ source: file.source,
334
+ target: file.target,
335
+ path: file.path,
336
+ referenceId: file.id,
337
+ };
338
+ const row = element('div', 'ck-mod-studio-file');
339
+ const open = button(`${file.target ? `${file.target.toLowerCase()}/` : ''}${file.path}`);
340
+ open.addEventListener('click', () => this.controller.openFile(ref));
341
+ const add = button('Add');
342
+ add.setAttribute('aria-label', `Add ${file.title} to project`);
343
+ add.addEventListener('click', () => {
344
+ const destination = window.prompt('Destination project path', file.path);
345
+ if (!destination)
346
+ return;
347
+ void this.run(() => this.controller.importReferenceFile(file, destination));
348
+ });
349
+ row.append(open, add);
350
+ section.append(row);
351
+ }
352
+ if (files.length === 0)
353
+ section.append(empty('No files'));
354
+ return section;
355
+ }
356
+ renderTabs(state) {
357
+ this.tabs.replaceChildren();
358
+ for (const ref of state.openFiles) {
359
+ const tab = button(`${ref.target ? `${ref.target.toLowerCase()}/` : ''}${ref.path}`);
360
+ tab.className = 'ck-mod-studio-tab';
361
+ tab.dataset.active = String(Boolean(state.activeFile && sameRef(state.activeFile, ref)));
362
+ tab.addEventListener('click', () => this.controller.openFile(ref));
363
+ const close = document.createElement('span');
364
+ close.textContent = '×';
365
+ close.setAttribute('role', 'button');
366
+ close.setAttribute('aria-label', `Close ${ref.path}`);
367
+ close.addEventListener('click', (event) => {
368
+ event.stopPropagation();
369
+ this.controller.closeFile(ref);
370
+ });
371
+ tab.append(close);
372
+ this.tabs.append(tab);
373
+ }
374
+ }
375
+ renderSettings(state) {
376
+ const project = state.project;
377
+ const disabled = !project;
378
+ for (const control of [
379
+ this.settingsName,
380
+ this.settingsDescription,
381
+ this.serverModuleName,
382
+ this.clientModuleName,
383
+ this.pairing,
384
+ ]) {
385
+ control.disabled = disabled;
386
+ }
387
+ if (!project)
388
+ return;
389
+ setInputUnlessFocused(this.settingsName, project.metadata.name);
390
+ setInputUnlessFocused(this.settingsDescription, project.metadata.description ?? '');
391
+ setInputUnlessFocused(this.serverModuleName, project.metadata.serverModuleName ?? '');
392
+ setInputUnlessFocused(this.clientModuleName, project.metadata.clientModuleName ?? '');
393
+ this.serverModuleName.disabled = !projectTargets(project.kind).includes('SERVER');
394
+ this.clientModuleName.disabled = !projectTargets(project.kind).includes('CLIENT');
395
+ this.pairing.disabled = project.kind !== 'FULL_STACK';
396
+ this.pairing.value = project.metadata.pairingPreference;
397
+ }
398
+ renderProblems(state) {
399
+ this.problemsPanel.replaceChildren();
400
+ const diagnostics = [
401
+ ...state.authoritativeDiagnostics,
402
+ ...state.localDiagnostics,
403
+ ];
404
+ if (diagnostics.length === 0) {
405
+ this.problemsPanel.append(empty('No problems.'));
406
+ return;
407
+ }
408
+ for (const diagnostic of diagnostics) {
409
+ const row = element('button', 'ck-mod-studio-problem');
410
+ row.dataset.source = diagnostic.source;
411
+ const source = document.createElement('span');
412
+ source.textContent =
413
+ diagnostic.source === 'rustc' ? 'rustc' : 'advisory';
414
+ const location = document.createElement('span');
415
+ location.textContent = `${diagnostic.target.toLowerCase()}/${diagnostic.path}:${diagnostic.line}:${diagnostic.column}`;
416
+ const message = document.createElement('span');
417
+ message.textContent = diagnostic.message;
418
+ row.append(source, location, message);
419
+ row.addEventListener('click', () => this.controller.openFile({
420
+ source: 'PROJECT',
421
+ target: diagnostic.target,
422
+ path: diagnostic.path,
423
+ }));
424
+ this.problemsPanel.append(row);
425
+ }
426
+ }
427
+ renderBuild(state) {
428
+ this.buildPanel.replaceChildren();
429
+ const output = document.createElement('pre');
430
+ output.textContent = state.buildOutput || 'No build has run.';
431
+ this.buildPanel.append(output);
432
+ }
433
+ renderRuntimeRows(panel, rows) {
434
+ panel.replaceChildren();
435
+ if (rows.length === 0) {
436
+ panel.append(empty('No runtime records.'));
437
+ return;
438
+ }
439
+ for (const row of rows) {
440
+ const line = document.createElement('pre');
441
+ line.textContent = `${row.success ? '✓' : '✗'} ${row.startedAt} ${row.moduleName} ${row.triggerSource} · ${row.durationUs}µs · ${row.fuelUsed} fuel${row.errorMessage ? `\n${row.errorMessage}` : ''}`;
442
+ panel.append(line);
443
+ }
444
+ }
445
+ async run(operation) {
446
+ try {
447
+ await operation();
448
+ }
449
+ catch (error) {
450
+ this.runtimeStatus.textContent =
451
+ error instanceof Error ? error.message : String(error);
452
+ }
453
+ }
454
+ }
455
+ function polledSurface(panel) {
456
+ if (panel === 'logs' || panel === 'runs')
457
+ return panel;
458
+ return null;
459
+ }
460
+ function budgetText(state) {
461
+ const usage = state.usage
462
+ ? `units ${state.usage.hourUnitsUsed}/${state.usage.unitsPerHour ?? '∞'} · compiles ${state.usage.compilesThisHour}/${state.usage.maxCompilesPerHour}`
463
+ : '';
464
+ const wallet = state.wallet
465
+ ? `wallet ${state.wallet.balanceCents} ${state.wallet.currency}`
466
+ : '';
467
+ return [usage, wallet].filter(Boolean).join(' · ');
468
+ }
469
+ function formatInvokeResult(result) {
470
+ return [
471
+ result.resultJson ?? result.resultBase64 ?? '(empty result)',
472
+ result.fuelUsed ? `${result.fuelUsed} fuel` : '',
473
+ result.durationUs !== undefined ? `${result.durationUs}µs` : '',
474
+ ]
475
+ .filter(Boolean)
476
+ .join('\n');
477
+ }
478
+ function sameRef(a, b) {
479
+ return (a.source === b.source &&
480
+ a.target === b.target &&
481
+ a.path === b.path &&
482
+ a.referenceId === b.referenceId);
483
+ }
484
+ function element(tag, className) {
485
+ const value = document.createElement(tag);
486
+ if (className)
487
+ value.className = className;
488
+ return value;
489
+ }
490
+ function button(label, type = 'button') {
491
+ const value = document.createElement('button');
492
+ value.type = type;
493
+ value.textContent = label;
494
+ return value;
495
+ }
496
+ function input(placeholder) {
497
+ const value = document.createElement('input');
498
+ value.placeholder = placeholder;
499
+ return value;
500
+ }
501
+ function labeled(label, control) {
502
+ const value = document.createElement('label');
503
+ const text = document.createElement('span');
504
+ text.textContent = label;
505
+ value.append(text, control);
506
+ return value;
507
+ }
508
+ function select(options) {
509
+ const value = document.createElement('select');
510
+ for (const [optionValue, label] of options) {
511
+ const option = document.createElement('option');
512
+ option.value = optionValue;
513
+ option.textContent = label;
514
+ value.append(option);
515
+ }
516
+ return value;
517
+ }
518
+ function empty(message) {
519
+ const value = element('div', 'ck-mod-studio-empty');
520
+ value.textContent = message;
521
+ return value;
522
+ }
523
+ function setInputUnlessFocused(inputElement, value) {
524
+ if (document.activeElement !== inputElement && inputElement.value !== value) {
525
+ inputElement.value = value;
526
+ }
527
+ }
@@ -0,0 +1,17 @@
1
+ import type { ModStudioState } from './controller.js';
2
+ import type { ModStudioFileRef } from './models.js';
3
+ export type ModStudioEditorMode = 'monaco' | 'textarea';
4
+ /** Editor implementation used by the DOM mount. */
5
+ export interface ModStudioEditorAdapter {
6
+ readonly mode: ModStudioEditorMode;
7
+ sync(state: ModStudioState): void;
8
+ layout(): void;
9
+ dispose(): void;
10
+ }
11
+ export interface ModStudioEditorCallbacks {
12
+ onProjectFileChange(target: 'SERVER' | 'CLIENT', path: string, content: string): void;
13
+ onLocalDiagnostics(diagnostics: ModStudioState['localDiagnostics']): void;
14
+ onOpenFile(ref: ModStudioFileRef): void;
15
+ onFailure?(error: Error): void;
16
+ }
17
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/mod-studio/editor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAExD,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,IAAI,CAAC;IACR,kBAAkB,CAChB,WAAW,EAAE,cAAc,CAAC,kBAAkB,CAAC,GAC9C,IAAI,CAAC;IACR,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,SAAS,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAChC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ export { ModStudioController, type ModStudioControllerOptions, type ModStudioBroker, type ModStudioInvokeResult, type ModStudioPhase, type ModStudioPolledSurface, type ModStudioRun, type ModStudioRuntimeStatus, type ModStudioPlayerCompute, type ModStudioPlayerWallet, type ModStudioState, type ModStudioStopResult, type ModStudioUsageSnapshot, type ModStudioWalletSnapshot, } from './controller.js';
2
+ export { mountModStudio, type ModStudioHandle, type MountModStudioOptions, } from './mount.js';
3
+ export { ModStudioOfflineError, ModStudioRevisionConflictError, cloneModStudioProject, modStudioFileKey, modStudioFileUri, normalizeModStudioPath, projectTargets, type CreateModStudioProjectInput, type ImportModStudioReferenceFileInput, type ModStudioFileRef, type ModStudioPairingPreference, type ModStudioProject, type ModStudioProjectFile, type ModStudioProjectKind, type ModStudioProjectMetadata, type ModStudioProjectProvider, type ModStudioProjectRevision, type ModStudioProjectScope, type ModStudioProjectSummary, type ModStudioReferenceFile, type ModStudioSaveState, type ModStudioTarget, type SaveModStudioLibraryFileInput, type SaveModStudioProjectInput, } from './models.js';
4
+ export { createModStudioStarterProject, type ModStudioNewProjectOptions, } from './starter-projects.js';
5
+ export { parseRustcDiagnostics, type ModStudioDiagnostic, type ModStudioDiagnosticSeverity, type ModStudioDiagnosticSource, } from './diagnostics.js';
6
+ export { isCurrentDiagnosticVersion, type MonacoModStudioEditorOptions, } from './monaco-editor.js';
7
+ export { EMBEDDED_PLATFORM_INDEX, MAX_PLATFORM_CRATES, MAX_PLATFORM_CRATE_FIELD_LENGTH, MAX_PLATFORM_INDEX_BYTES, computePlatformIndexContentHash, loadPlatformIndex, type PlatformCrate, type PlatformIndex, type PlatformSymbol, type PlatformSymbolKind, } from '../live-coding/platform-index.js';
8
+ export { DEFAULT_VFS_LIMITS, VfsLimitError, VirtualFileSystem, offsetAt, type VirtualDocument, type VirtualFileSystemLimits, } from '../live-coding/vfs.js';
9
+ export { WorkerLanguageClient, WorkerMessageReader, WorkerMessageWriter, createDefaultRustLanguageWorker, type LanguageWorkerLike, type WorkerLanguageClientOptions, } from '../live-coding/worker-transport.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mod-studio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,8BAA8B,EAC9B,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,KAAK,2BAA2B,EAChC,KAAK,iCAAiC,EACtC,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,GAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,6BAA6B,EAC7B,KAAK,0BAA0B,GAChC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,KAAK,4BAA4B,GAClC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,+BAA+B,EAC/B,wBAAwB,EACxB,+BAA+B,EAC/B,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,+BAA+B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,GACjC,MAAM,oCAAoC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { ModStudioController, } from './controller.js';
2
+ export { mountModStudio, } from './mount.js';
3
+ export { ModStudioOfflineError, ModStudioRevisionConflictError, cloneModStudioProject, modStudioFileKey, modStudioFileUri, normalizeModStudioPath, projectTargets, } from './models.js';
4
+ export { createModStudioStarterProject, } from './starter-projects.js';
5
+ export { parseRustcDiagnostics, } from './diagnostics.js';
6
+ export { isCurrentDiagnosticVersion, } from './monaco-editor.js';
7
+ export { EMBEDDED_PLATFORM_INDEX, MAX_PLATFORM_CRATES, MAX_PLATFORM_CRATE_FIELD_LENGTH, MAX_PLATFORM_INDEX_BYTES, computePlatformIndexContentHash, loadPlatformIndex, } from '../live-coding/platform-index.js';
8
+ export { DEFAULT_VFS_LIMITS, VfsLimitError, VirtualFileSystem, offsetAt, } from '../live-coding/vfs.js';
9
+ export { WorkerLanguageClient, WorkerMessageReader, WorkerMessageWriter, createDefaultRustLanguageWorker, } from '../live-coding/worker-transport.js';