@crowdedkingdoms/crowdyjs 9.0.0 → 11.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 +60 -38
  2. package/README.md +86 -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/crowdy-studio/controller.d.ts +188 -0
  7. package/dist/crowdy-studio/controller.d.ts.map +1 -0
  8. package/dist/crowdy-studio/controller.js +915 -0
  9. package/dist/crowdy-studio/diagnostics.d.ts +22 -0
  10. package/dist/crowdy-studio/diagnostics.d.ts.map +1 -0
  11. package/dist/crowdy-studio/diagnostics.js +141 -0
  12. package/dist/crowdy-studio/dom-shell.d.ts +55 -0
  13. package/dist/crowdy-studio/dom-shell.d.ts.map +1 -0
  14. package/dist/crowdy-studio/dom-shell.js +527 -0
  15. package/dist/crowdy-studio/editor.d.ts +17 -0
  16. package/dist/crowdy-studio/editor.d.ts.map +1 -0
  17. package/dist/crowdy-studio/editor.js +1 -0
  18. package/dist/crowdy-studio/index.d.ts +10 -0
  19. package/dist/crowdy-studio/index.d.ts.map +1 -0
  20. package/dist/crowdy-studio/index.js +9 -0
  21. package/dist/crowdy-studio/models.d.ts +149 -0
  22. package/dist/crowdy-studio/models.d.ts.map +1 -0
  23. package/dist/crowdy-studio/models.js +62 -0
  24. package/dist/crowdy-studio/monaco-editor.d.ts +16 -0
  25. package/dist/crowdy-studio/monaco-editor.d.ts.map +1 -0
  26. package/dist/crowdy-studio/monaco-editor.js +548 -0
  27. package/dist/crowdy-studio/mount.d.ts +17 -0
  28. package/dist/crowdy-studio/mount.d.ts.map +1 -0
  29. package/dist/crowdy-studio/mount.js +86 -0
  30. package/dist/crowdy-studio/starter-projects.d.ts +11 -0
  31. package/dist/crowdy-studio/starter-projects.d.ts.map +1 -0
  32. package/dist/crowdy-studio/starter-projects.js +102 -0
  33. package/dist/crowdy-studio/styles.d.ts +2 -0
  34. package/dist/crowdy-studio/styles.d.ts.map +1 -0
  35. package/dist/crowdy-studio/styles.js +14 -0
  36. package/dist/crowdy-studio/textarea-editor.d.ts +8 -0
  37. package/dist/crowdy-studio/textarea-editor.d.ts.map +1 -0
  38. package/dist/crowdy-studio/textarea-editor.js +71 -0
  39. package/dist/domains/crowdyStudio.d.ts +27 -0
  40. package/dist/domains/crowdyStudio.d.ts.map +1 -0
  41. package/dist/domains/crowdyStudio.js +301 -0
  42. package/dist/domains/playerCompute.d.ts +1 -1
  43. package/dist/domains/playerCompute.js +1 -1
  44. package/dist/generated/graphql.d.ts +792 -7
  45. package/dist/generated/graphql.d.ts.map +1 -1
  46. package/dist/generated/graphql.js +57 -0
  47. package/dist/index.d.ts +3 -5
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +3 -5
  50. package/dist/kit/npcs.d.ts.map +1 -1
  51. package/dist/kit/social.d.ts.map +1 -1
  52. package/dist/live-coding/rust-analysis.d.ts.map +1 -1
  53. package/dist/live-coding/rust-analysis.js +64 -1
  54. package/dist/live-coding/worker-transport.d.ts +3 -0
  55. package/dist/live-coding/worker-transport.d.ts.map +1 -1
  56. package/dist/live-coding/worker-transport.js +13 -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,102 @@
1
+ import { projectTargets, } from './models.js';
2
+ const SDK_VERSION = '0.1.5';
3
+ /** Create a compile-oriented starter without introducing a raw JSON source map. */
4
+ export function createCrowdyStudioStarterProject(options) {
5
+ const base = moduleName(options.name);
6
+ const targets = projectTargets(options.kind);
7
+ const metadata = {
8
+ name: options.name.trim() || 'Untitled mod',
9
+ ...(options.description?.trim()
10
+ ? { description: options.description.trim() }
11
+ : {}),
12
+ ...(targets.includes('SERVER')
13
+ ? { serverModuleName: `${base}-server` }
14
+ : {}),
15
+ ...(targets.includes('CLIENT')
16
+ ? { clientModuleName: `${base}-client` }
17
+ : {}),
18
+ pairingPreference: options.kind === 'FULL_STACK' ? 'REQUIRED' : 'NONE',
19
+ };
20
+ return {
21
+ appId: options.appId,
22
+ gridId: options.gridId,
23
+ kind: options.kind,
24
+ metadata,
25
+ files: targets.flatMap((target) => starterFiles(target, target === 'SERVER'
26
+ ? metadata.serverModuleName
27
+ : metadata.clientModuleName)),
28
+ };
29
+ }
30
+ function starterFiles(target, name) {
31
+ return [
32
+ {
33
+ target,
34
+ path: 'Cargo.toml',
35
+ content: `[package]
36
+ name = "${name}"
37
+ version = "0.1.0"
38
+ edition = "2021"
39
+
40
+ [lib]
41
+ crate-type = ["cdylib"]
42
+
43
+ [dependencies]
44
+ crowdy-compute-sdk = "${SDK_VERSION}"
45
+ `,
46
+ },
47
+ {
48
+ target,
49
+ path: 'src/lib.rs',
50
+ content: target === 'SERVER' ? serverSource() : clientSource(),
51
+ },
52
+ ];
53
+ }
54
+ function serverSource() {
55
+ return `use crowdy_compute_sdk as crowdy;
56
+
57
+ fn on_init() {
58
+ // Runs once when this SERVER module starts on the owned grid.
59
+ }
60
+
61
+ fn on_tick(_dt_ms: u32) {
62
+ // Server host calls are permission checked and clamped to the owned grid.
63
+ // Type "crowdy::" for the platform-indexed host-call surface.
64
+ }
65
+
66
+ fn on_invoke(payload: &[u8]) -> Vec<u8> {
67
+ // Called by Crowdy Studio's Invoke panel or an allowed game caller.
68
+ payload.to_vec()
69
+ }
70
+
71
+ crowdy::register_module!(init: on_init, tick: on_tick, invoke: on_invoke);
72
+ `;
73
+ }
74
+ function clientSource() {
75
+ return `use crowdy_compute_sdk as crowdy;
76
+
77
+ fn on_init() {
78
+ // Runs after the hash-bound CLIENT artifact enters the browser sandbox.
79
+ }
80
+
81
+ fn on_tick(_dt_ms: u32) {
82
+ // Client host calls are allow-listed by PlayerCodeBroker. Presentation
83
+ // effects (for example HUD updates) never receive the page's app token.
84
+ // Type "crowdy::" for lifecycle and host-call completions.
85
+ }
86
+
87
+ fn on_invoke(payload: &[u8]) -> Vec<u8> {
88
+ payload.to_vec()
89
+ }
90
+
91
+ crowdy::register_module!(init: on_init, tick: on_tick, invoke: on_invoke);
92
+ `;
93
+ }
94
+ function moduleName(value) {
95
+ const slug = value
96
+ .trim()
97
+ .toLowerCase()
98
+ .replace(/[^a-z0-9]+/gu, '-')
99
+ .replace(/^-+|-+$/gu, '')
100
+ .slice(0, 48);
101
+ return slug || 'player-mod';
102
+ }
@@ -0,0 +1,2 @@
1
+ export declare const CROWDY_STUDIO_STYLES = "\n.ck-crowdy-studio{--ck-bg:#111827;--ck-panel:#182235;--ck-line:#334155;--ck-text:#e5e7eb;--ck-muted:#94a3b8;--ck-accent:#38bdf8;display:grid;grid-template-rows:auto auto minmax(360px,1fr) minmax(150px,.36fr);min-height:680px;background:var(--ck-bg);color:var(--ck-text);font:13px/1.4 ui-sans-serif,system-ui,sans-serif;border:1px solid var(--ck-line)}\n.ck-crowdy-studio *{box-sizing:border-box}.ck-crowdy-studio button,.ck-crowdy-studio input,.ck-crowdy-studio select,.ck-crowdy-studio textarea{font:inherit}.ck-crowdy-studio button,.ck-crowdy-studio select,.ck-crowdy-studio input{background:#0f172a;color:var(--ck-text);border:1px solid var(--ck-line);border-radius:4px;padding:5px 8px}.ck-crowdy-studio button{cursor:pointer}.ck-crowdy-studio button:hover{border-color:var(--ck-accent)}.ck-crowdy-studio button:disabled{opacity:.5;cursor:not-allowed}\n.ck-crowdy-studio-toolbar,.ck-crowdy-studio-actions,.ck-crowdy-studio-tabs,.ck-crowdy-studio-panel-tabs{display:flex;align-items:center;gap:6px;padding:7px;border-bottom:1px solid var(--ck-line)}.ck-crowdy-studio-toolbar{justify-content:space-between;flex-wrap:wrap}.ck-crowdy-studio-project-tools,.ck-crowdy-studio-runtime-tools{display:flex;align-items:center;gap:6px;flex-wrap:wrap}\n.ck-crowdy-studio-save[data-state=SAVED]{color:#86efac}.ck-crowdy-studio-save[data-state=SAVING]{color:#fde68a}.ck-crowdy-studio-save[data-state=CONFLICT]{color:#fca5a5}.ck-crowdy-studio-save[data-state=OFFLINE]{color:#fdba74}\n.ck-crowdy-studio-main{display:grid;grid-template-columns:230px minmax(0,1fr) 260px;min-height:0}.ck-crowdy-studio-explorer,.ck-crowdy-studio-settings{background:var(--ck-panel);overflow:auto;padding:8px}.ck-crowdy-studio-explorer{border-right:1px solid var(--ck-line)}.ck-crowdy-studio-settings{border-left:1px solid var(--ck-line)}.ck-crowdy-studio-editor-column{display:grid;grid-template-rows:auto minmax(0,1fr);min-width:0}\n.ck-crowdy-studio-editor{min-height:0;position:relative}.ck-crowdy-studio-textarea{width:100%;height:100%;min-height:330px;resize:none;background:#0b1020;color:var(--ck-text);border:0;padding:12px;font:13px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace}.ck-crowdy-studio-editor-notice{padding:4px 8px;background:#78350f;color:#ffedd5}\n.ck-crowdy-studio-section{margin-bottom:12px}.ck-crowdy-studio-section-header{display:flex;align-items:center;justify-content:space-between;color:var(--ck-muted);font-weight:700;text-transform:uppercase;font-size:11px;margin-bottom:4px}.ck-crowdy-studio-file{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:3px;align-items:center}.ck-crowdy-studio-file>button:first-child{text-align:left;overflow:hidden;text-overflow:ellipsis;border:0;background:transparent}.ck-crowdy-studio-file>button:not(:first-child){padding:1px 4px}\n.ck-crowdy-studio-tabs{padding:4px;overflow:auto}.ck-crowdy-studio-tab[data-active=true],.ck-crowdy-studio-panel-tab[data-active=true]{border-color:var(--ck-accent);color:#bae6fd}.ck-crowdy-studio-tab{white-space:nowrap}.ck-crowdy-studio-tab span{margin-left:7px;color:var(--ck-muted)}\n.ck-crowdy-studio-settings label{display:grid;gap:3px;margin-bottom:9px;color:var(--ck-muted)}.ck-crowdy-studio-settings input,.ck-crowdy-studio-settings select{width:100%}.ck-crowdy-studio-new{display:none;gap:6px;align-items:center;width:100%;padding:7px;border-bottom:1px solid var(--ck-line)}.ck-crowdy-studio-new[data-open=true]{display:flex}.ck-crowdy-studio-new input{flex:1}\n.ck-crowdy-studio-bottom{display:grid;grid-template-rows:auto minmax(0,1fr);min-height:0;border-top:1px solid var(--ck-line)}.ck-crowdy-studio-panel{display:none;overflow:auto;padding:8px}.ck-crowdy-studio-panel[data-active=true]{display:block}.ck-crowdy-studio-panel pre{white-space:pre-wrap;margin:0;font:12px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace}.ck-crowdy-studio-problem{display:grid;grid-template-columns:auto auto 1fr;gap:8px;padding:3px;border-bottom:1px solid #243247}.ck-crowdy-studio-problem[data-source=rustc]{color:#fecaca}.ck-crowdy-studio-problem[data-source=local-advisory]{color:#fde68a}\n.ck-crowdy-studio-status{color:var(--ck-muted)}.ck-crowdy-studio-invoke{display:grid;grid-template-columns:180px 1fr auto;gap:6px}.ck-crowdy-studio-invoke textarea{min-height:70px;background:#0f172a;color:var(--ck-text);border:1px solid var(--ck-line)}.ck-crowdy-studio-empty{color:var(--ck-muted);padding:8px}\n@media(max-width:900px){.ck-crowdy-studio-main{grid-template-columns:180px minmax(0,1fr)}.ck-crowdy-studio-settings{display:none}}@media(max-width:620px){.ck-crowdy-studio-main{grid-template-columns:1fr}.ck-crowdy-studio-explorer{display:none}}\n";
2
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,6hJAahC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export const CROWDY_STUDIO_STYLES = `
2
+ .ck-crowdy-studio{--ck-bg:#111827;--ck-panel:#182235;--ck-line:#334155;--ck-text:#e5e7eb;--ck-muted:#94a3b8;--ck-accent:#38bdf8;display:grid;grid-template-rows:auto auto minmax(360px,1fr) minmax(150px,.36fr);min-height:680px;background:var(--ck-bg);color:var(--ck-text);font:13px/1.4 ui-sans-serif,system-ui,sans-serif;border:1px solid var(--ck-line)}
3
+ .ck-crowdy-studio *{box-sizing:border-box}.ck-crowdy-studio button,.ck-crowdy-studio input,.ck-crowdy-studio select,.ck-crowdy-studio textarea{font:inherit}.ck-crowdy-studio button,.ck-crowdy-studio select,.ck-crowdy-studio input{background:#0f172a;color:var(--ck-text);border:1px solid var(--ck-line);border-radius:4px;padding:5px 8px}.ck-crowdy-studio button{cursor:pointer}.ck-crowdy-studio button:hover{border-color:var(--ck-accent)}.ck-crowdy-studio button:disabled{opacity:.5;cursor:not-allowed}
4
+ .ck-crowdy-studio-toolbar,.ck-crowdy-studio-actions,.ck-crowdy-studio-tabs,.ck-crowdy-studio-panel-tabs{display:flex;align-items:center;gap:6px;padding:7px;border-bottom:1px solid var(--ck-line)}.ck-crowdy-studio-toolbar{justify-content:space-between;flex-wrap:wrap}.ck-crowdy-studio-project-tools,.ck-crowdy-studio-runtime-tools{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
5
+ .ck-crowdy-studio-save[data-state=SAVED]{color:#86efac}.ck-crowdy-studio-save[data-state=SAVING]{color:#fde68a}.ck-crowdy-studio-save[data-state=CONFLICT]{color:#fca5a5}.ck-crowdy-studio-save[data-state=OFFLINE]{color:#fdba74}
6
+ .ck-crowdy-studio-main{display:grid;grid-template-columns:230px minmax(0,1fr) 260px;min-height:0}.ck-crowdy-studio-explorer,.ck-crowdy-studio-settings{background:var(--ck-panel);overflow:auto;padding:8px}.ck-crowdy-studio-explorer{border-right:1px solid var(--ck-line)}.ck-crowdy-studio-settings{border-left:1px solid var(--ck-line)}.ck-crowdy-studio-editor-column{display:grid;grid-template-rows:auto minmax(0,1fr);min-width:0}
7
+ .ck-crowdy-studio-editor{min-height:0;position:relative}.ck-crowdy-studio-textarea{width:100%;height:100%;min-height:330px;resize:none;background:#0b1020;color:var(--ck-text);border:0;padding:12px;font:13px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace}.ck-crowdy-studio-editor-notice{padding:4px 8px;background:#78350f;color:#ffedd5}
8
+ .ck-crowdy-studio-section{margin-bottom:12px}.ck-crowdy-studio-section-header{display:flex;align-items:center;justify-content:space-between;color:var(--ck-muted);font-weight:700;text-transform:uppercase;font-size:11px;margin-bottom:4px}.ck-crowdy-studio-file{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:3px;align-items:center}.ck-crowdy-studio-file>button:first-child{text-align:left;overflow:hidden;text-overflow:ellipsis;border:0;background:transparent}.ck-crowdy-studio-file>button:not(:first-child){padding:1px 4px}
9
+ .ck-crowdy-studio-tabs{padding:4px;overflow:auto}.ck-crowdy-studio-tab[data-active=true],.ck-crowdy-studio-panel-tab[data-active=true]{border-color:var(--ck-accent);color:#bae6fd}.ck-crowdy-studio-tab{white-space:nowrap}.ck-crowdy-studio-tab span{margin-left:7px;color:var(--ck-muted)}
10
+ .ck-crowdy-studio-settings label{display:grid;gap:3px;margin-bottom:9px;color:var(--ck-muted)}.ck-crowdy-studio-settings input,.ck-crowdy-studio-settings select{width:100%}.ck-crowdy-studio-new{display:none;gap:6px;align-items:center;width:100%;padding:7px;border-bottom:1px solid var(--ck-line)}.ck-crowdy-studio-new[data-open=true]{display:flex}.ck-crowdy-studio-new input{flex:1}
11
+ .ck-crowdy-studio-bottom{display:grid;grid-template-rows:auto minmax(0,1fr);min-height:0;border-top:1px solid var(--ck-line)}.ck-crowdy-studio-panel{display:none;overflow:auto;padding:8px}.ck-crowdy-studio-panel[data-active=true]{display:block}.ck-crowdy-studio-panel pre{white-space:pre-wrap;margin:0;font:12px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace}.ck-crowdy-studio-problem{display:grid;grid-template-columns:auto auto 1fr;gap:8px;padding:3px;border-bottom:1px solid #243247}.ck-crowdy-studio-problem[data-source=rustc]{color:#fecaca}.ck-crowdy-studio-problem[data-source=local-advisory]{color:#fde68a}
12
+ .ck-crowdy-studio-status{color:var(--ck-muted)}.ck-crowdy-studio-invoke{display:grid;grid-template-columns:180px 1fr auto;gap:6px}.ck-crowdy-studio-invoke textarea{min-height:70px;background:#0f172a;color:var(--ck-text);border:1px solid var(--ck-line)}.ck-crowdy-studio-empty{color:var(--ck-muted);padding:8px}
13
+ @media(max-width:900px){.ck-crowdy-studio-main{grid-template-columns:180px minmax(0,1fr)}.ck-crowdy-studio-settings{display:none}}@media(max-width:620px){.ck-crowdy-studio-main{grid-template-columns:1fr}.ck-crowdy-studio-explorer{display:none}}
14
+ `;
@@ -0,0 +1,8 @@
1
+ import type { CrowdyStudioEditorAdapter, CrowdyStudioEditorCallbacks } from './editor.js';
2
+ /**
3
+ * Target/file-aware fallback used when Monaco or the local Rust worker cannot
4
+ * start. It edits the active source file directly; project tabs and explorer
5
+ * continue to work and no JSON source blob is exposed.
6
+ */
7
+ export declare function createTextareaCrowdyStudioEditor(host: HTMLElement, callbacks: CrowdyStudioEditorCallbacks): CrowdyStudioEditorAdapter;
8
+ //# sourceMappingURL=textarea-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea-editor.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/textarea-editor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAC5B,MAAM,aAAa,CAAC;AAGrB;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,2BAA2B,GACrC,yBAAyB,CAwD3B"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Target/file-aware fallback used when Monaco or the local Rust worker cannot
3
+ * start. It edits the active source file directly; project tabs and explorer
4
+ * continue to work and no JSON source blob is exposed.
5
+ */
6
+ export function createTextareaCrowdyStudioEditor(host, callbacks) {
7
+ const notice = document.createElement('div');
8
+ notice.className = 'ck-crowdy-studio-editor-notice';
9
+ notice.textContent =
10
+ 'Basic editor active — Monaco or the local Rust worker was unavailable.';
11
+ const textarea = document.createElement('textarea');
12
+ textarea.className = 'ck-crowdy-studio-textarea';
13
+ textarea.rows = 24;
14
+ textarea.spellcheck = false;
15
+ textarea.setAttribute('aria-label', 'Project source editor');
16
+ host.replaceChildren(notice, textarea);
17
+ let active = null;
18
+ let disposed = false;
19
+ const onInput = () => {
20
+ if (disposed ||
21
+ active?.source !== 'PROJECT' ||
22
+ !active.target) {
23
+ return;
24
+ }
25
+ callbacks.onProjectFileChange(active.target, active.path, textarea.value);
26
+ };
27
+ textarea.addEventListener('input', onInput);
28
+ return {
29
+ mode: 'textarea',
30
+ sync(state) {
31
+ if (disposed)
32
+ return;
33
+ const next = state.activeFile;
34
+ active = next;
35
+ if (!next) {
36
+ textarea.value = '';
37
+ textarea.disabled = true;
38
+ textarea.placeholder = 'Create or open a project file';
39
+ delete textarea.dataset.target;
40
+ delete textarea.dataset.path;
41
+ return;
42
+ }
43
+ textarea.disabled = false;
44
+ textarea.readOnly = next.source !== 'PROJECT';
45
+ textarea.dataset.target = next.target ?? 'SHARED';
46
+ textarea.dataset.path = next.path;
47
+ const content = contentFor(state, next);
48
+ if (textarea.value !== content)
49
+ textarea.value = content;
50
+ },
51
+ layout() { },
52
+ dispose() {
53
+ if (disposed)
54
+ return;
55
+ disposed = true;
56
+ textarea.removeEventListener('input', onInput);
57
+ host.replaceChildren();
58
+ },
59
+ };
60
+ }
61
+ function contentFor(state, ref) {
62
+ if (ref.source === 'PROJECT') {
63
+ return (state.project?.files.find((file) => file.target === ref.target && file.path === ref.path)?.content ?? '');
64
+ }
65
+ const files = ref.source === 'PERSONAL_LIBRARY'
66
+ ? state.personalLibraryFiles
67
+ : state.commonFiles;
68
+ return (files.find((file) => ref.referenceId
69
+ ? file.id === ref.referenceId
70
+ : file.path === ref.path && file.target === ref.target)?.content ?? '');
71
+ }
@@ -0,0 +1,27 @@
1
+ import type { GraphQLClient } from '../client.js';
2
+ import { type CreateCrowdyStudioProjectInput, type ImportCrowdyStudioReferenceFileInput, type CrowdyStudioProject, type CrowdyStudioProjectProvider, type CrowdyStudioProjectScope, type CrowdyStudioProjectSummary, type CrowdyStudioReferenceFile, type SaveCrowdyStudioLibraryFileInput, type SaveCrowdyStudioProjectInput } from '../crowdy-studio/models.js';
3
+ /**
4
+ * Schema-coupled Game API adapter for private Crowdy Studio projects and
5
+ * reusable files. Generated GraphQL documents and DTOs stay in this module;
6
+ * the controller and public project models remain transport-neutral. Mutable
7
+ * projects remain separate from immutable player-compute versions, and only
8
+ * the controller's deploy path converts target files to sourceFilesJson.
9
+ */
10
+ export declare class CrowdyStudioAPI implements CrowdyStudioProjectProvider {
11
+ private readonly graphql;
12
+ private readonly baselines;
13
+ constructor(graphql: GraphQLClient);
14
+ listProjects(scope: CrowdyStudioProjectScope): Promise<CrowdyStudioProjectSummary[]>;
15
+ getProject(input: CrowdyStudioProjectScope & {
16
+ projectId: string;
17
+ }): Promise<CrowdyStudioProject>;
18
+ createProject(input: CreateCrowdyStudioProjectInput): Promise<CrowdyStudioProject>;
19
+ saveProject(input: SaveCrowdyStudioProjectInput): Promise<CrowdyStudioProject>;
20
+ listPersonalLibraryFiles(scope: CrowdyStudioProjectScope): Promise<CrowdyStudioReferenceFile[]>;
21
+ savePersonalLibraryFile(input: SaveCrowdyStudioLibraryFileInput): Promise<CrowdyStudioReferenceFile>;
22
+ listCommonFiles(scope: CrowdyStudioProjectScope): Promise<CrowdyStudioReferenceFile[]>;
23
+ importReferenceFile(input: ImportCrowdyStudioReferenceFileInput): Promise<CrowdyStudioProject>;
24
+ private remember;
25
+ private request;
26
+ }
27
+ //# sourceMappingURL=crowdyStudio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crowdyStudio.d.ts","sourceRoot":"","sources":["../../src/domains/crowdyStudio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQlD,OAAO,EAIL,KAAK,8BAA8B,EACnC,KAAK,oCAAoC,EAEzC,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,gCAAgC,EACrC,KAAK,4BAA4B,EAClC,MAAM,4BAA4B,CAAC;AA0BpC;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,2BAA2B;IAGrD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;gBAEvC,OAAO,EAAE,aAAa;IAE7C,YAAY,CAChB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAUlC,UAAU,CACd,KAAK,EAAE,wBAAwB,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GACtD,OAAO,CAAC,mBAAmB,CAAC;IAQzB,aAAa,CACjB,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,mBAAmB,CAAC;IAoBzB,WAAW,CACf,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,mBAAmB,CAAC;IAwDzB,wBAAwB,CAC5B,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,yBAAyB,EAAE,CAAC;IAUjC,uBAAuB,CAC3B,KAAK,EAAE,gCAAgC,GACtC,OAAO,CAAC,yBAAyB,CAAC;IAc/B,eAAe,CACnB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,yBAAyB,EAAE,CAAC;IASjC,mBAAmB,CACvB,KAAK,EAAE,oCAAoC,GAC1C,OAAO,CAAC,mBAAmB,CAAC;IAuB/B,OAAO,CAAC,QAAQ;YAKF,OAAO;CAiBtB"}
@@ -0,0 +1,301 @@
1
+ import { CrowdyGraphQLError, CrowdyHttpError, CrowdyNetworkError, CrowdyTimeoutError, } from '../errors.js';
2
+ import { CrowdyStudioOfflineError, CrowdyStudioRevisionConflictError, normalizeCrowdyStudioPath, } from '../crowdy-studio/models.js';
3
+ import { CrowdyStudioCommonFilesDocument, CrowdyStudioImportSource, CrowdyStudioLibraryFilesDocument, CrowdyStudioLibrarySaveDocument, CrowdyStudioPairingPreference as CrowdyStudioPairingPreferenceEnum, CrowdyStudioProjectCreateDocument, CrowdyStudioProjectDocument, CrowdyStudioProjectImportFileDocument, CrowdyStudioProjectSaveDocument, CrowdyStudioProjectsDocument, } from '../generated/graphql.js';
4
+ /**
5
+ * Schema-coupled Game API adapter for private Crowdy Studio projects and
6
+ * reusable files. Generated GraphQL documents and DTOs stay in this module;
7
+ * the controller and public project models remain transport-neutral. Mutable
8
+ * projects remain separate from immutable player-compute versions, and only
9
+ * the controller's deploy path converts target files to sourceFilesJson.
10
+ */
11
+ export class CrowdyStudioAPI {
12
+ constructor(graphql) {
13
+ this.graphql = graphql;
14
+ this.baselines = new Map();
15
+ }
16
+ async listProjects(scope) {
17
+ const data = await this.request(CrowdyStudioProjectsDocument, {
18
+ appId: scope.appId,
19
+ includeArchived: false,
20
+ limit: 50,
21
+ offset: 0,
22
+ });
23
+ return data.crowdyStudioProjects.map(fromSummaryDto);
24
+ }
25
+ async getProject(input) {
26
+ const data = await this.request(CrowdyStudioProjectDocument, {
27
+ appId: input.appId,
28
+ projectId: input.projectId,
29
+ });
30
+ return this.remember(fromProjectDto(data.crowdyStudioProject, input.gridId));
31
+ }
32
+ async createProject(input) {
33
+ const data = await this.request(CrowdyStudioProjectCreateDocument, {
34
+ input: {
35
+ appId: input.appId,
36
+ gridId: input.gridId,
37
+ name: input.metadata.name,
38
+ description: input.metadata.description ?? null,
39
+ serverModuleName: input.metadata.serverModuleName ?? null,
40
+ clientModuleName: input.metadata.clientModuleName ?? null,
41
+ pairingPreference: toApiPairing(input.kind, input.metadata.pairingPreference),
42
+ sdkVersion: '0.1.5',
43
+ abiVersion: 0,
44
+ initialFiles: input.files.map(toApiFile),
45
+ },
46
+ });
47
+ return this.remember(fromProjectDto(data.crowdyStudioProjectCreate, input.gridId));
48
+ }
49
+ async saveProject(input) {
50
+ try {
51
+ const baseline = this.baselines.get(input.projectId) ??
52
+ (await this.getProject({
53
+ appId: input.appId,
54
+ gridId: input.gridId,
55
+ projectId: input.projectId,
56
+ }));
57
+ const delta = projectFileDelta(baseline, input);
58
+ const data = await this.request(CrowdyStudioProjectSaveDocument, {
59
+ input: {
60
+ appId: input.appId,
61
+ projectId: input.projectId,
62
+ expectedRevision: input.expectedRevisionId,
63
+ gridId: input.gridId,
64
+ name: input.metadata.name,
65
+ description: input.metadata.description ?? null,
66
+ serverModuleName: input.metadata.serverModuleName ?? null,
67
+ clientModuleName: input.metadata.clientModuleName ?? null,
68
+ pairingPreference: toApiPairing(projectKind(input), input.metadata.pairingPreference),
69
+ upserts: delta.upserts.map(toApiFile),
70
+ deletes: delta.deletes.map(({ target, path }) => ({
71
+ target: target,
72
+ path,
73
+ })),
74
+ },
75
+ });
76
+ return this.remember(fromProjectDto(data.crowdyStudioProjectSave, input.gridId));
77
+ }
78
+ catch (error) {
79
+ if (error instanceof CrowdyGraphQLError &&
80
+ error.code === 'CONFLICT' &&
81
+ error.message.includes('CROWDY_STUDIO_REVISION_CONFLICT')) {
82
+ let remoteProject;
83
+ try {
84
+ remoteProject = await this.getProject({
85
+ appId: input.appId,
86
+ gridId: input.gridId,
87
+ projectId: input.projectId,
88
+ });
89
+ }
90
+ catch {
91
+ // The conflict remains actionable if the follow-up read fails.
92
+ }
93
+ throw new CrowdyStudioRevisionConflictError(error.message, remoteProject);
94
+ }
95
+ throw error;
96
+ }
97
+ }
98
+ async listPersonalLibraryFiles(scope) {
99
+ const data = await this.request(CrowdyStudioLibraryFilesDocument, {
100
+ appId: scope.appId,
101
+ includeArchived: false,
102
+ limit: 100,
103
+ offset: 0,
104
+ });
105
+ return data.crowdyStudioLibraryFiles.map(fromLibraryDto);
106
+ }
107
+ async savePersonalLibraryFile(input) {
108
+ const data = await this.request(CrowdyStudioLibrarySaveDocument, {
109
+ input: {
110
+ appId: input.appId,
111
+ title: input.title,
112
+ pathHint: normalizeCrowdyStudioPath(input.path),
113
+ target: input.target,
114
+ tags: input.tags ?? [],
115
+ content: input.content,
116
+ },
117
+ });
118
+ return fromLibraryDto(data.crowdyStudioLibrarySave);
119
+ }
120
+ async listCommonFiles(scope) {
121
+ const data = await this.request(CrowdyStudioCommonFilesDocument, {
122
+ appId: scope.appId,
123
+ limit: 100,
124
+ offset: 0,
125
+ });
126
+ return data.crowdyStudioCommonFiles.map(fromCommonDto);
127
+ }
128
+ async importReferenceFile(input) {
129
+ const data = await this.request(CrowdyStudioProjectImportFileDocument, {
130
+ input: {
131
+ appId: input.appId,
132
+ projectId: input.projectId,
133
+ expectedProjectRevision: input.expectedRevisionId,
134
+ source: input.source === 'PERSONAL_LIBRARY'
135
+ ? CrowdyStudioImportSource.Library
136
+ : CrowdyStudioImportSource.Common,
137
+ ...(input.source === 'PERSONAL_LIBRARY'
138
+ ? { libraryFileId: input.referenceId }
139
+ : { commonVersionId: input.referenceId }),
140
+ ...(input.destinationPath
141
+ ? { destinationPath: normalizeCrowdyStudioPath(input.destinationPath) }
142
+ : {}),
143
+ },
144
+ });
145
+ return this.remember(fromProjectDto(data.crowdyStudioProjectImportFile, input.gridId));
146
+ }
147
+ remember(project) {
148
+ this.baselines.set(project.projectId, cloneProject(project));
149
+ return project;
150
+ }
151
+ async request(document, variables) {
152
+ try {
153
+ return await this.graphql.request(document, variables);
154
+ }
155
+ catch (error) {
156
+ if (error instanceof CrowdyNetworkError ||
157
+ error instanceof CrowdyTimeoutError ||
158
+ (error instanceof CrowdyHttpError && error.status >= 500)) {
159
+ throw new CrowdyStudioOfflineError(error.message, error);
160
+ }
161
+ throw error;
162
+ }
163
+ }
164
+ }
165
+ function fromSummaryDto(dto) {
166
+ return {
167
+ projectId: dto.projectId,
168
+ name: dto.name,
169
+ kind: kindFromApi(dto.pairingPreference),
170
+ revisionId: String(dto.revision),
171
+ ...(dto.serverModuleName
172
+ ? { serverModuleName: dto.serverModuleName }
173
+ : {}),
174
+ ...(dto.clientModuleName
175
+ ? { clientModuleName: dto.clientModuleName }
176
+ : {}),
177
+ updatedAt: dto.updatedAt,
178
+ };
179
+ }
180
+ function fromProjectDto(dto, fallbackGridId) {
181
+ const files = dto.files.map((file) => ({
182
+ target: file.target,
183
+ path: normalizeCrowdyStudioPath(file.path),
184
+ content: file.content,
185
+ }));
186
+ return {
187
+ projectId: dto.projectId,
188
+ appId: String(dto.appId),
189
+ gridId: dto.gridId == null ? fallbackGridId : String(dto.gridId),
190
+ kind: kindFromApi(dto.pairingPreference),
191
+ metadata: {
192
+ name: dto.name,
193
+ ...(dto.description ? { description: dto.description } : {}),
194
+ ...(dto.serverModuleName
195
+ ? { serverModuleName: dto.serverModuleName }
196
+ : {}),
197
+ ...(dto.clientModuleName
198
+ ? { clientModuleName: dto.clientModuleName }
199
+ : {}),
200
+ pairingPreference: fromApiPairing(dto.pairingPreference),
201
+ },
202
+ files,
203
+ sdkVersion: dto.sdkVersion,
204
+ abiVersion: dto.abiVersion,
205
+ revision: {
206
+ id: String(dto.revision),
207
+ savedAt: dto.updatedAt,
208
+ },
209
+ createdAt: dto.createdAt,
210
+ updatedAt: dto.updatedAt,
211
+ };
212
+ }
213
+ function fromLibraryDto(dto) {
214
+ return {
215
+ id: dto.libraryFileId,
216
+ source: 'PERSONAL_LIBRARY',
217
+ title: dto.title,
218
+ target: dto.target,
219
+ path: normalizeCrowdyStudioPath(dto.pathHint),
220
+ content: dto.content,
221
+ tags: [...dto.tags],
222
+ updatedAt: dto.updatedAt,
223
+ };
224
+ }
225
+ function fromCommonDto(dto) {
226
+ return {
227
+ id: dto.versionId,
228
+ source: 'COMMON',
229
+ title: dto.title,
230
+ target: dto.target,
231
+ path: normalizeCrowdyStudioPath(dto.path),
232
+ content: dto.content,
233
+ tags: [...dto.tags],
234
+ updatedAt: dto.updatedAt,
235
+ };
236
+ }
237
+ function kindFromApi(pairing) {
238
+ if (pairing === CrowdyStudioPairingPreferenceEnum.ServerOnly)
239
+ return 'SERVER';
240
+ if (pairing === CrowdyStudioPairingPreferenceEnum.ClientOnly)
241
+ return 'CLIENT';
242
+ return 'FULL_STACK';
243
+ }
244
+ function fromApiPairing(pairing) {
245
+ if (pairing === CrowdyStudioPairingPreferenceEnum.Paired)
246
+ return 'REQUIRED';
247
+ if (pairing === CrowdyStudioPairingPreferenceEnum.Independent)
248
+ return 'OPTIONAL';
249
+ return 'NONE';
250
+ }
251
+ function toApiPairing(kind, pairing) {
252
+ if (kind === 'SERVER')
253
+ return CrowdyStudioPairingPreferenceEnum.ServerOnly;
254
+ if (kind === 'CLIENT')
255
+ return CrowdyStudioPairingPreferenceEnum.ClientOnly;
256
+ return pairing === 'REQUIRED'
257
+ ? CrowdyStudioPairingPreferenceEnum.Paired
258
+ : CrowdyStudioPairingPreferenceEnum.Independent;
259
+ }
260
+ function toApiFile(file) {
261
+ return {
262
+ target: file.target,
263
+ path: normalizeCrowdyStudioPath(file.path),
264
+ content: file.content,
265
+ };
266
+ }
267
+ function projectKind(input) {
268
+ const hasServer = input.files.some((file) => file.target === 'SERVER');
269
+ const hasClient = input.files.some((file) => file.target === 'CLIENT');
270
+ if (hasServer && hasClient)
271
+ return 'FULL_STACK';
272
+ if (hasServer)
273
+ return 'SERVER';
274
+ return 'CLIENT';
275
+ }
276
+ function projectFileDelta(baseline, input) {
277
+ const previous = new Map(baseline.files.map((file) => [
278
+ `${file.target}:${normalizeCrowdyStudioPath(file.path)}`,
279
+ file,
280
+ ]));
281
+ const current = new Map(input.files.map((file) => [
282
+ `${file.target}:${normalizeCrowdyStudioPath(file.path)}`,
283
+ file,
284
+ ]));
285
+ const upserts = input.files.filter((file) => {
286
+ const before = previous.get(`${file.target}:${normalizeCrowdyStudioPath(file.path)}`);
287
+ return !before || before.content !== file.content;
288
+ });
289
+ const deletes = baseline.files
290
+ .filter((file) => !current.has(`${file.target}:${normalizeCrowdyStudioPath(file.path)}`))
291
+ .map((file) => ({ target: file.target, path: file.path }));
292
+ return { upserts, deletes };
293
+ }
294
+ function cloneProject(project) {
295
+ return {
296
+ ...project,
297
+ metadata: { ...project.metadata },
298
+ files: project.files.map((file) => ({ ...file })),
299
+ revision: { ...project.revision },
300
+ };
301
+ }
@@ -77,7 +77,7 @@ export declare class PlayerComputeAPI {
77
77
  /**
78
78
  * Fetch a client artifact and decode its bytes to an ArrayBuffer plus the
79
79
  * broker inputs (content hash for side-load verification, per-dispatch fuel
80
- * budget). Convenience over {@link artifact} for the live-coding client
80
+ * budget). Convenience over {@link artifact} for the Crowdy Studio CLIENT
81
81
  * deploy loop.
82
82
  */
83
83
  artifactBytes(variables: PlayerComputeArtifactQueryVariables): Promise<{
@@ -116,7 +116,7 @@ export class PlayerComputeAPI {
116
116
  /**
117
117
  * Fetch a client artifact and decode its bytes to an ArrayBuffer plus the
118
118
  * broker inputs (content hash for side-load verification, per-dispatch fuel
119
- * budget). Convenience over {@link artifact} for the live-coding client
119
+ * budget). Convenience over {@link artifact} for the Crowdy Studio CLIENT
120
120
  * deploy loop.
121
121
  */
122
122
  async artifactBytes(variables) {