@crowdedkingdoms/crowdyjs 10.0.0 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +59 -48
- package/README.md +29 -21
- package/dist/crowdy-client.d.ts +3 -3
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +2 -2
- package/dist/crowdy-studio/controller.d.ts +188 -0
- package/dist/crowdy-studio/controller.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/controller.js +22 -22
- package/dist/crowdy-studio/diagnostics.d.ts +22 -0
- package/dist/crowdy-studio/diagnostics.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/diagnostics.js +2 -2
- package/dist/{mod-studio → crowdy-studio}/dom-shell.d.ts +4 -4
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/dom-shell.js +31 -31
- package/dist/crowdy-studio/editor.d.ts +17 -0
- package/dist/crowdy-studio/editor.d.ts.map +1 -0
- package/dist/crowdy-studio/index.d.ts +10 -0
- package/dist/crowdy-studio/index.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/index.js +4 -4
- package/dist/crowdy-studio/models.d.ts +149 -0
- package/dist/crowdy-studio/models.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/models.js +10 -10
- package/dist/{mod-studio → crowdy-studio}/monaco-editor.d.ts +3 -3
- package/dist/crowdy-studio/monaco-editor.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/monaco-editor.js +4 -4
- package/dist/crowdy-studio/mount.d.ts +23 -0
- package/dist/crowdy-studio/mount.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/mount.js +48 -14
- package/dist/crowdy-studio/starter-projects.d.ts +11 -0
- package/dist/crowdy-studio/starter-projects.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/starter-projects.js +2 -2
- package/dist/crowdy-studio/styles.d.ts +2 -0
- package/dist/crowdy-studio/styles.d.ts.map +1 -0
- package/dist/crowdy-studio/styles.js +14 -0
- package/dist/crowdy-studio/textarea-editor.d.ts +8 -0
- package/dist/crowdy-studio/textarea-editor.d.ts.map +1 -0
- package/dist/{mod-studio → crowdy-studio}/textarea-editor.js +3 -3
- package/dist/domains/crowdyStudio.d.ts +27 -0
- package/dist/domains/crowdyStudio.d.ts.map +1 -0
- package/dist/domains/{playerCodeProjects.js → crowdyStudio.js} +47 -45
- package/dist/domains/playerCompute.d.ts +1 -1
- package/dist/domains/playerCompute.js +1 -1
- package/dist/generated/graphql.d.ts +670 -670
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +57 -57
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/live-coding/rust-analysis.js +1 -1
- package/package.json +4 -4
- package/dist/domains/playerCodeProjects.d.ts +0 -25
- package/dist/domains/playerCodeProjects.d.ts.map +0 -1
- package/dist/mod-studio/controller.d.ts +0 -188
- package/dist/mod-studio/controller.d.ts.map +0 -1
- package/dist/mod-studio/diagnostics.d.ts +0 -22
- package/dist/mod-studio/diagnostics.d.ts.map +0 -1
- package/dist/mod-studio/dom-shell.d.ts.map +0 -1
- package/dist/mod-studio/editor.d.ts +0 -17
- package/dist/mod-studio/editor.d.ts.map +0 -1
- package/dist/mod-studio/index.d.ts +0 -10
- package/dist/mod-studio/index.d.ts.map +0 -1
- package/dist/mod-studio/models.d.ts +0 -149
- package/dist/mod-studio/models.d.ts.map +0 -1
- package/dist/mod-studio/monaco-editor.d.ts.map +0 -1
- package/dist/mod-studio/mount.d.ts +0 -17
- package/dist/mod-studio/mount.d.ts.map +0 -1
- package/dist/mod-studio/starter-projects.d.ts +0 -11
- package/dist/mod-studio/starter-projects.d.ts.map +0 -1
- package/dist/mod-studio/styles.d.ts +0 -2
- package/dist/mod-studio/styles.d.ts.map +0 -1
- package/dist/mod-studio/styles.js +0 -14
- package/dist/mod-studio/textarea-editor.d.ts +0 -8
- package/dist/mod-studio/textarea-editor.d.ts.map +0 -1
- /package/dist/{mod-studio → crowdy-studio}/editor.js +0 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/** Provider error indicating that the expected revision lost a save race. */
|
|
2
|
-
export class
|
|
2
|
+
export class CrowdyStudioRevisionConflictError extends Error {
|
|
3
3
|
constructor(message = 'The project changed in another session', remoteProject) {
|
|
4
4
|
super(message);
|
|
5
5
|
this.remoteProject = remoteProject;
|
|
6
6
|
this.code = 'PROJECT_REVISION_CONFLICT';
|
|
7
|
-
this.name = '
|
|
7
|
+
this.name = 'CrowdyStudioRevisionConflictError';
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
/** Provider error indicating that the write should be retried when online. */
|
|
11
|
-
export class
|
|
11
|
+
export class CrowdyStudioOfflineError extends Error {
|
|
12
12
|
constructor(message = 'The project service is offline', cause) {
|
|
13
13
|
super(message);
|
|
14
14
|
this.code = 'PROJECT_OFFLINE';
|
|
15
|
-
this.name = '
|
|
15
|
+
this.name = 'CrowdyStudioOfflineError';
|
|
16
16
|
this.cause = cause;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
/** Validate and normalize a target-relative project path. */
|
|
20
|
-
export function
|
|
20
|
+
export function normalizeCrowdyStudioPath(path) {
|
|
21
21
|
const normalized = path.trim().replace(/\\/gu, '/').replace(/^\.\/+/u, '');
|
|
22
22
|
if (normalized.length === 0 ||
|
|
23
23
|
normalized.length > 240 ||
|
|
@@ -30,16 +30,16 @@ export function normalizeModStudioPath(path) {
|
|
|
30
30
|
return normalized;
|
|
31
31
|
}
|
|
32
32
|
/** Stable key for maps, tabs, diagnostics, and tests. */
|
|
33
|
-
export function
|
|
34
|
-
return `${target}:${
|
|
33
|
+
export function crowdyStudioFileKey(target, path) {
|
|
34
|
+
return `${target}:${normalizeCrowdyStudioPath(path)}`;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Target-prefixed URI used by Monaco and the browser VFS. Both targets can
|
|
38
38
|
* therefore load `Cargo.toml` and `src/lib.rs` at the same time.
|
|
39
39
|
*/
|
|
40
|
-
export function
|
|
40
|
+
export function crowdyStudioFileUri(workspaceUri, target, path) {
|
|
41
41
|
const root = workspaceUri.replace(/\/+$/u, '');
|
|
42
|
-
const encodedPath =
|
|
42
|
+
const encodedPath = normalizeCrowdyStudioPath(path)
|
|
43
43
|
.split('/')
|
|
44
44
|
.map(encodeURIComponent)
|
|
45
45
|
.join('/');
|
|
@@ -52,7 +52,7 @@ export function projectTargets(kind) {
|
|
|
52
52
|
return ['CLIENT'];
|
|
53
53
|
return ['SERVER', 'CLIENT'];
|
|
54
54
|
}
|
|
55
|
-
export function
|
|
55
|
+
export function cloneCrowdyStudioProject(project) {
|
|
56
56
|
return {
|
|
57
57
|
...project,
|
|
58
58
|
metadata: { ...project.metadata },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CrowdyStudioEditorAdapter, CrowdyStudioEditorCallbacks } from './editor.js';
|
|
2
2
|
import { type PlatformIndex } from '../live-coding/platform-index.js';
|
|
3
|
-
export interface
|
|
3
|
+
export interface MonacoCrowdyStudioEditorOptions {
|
|
4
4
|
editorWorkerFactory?: () => Worker;
|
|
5
5
|
languageWorkerFactory?: () => Worker;
|
|
6
6
|
platformIndex?: PlatformIndex | unknown;
|
|
@@ -11,6 +11,6 @@ export interface MonacoModStudioEditorOptions {
|
|
|
11
11
|
* loaded project/reference file is opened in the worker; project URIs include
|
|
12
12
|
* `/server/` or `/client/`, so duplicate Cargo and lib paths never collide.
|
|
13
13
|
*/
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function createMonacoCrowdyStudioEditor(host: HTMLElement, options: MonacoCrowdyStudioEditorOptions, callbacks: CrowdyStudioEditorCallbacks): Promise<CrowdyStudioEditorAdapter>;
|
|
15
15
|
export declare function isCurrentDiagnosticVersion(version: unknown, currentVersion: number): boolean;
|
|
16
16
|
//# sourceMappingURL=monaco-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monaco-editor.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/monaco-editor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAC5B,MAAM,aAAa,CAAC;AAerB,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAW1C,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC;IACnC,qBAAqB,CAAC,EAAE,MAAM,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IACxC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAmBD;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,+BAA+B,EACxC,SAAS,EAAE,2BAA2B,GACrC,OAAO,CAAC,yBAAyB,CAAC,CAoXpC;AA6GD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,GACrB,OAAO,CAKT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { crowdyStudioFileUri, } from './models.js';
|
|
2
2
|
import { isRecord, } from '../live-coding/lsp-protocol.js';
|
|
3
3
|
import { loadPlatformIndex, } from '../live-coding/platform-index.js';
|
|
4
4
|
import { acquireMonacoWorkspace, ensureMonacoServicesInitialized, } from '../live-coding/monaco-services.js';
|
|
@@ -8,7 +8,7 @@ let rustLanguagesRegistered = false;
|
|
|
8
8
|
* loaded project/reference file is opened in the worker; project URIs include
|
|
9
9
|
* `/server/` or `/client/`, so duplicate Cargo and lib paths never collide.
|
|
10
10
|
*/
|
|
11
|
-
export async function
|
|
11
|
+
export async function createMonacoCrowdyStudioEditor(host, options, callbacks) {
|
|
12
12
|
if (!options.languageWorkerFactory && typeof Worker === 'undefined') {
|
|
13
13
|
throw new Error('Worker is unavailable');
|
|
14
14
|
}
|
|
@@ -97,7 +97,7 @@ export async function createMonacoModStudioEditor(host, options, callbacks) {
|
|
|
97
97
|
}));
|
|
98
98
|
await languageClient.initialize({
|
|
99
99
|
processId: null,
|
|
100
|
-
clientInfo: { name: 'CrowdyJS
|
|
100
|
+
clientInfo: { name: 'CrowdyJS Crowdy Studio', version: '1' },
|
|
101
101
|
rootUri: workspaceUri,
|
|
102
102
|
capabilities: {
|
|
103
103
|
general: { positionEncodings: ['utf-16'] },
|
|
@@ -320,7 +320,7 @@ function collectFiles(state, workspaceUri) {
|
|
|
320
320
|
key: keyForRef(ref),
|
|
321
321
|
ref,
|
|
322
322
|
content: file.content,
|
|
323
|
-
uri:
|
|
323
|
+
uri: crowdyStudioFileUri(workspaceUri, file.target, file.path),
|
|
324
324
|
};
|
|
325
325
|
}) ?? [];
|
|
326
326
|
return [
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CrowdyStudioController, type CrowdyStudioControllerOptions } from './controller.js';
|
|
2
|
+
import type { CrowdyStudioEditorAdapter, CrowdyStudioEditorMode } from './editor.js';
|
|
3
|
+
import { type MonacoCrowdyStudioEditorOptions } from './monaco-editor.js';
|
|
4
|
+
export interface MountCrowdyStudioOptions extends CrowdyStudioControllerOptions, MonacoCrowdyStudioEditorOptions {
|
|
5
|
+
}
|
|
6
|
+
export interface CrowdyStudioHandle {
|
|
7
|
+
controller: CrowdyStudioController;
|
|
8
|
+
editorMode: CrowdyStudioEditorMode;
|
|
9
|
+
destroy(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Keep an embedded editor fitted to its host. Hosts can resize without a
|
|
13
|
+
* window resize (for example when a game drags a dock splitter), so Monaco
|
|
14
|
+
* must follow the element itself rather than the browser viewport.
|
|
15
|
+
*/
|
|
16
|
+
export declare function observeCrowdyStudioEditorLayout(host: HTMLElement, currentEditor: () => CrowdyStudioEditorAdapter | null): () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Mount the project-first Crowdy Studio. Monaco and its browser Rust worker are
|
|
19
|
+
* loaded lazily; any editor/worker/WASM startup failure keeps the full project
|
|
20
|
+
* UI and swaps in the target/file-aware textarea editor.
|
|
21
|
+
*/
|
|
22
|
+
export declare function mountCrowdyStudio(host: HTMLElement, options: MountCrowdyStudioOptions): Promise<CrowdyStudioHandle>;
|
|
23
|
+
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/crowdy-studio/mount.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,EACnC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EACV,yBAAyB,EAEzB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,wBACf,SAAQ,6BAA6B,EACnC,+BAA+B;CAAG;AAEtC,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,sBAAsB,CAAC;IACnC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,yBAAyB,GAAG,IAAI,GACpD,MAAM,IAAI,CAmBZ;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAwG7B"}
|
|
@@ -1,21 +1,51 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { CrowdyStudioController, } from './controller.js';
|
|
2
|
+
import { CrowdyStudioDomShell } from './dom-shell.js';
|
|
3
|
+
import { createMonacoCrowdyStudioEditor, } from './monaco-editor.js';
|
|
4
|
+
import { createTextareaCrowdyStudioEditor } from './textarea-editor.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Keep an embedded editor fitted to its host. Hosts can resize without a
|
|
7
|
+
* window resize (for example when a game drags a dock splitter), so Monaco
|
|
8
|
+
* must follow the element itself rather than the browser viewport.
|
|
9
|
+
*/
|
|
10
|
+
export function observeCrowdyStudioEditorLayout(host, currentEditor) {
|
|
11
|
+
const Observer = globalThis.ResizeObserver;
|
|
12
|
+
if (!Observer)
|
|
13
|
+
return () => { };
|
|
14
|
+
let stopped = false;
|
|
15
|
+
let queued = false;
|
|
16
|
+
const observer = new Observer(() => {
|
|
17
|
+
if (stopped || queued)
|
|
18
|
+
return;
|
|
19
|
+
queued = true;
|
|
20
|
+
queueMicrotask(() => {
|
|
21
|
+
queued = false;
|
|
22
|
+
if (!stopped)
|
|
23
|
+
currentEditor()?.layout();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
observer.observe(host);
|
|
27
|
+
return () => {
|
|
28
|
+
if (stopped)
|
|
29
|
+
return;
|
|
30
|
+
stopped = true;
|
|
31
|
+
observer.disconnect();
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Mount the project-first Crowdy Studio. Monaco and its browser Rust worker are
|
|
7
36
|
* loaded lazily; any editor/worker/WASM startup failure keeps the full project
|
|
8
37
|
* UI and swaps in the target/file-aware textarea editor.
|
|
9
38
|
*/
|
|
10
|
-
export async function
|
|
39
|
+
export async function mountCrowdyStudio(host, options) {
|
|
11
40
|
if (typeof document === 'undefined') {
|
|
12
|
-
throw new Error('
|
|
41
|
+
throw new Error('mountCrowdyStudio requires a DOM document');
|
|
13
42
|
}
|
|
14
|
-
const controller = new
|
|
15
|
-
const shell = new
|
|
43
|
+
const controller = new CrowdyStudioController(options);
|
|
44
|
+
const shell = new CrowdyStudioDomShell(host, controller);
|
|
16
45
|
let editor = null;
|
|
17
46
|
let destroyed = false;
|
|
18
47
|
let recoveringEditor = false;
|
|
48
|
+
const disconnectLayoutObserver = observeCrowdyStudioEditorLayout(host, () => editor);
|
|
19
49
|
const callbacks = {
|
|
20
50
|
onProjectFileChange: (target, path, content) => controller.updateFile(target, path, content),
|
|
21
51
|
onLocalDiagnostics: (diagnostics) => controller.setLocalDiagnostics(diagnostics),
|
|
@@ -28,11 +58,12 @@ export async function mountModStudio(host, options) {
|
|
|
28
58
|
return;
|
|
29
59
|
}
|
|
30
60
|
recoveringEditor = true;
|
|
31
|
-
console.warn('
|
|
61
|
+
console.warn('Crowdy Studio Rust worker failed; switching to the file-aware fallback', error);
|
|
32
62
|
editor.dispose();
|
|
33
63
|
controller.setLocalDiagnostics([]);
|
|
34
|
-
editor =
|
|
64
|
+
editor = createTextareaCrowdyStudioEditor(shell.editorHost, callbacks);
|
|
35
65
|
editor.sync(controller.getState());
|
|
66
|
+
editor.layout();
|
|
36
67
|
recoveringEditor = false;
|
|
37
68
|
});
|
|
38
69
|
},
|
|
@@ -49,15 +80,17 @@ export async function mountModStudio(host, options) {
|
|
|
49
80
|
try {
|
|
50
81
|
await controller.initialize();
|
|
51
82
|
try {
|
|
52
|
-
editor = await
|
|
83
|
+
editor = await createMonacoCrowdyStudioEditor(shell.editorHost, options, callbacks);
|
|
53
84
|
}
|
|
54
85
|
catch (error) {
|
|
55
|
-
console.warn('
|
|
56
|
-
editor =
|
|
86
|
+
console.warn('Crowdy Studio Monaco editor unavailable; using the file-aware fallback', error);
|
|
87
|
+
editor = createTextareaCrowdyStudioEditor(shell.editorHost, callbacks);
|
|
57
88
|
}
|
|
58
89
|
editor.sync(controller.getState());
|
|
90
|
+
editor.layout();
|
|
59
91
|
}
|
|
60
92
|
catch (error) {
|
|
93
|
+
disconnectLayoutObserver();
|
|
61
94
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
62
95
|
unsubscribe();
|
|
63
96
|
const failedEditor = editor;
|
|
@@ -75,6 +108,7 @@ export async function mountModStudio(host, options) {
|
|
|
75
108
|
if (destroyed)
|
|
76
109
|
return;
|
|
77
110
|
destroyed = true;
|
|
111
|
+
disconnectLayoutObserver();
|
|
78
112
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
79
113
|
unsubscribe();
|
|
80
114
|
editor?.dispose();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CreateCrowdyStudioProjectInput, type CrowdyStudioProjectKind } from './models.js';
|
|
2
|
+
export interface CrowdyStudioNewProjectOptions {
|
|
3
|
+
appId: string;
|
|
4
|
+
gridId: string;
|
|
5
|
+
name: string;
|
|
6
|
+
kind: CrowdyStudioProjectKind;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Create a compile-oriented starter without introducing a raw JSON source map. */
|
|
10
|
+
export declare function createCrowdyStudioStarterProject(options: CrowdyStudioNewProjectOptions): CreateCrowdyStudioProjectInput;
|
|
11
|
+
//# sourceMappingURL=starter-projects.d.ts.map
|
|
@@ -0,0 +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;AAIrB,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;CACtB;AAED,mFAAmF;AACnF,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,6BAA6B,GACrC,8BAA8B,CA2BhC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { projectTargets, } from './models.js';
|
|
2
2
|
const SDK_VERSION = '0.1.5';
|
|
3
3
|
/** Create a compile-oriented starter without introducing a raw JSON source map. */
|
|
4
|
-
export function
|
|
4
|
+
export function createCrowdyStudioStarterProject(options) {
|
|
5
5
|
const base = moduleName(options.name);
|
|
6
6
|
const targets = projectTargets(options.kind);
|
|
7
7
|
const metadata = {
|
|
@@ -64,7 +64,7 @@ fn on_tick(_dt_ms: u32) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
fn on_invoke(payload: &[u8]) -> Vec<u8> {
|
|
67
|
-
// Called by
|
|
67
|
+
// Called by Crowdy Studio's Invoke panel or an allowed game caller.
|
|
68
68
|
payload.to_vec()
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -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;container-type:inline-size;display:grid;grid-template-rows:auto auto minmax(240px,1fr) minmax(120px,.36fr);width:100%;height:100%;min-height:0;overflow:hidden;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:0;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@container(max-width:900px){.ck-crowdy-studio-main{grid-template-columns:180px minmax(0,1fr)}.ck-crowdy-studio-settings{display:none}}@container(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,+lJAahC,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;container-type:inline-size;display:grid;grid-template-rows:auto auto minmax(240px,1fr) minmax(120px,.36fr);width:100%;height:100%;min-height:0;overflow:hidden;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:0;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
|
+
@container(max-width:900px){.ck-crowdy-studio-main{grid-template-columns:180px minmax(0,1fr)}.ck-crowdy-studio-settings{display:none}}@container(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"}
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* start. It edits the active source file directly; project tabs and explorer
|
|
4
4
|
* continue to work and no JSON source blob is exposed.
|
|
5
5
|
*/
|
|
6
|
-
export function
|
|
6
|
+
export function createTextareaCrowdyStudioEditor(host, callbacks) {
|
|
7
7
|
const notice = document.createElement('div');
|
|
8
|
-
notice.className = 'ck-
|
|
8
|
+
notice.className = 'ck-crowdy-studio-editor-notice';
|
|
9
9
|
notice.textContent =
|
|
10
10
|
'Basic editor active — Monaco or the local Rust worker was unavailable.';
|
|
11
11
|
const textarea = document.createElement('textarea');
|
|
12
|
-
textarea.className = 'ck-
|
|
12
|
+
textarea.className = 'ck-crowdy-studio-textarea';
|
|
13
13
|
textarea.rows = 24;
|
|
14
14
|
textarea.spellcheck = false;
|
|
15
15
|
textarea.setAttribute('aria-label', 'Project source editor');
|
|
@@ -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"}
|
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
import { CrowdyGraphQLError, CrowdyHttpError, CrowdyNetworkError, CrowdyTimeoutError, } from '../errors.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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.
|
|
8
10
|
*/
|
|
9
|
-
export class
|
|
11
|
+
export class CrowdyStudioAPI {
|
|
10
12
|
constructor(graphql) {
|
|
11
13
|
this.graphql = graphql;
|
|
12
14
|
this.baselines = new Map();
|
|
13
15
|
}
|
|
14
16
|
async listProjects(scope) {
|
|
15
|
-
const data = await this.request(
|
|
17
|
+
const data = await this.request(CrowdyStudioProjectsDocument, {
|
|
16
18
|
appId: scope.appId,
|
|
17
19
|
includeArchived: false,
|
|
18
20
|
limit: 50,
|
|
19
21
|
offset: 0,
|
|
20
22
|
});
|
|
21
|
-
return data.
|
|
23
|
+
return data.crowdyStudioProjects.map(fromSummaryDto);
|
|
22
24
|
}
|
|
23
25
|
async getProject(input) {
|
|
24
|
-
const data = await this.request(
|
|
26
|
+
const data = await this.request(CrowdyStudioProjectDocument, {
|
|
25
27
|
appId: input.appId,
|
|
26
28
|
projectId: input.projectId,
|
|
27
29
|
});
|
|
28
|
-
return this.remember(fromProjectDto(data.
|
|
30
|
+
return this.remember(fromProjectDto(data.crowdyStudioProject, input.gridId));
|
|
29
31
|
}
|
|
30
32
|
async createProject(input) {
|
|
31
|
-
const data = await this.request(
|
|
33
|
+
const data = await this.request(CrowdyStudioProjectCreateDocument, {
|
|
32
34
|
input: {
|
|
33
35
|
appId: input.appId,
|
|
34
36
|
gridId: input.gridId,
|
|
@@ -42,7 +44,7 @@ export class PlayerCodeProjectsAPI {
|
|
|
42
44
|
initialFiles: input.files.map(toApiFile),
|
|
43
45
|
},
|
|
44
46
|
});
|
|
45
|
-
return this.remember(fromProjectDto(data.
|
|
47
|
+
return this.remember(fromProjectDto(data.crowdyStudioProjectCreate, input.gridId));
|
|
46
48
|
}
|
|
47
49
|
async saveProject(input) {
|
|
48
50
|
try {
|
|
@@ -53,7 +55,7 @@ export class PlayerCodeProjectsAPI {
|
|
|
53
55
|
projectId: input.projectId,
|
|
54
56
|
}));
|
|
55
57
|
const delta = projectFileDelta(baseline, input);
|
|
56
|
-
const data = await this.request(
|
|
58
|
+
const data = await this.request(CrowdyStudioProjectSaveDocument, {
|
|
57
59
|
input: {
|
|
58
60
|
appId: input.appId,
|
|
59
61
|
projectId: input.projectId,
|
|
@@ -71,12 +73,12 @@ export class PlayerCodeProjectsAPI {
|
|
|
71
73
|
})),
|
|
72
74
|
},
|
|
73
75
|
});
|
|
74
|
-
return this.remember(fromProjectDto(data.
|
|
76
|
+
return this.remember(fromProjectDto(data.crowdyStudioProjectSave, input.gridId));
|
|
75
77
|
}
|
|
76
78
|
catch (error) {
|
|
77
79
|
if (error instanceof CrowdyGraphQLError &&
|
|
78
80
|
error.code === 'CONFLICT' &&
|
|
79
|
-
error.message.includes('
|
|
81
|
+
error.message.includes('CROWDY_STUDIO_REVISION_CONFLICT')) {
|
|
80
82
|
let remoteProject;
|
|
81
83
|
try {
|
|
82
84
|
remoteProject = await this.getProject({
|
|
@@ -88,59 +90,59 @@ export class PlayerCodeProjectsAPI {
|
|
|
88
90
|
catch {
|
|
89
91
|
// The conflict remains actionable if the follow-up read fails.
|
|
90
92
|
}
|
|
91
|
-
throw new
|
|
93
|
+
throw new CrowdyStudioRevisionConflictError(error.message, remoteProject);
|
|
92
94
|
}
|
|
93
95
|
throw error;
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
async listPersonalLibraryFiles(scope) {
|
|
97
|
-
const data = await this.request(
|
|
99
|
+
const data = await this.request(CrowdyStudioLibraryFilesDocument, {
|
|
98
100
|
appId: scope.appId,
|
|
99
101
|
includeArchived: false,
|
|
100
102
|
limit: 100,
|
|
101
103
|
offset: 0,
|
|
102
104
|
});
|
|
103
|
-
return data.
|
|
105
|
+
return data.crowdyStudioLibraryFiles.map(fromLibraryDto);
|
|
104
106
|
}
|
|
105
107
|
async savePersonalLibraryFile(input) {
|
|
106
|
-
const data = await this.request(
|
|
108
|
+
const data = await this.request(CrowdyStudioLibrarySaveDocument, {
|
|
107
109
|
input: {
|
|
108
110
|
appId: input.appId,
|
|
109
111
|
title: input.title,
|
|
110
|
-
pathHint:
|
|
112
|
+
pathHint: normalizeCrowdyStudioPath(input.path),
|
|
111
113
|
target: input.target,
|
|
112
114
|
tags: input.tags ?? [],
|
|
113
115
|
content: input.content,
|
|
114
116
|
},
|
|
115
117
|
});
|
|
116
|
-
return fromLibraryDto(data.
|
|
118
|
+
return fromLibraryDto(data.crowdyStudioLibrarySave);
|
|
117
119
|
}
|
|
118
120
|
async listCommonFiles(scope) {
|
|
119
|
-
const data = await this.request(
|
|
121
|
+
const data = await this.request(CrowdyStudioCommonFilesDocument, {
|
|
120
122
|
appId: scope.appId,
|
|
121
123
|
limit: 100,
|
|
122
124
|
offset: 0,
|
|
123
125
|
});
|
|
124
|
-
return data.
|
|
126
|
+
return data.crowdyStudioCommonFiles.map(fromCommonDto);
|
|
125
127
|
}
|
|
126
128
|
async importReferenceFile(input) {
|
|
127
|
-
const data = await this.request(
|
|
129
|
+
const data = await this.request(CrowdyStudioProjectImportFileDocument, {
|
|
128
130
|
input: {
|
|
129
131
|
appId: input.appId,
|
|
130
132
|
projectId: input.projectId,
|
|
131
133
|
expectedProjectRevision: input.expectedRevisionId,
|
|
132
134
|
source: input.source === 'PERSONAL_LIBRARY'
|
|
133
|
-
?
|
|
134
|
-
:
|
|
135
|
+
? CrowdyStudioImportSource.Library
|
|
136
|
+
: CrowdyStudioImportSource.Common,
|
|
135
137
|
...(input.source === 'PERSONAL_LIBRARY'
|
|
136
138
|
? { libraryFileId: input.referenceId }
|
|
137
139
|
: { commonVersionId: input.referenceId }),
|
|
138
140
|
...(input.destinationPath
|
|
139
|
-
? { destinationPath:
|
|
141
|
+
? { destinationPath: normalizeCrowdyStudioPath(input.destinationPath) }
|
|
140
142
|
: {}),
|
|
141
143
|
},
|
|
142
144
|
});
|
|
143
|
-
return this.remember(fromProjectDto(data.
|
|
145
|
+
return this.remember(fromProjectDto(data.crowdyStudioProjectImportFile, input.gridId));
|
|
144
146
|
}
|
|
145
147
|
remember(project) {
|
|
146
148
|
this.baselines.set(project.projectId, cloneProject(project));
|
|
@@ -154,7 +156,7 @@ export class PlayerCodeProjectsAPI {
|
|
|
154
156
|
if (error instanceof CrowdyNetworkError ||
|
|
155
157
|
error instanceof CrowdyTimeoutError ||
|
|
156
158
|
(error instanceof CrowdyHttpError && error.status >= 500)) {
|
|
157
|
-
throw new
|
|
159
|
+
throw new CrowdyStudioOfflineError(error.message, error);
|
|
158
160
|
}
|
|
159
161
|
throw error;
|
|
160
162
|
}
|
|
@@ -178,7 +180,7 @@ function fromSummaryDto(dto) {
|
|
|
178
180
|
function fromProjectDto(dto, fallbackGridId) {
|
|
179
181
|
const files = dto.files.map((file) => ({
|
|
180
182
|
target: file.target,
|
|
181
|
-
path:
|
|
183
|
+
path: normalizeCrowdyStudioPath(file.path),
|
|
182
184
|
content: file.content,
|
|
183
185
|
}));
|
|
184
186
|
return {
|
|
@@ -214,7 +216,7 @@ function fromLibraryDto(dto) {
|
|
|
214
216
|
source: 'PERSONAL_LIBRARY',
|
|
215
217
|
title: dto.title,
|
|
216
218
|
target: dto.target,
|
|
217
|
-
path:
|
|
219
|
+
path: normalizeCrowdyStudioPath(dto.pathHint),
|
|
218
220
|
content: dto.content,
|
|
219
221
|
tags: [...dto.tags],
|
|
220
222
|
updatedAt: dto.updatedAt,
|
|
@@ -226,39 +228,39 @@ function fromCommonDto(dto) {
|
|
|
226
228
|
source: 'COMMON',
|
|
227
229
|
title: dto.title,
|
|
228
230
|
target: dto.target,
|
|
229
|
-
path:
|
|
231
|
+
path: normalizeCrowdyStudioPath(dto.path),
|
|
230
232
|
content: dto.content,
|
|
231
233
|
tags: [...dto.tags],
|
|
232
234
|
updatedAt: dto.updatedAt,
|
|
233
235
|
};
|
|
234
236
|
}
|
|
235
237
|
function kindFromApi(pairing) {
|
|
236
|
-
if (pairing ===
|
|
238
|
+
if (pairing === CrowdyStudioPairingPreferenceEnum.ServerOnly)
|
|
237
239
|
return 'SERVER';
|
|
238
|
-
if (pairing ===
|
|
240
|
+
if (pairing === CrowdyStudioPairingPreferenceEnum.ClientOnly)
|
|
239
241
|
return 'CLIENT';
|
|
240
242
|
return 'FULL_STACK';
|
|
241
243
|
}
|
|
242
244
|
function fromApiPairing(pairing) {
|
|
243
|
-
if (pairing ===
|
|
245
|
+
if (pairing === CrowdyStudioPairingPreferenceEnum.Paired)
|
|
244
246
|
return 'REQUIRED';
|
|
245
|
-
if (pairing ===
|
|
247
|
+
if (pairing === CrowdyStudioPairingPreferenceEnum.Independent)
|
|
246
248
|
return 'OPTIONAL';
|
|
247
249
|
return 'NONE';
|
|
248
250
|
}
|
|
249
251
|
function toApiPairing(kind, pairing) {
|
|
250
252
|
if (kind === 'SERVER')
|
|
251
|
-
return
|
|
253
|
+
return CrowdyStudioPairingPreferenceEnum.ServerOnly;
|
|
252
254
|
if (kind === 'CLIENT')
|
|
253
|
-
return
|
|
255
|
+
return CrowdyStudioPairingPreferenceEnum.ClientOnly;
|
|
254
256
|
return pairing === 'REQUIRED'
|
|
255
|
-
?
|
|
256
|
-
:
|
|
257
|
+
? CrowdyStudioPairingPreferenceEnum.Paired
|
|
258
|
+
: CrowdyStudioPairingPreferenceEnum.Independent;
|
|
257
259
|
}
|
|
258
260
|
function toApiFile(file) {
|
|
259
261
|
return {
|
|
260
262
|
target: file.target,
|
|
261
|
-
path:
|
|
263
|
+
path: normalizeCrowdyStudioPath(file.path),
|
|
262
264
|
content: file.content,
|
|
263
265
|
};
|
|
264
266
|
}
|
|
@@ -273,19 +275,19 @@ function projectKind(input) {
|
|
|
273
275
|
}
|
|
274
276
|
function projectFileDelta(baseline, input) {
|
|
275
277
|
const previous = new Map(baseline.files.map((file) => [
|
|
276
|
-
`${file.target}:${
|
|
278
|
+
`${file.target}:${normalizeCrowdyStudioPath(file.path)}`,
|
|
277
279
|
file,
|
|
278
280
|
]));
|
|
279
281
|
const current = new Map(input.files.map((file) => [
|
|
280
|
-
`${file.target}:${
|
|
282
|
+
`${file.target}:${normalizeCrowdyStudioPath(file.path)}`,
|
|
281
283
|
file,
|
|
282
284
|
]));
|
|
283
285
|
const upserts = input.files.filter((file) => {
|
|
284
|
-
const before = previous.get(`${file.target}:${
|
|
286
|
+
const before = previous.get(`${file.target}:${normalizeCrowdyStudioPath(file.path)}`);
|
|
285
287
|
return !before || before.content !== file.content;
|
|
286
288
|
});
|
|
287
289
|
const deletes = baseline.files
|
|
288
|
-
.filter((file) => !current.has(`${file.target}:${
|
|
290
|
+
.filter((file) => !current.has(`${file.target}:${normalizeCrowdyStudioPath(file.path)}`))
|
|
289
291
|
.map((file) => ({ target: file.target, path: file.path }));
|
|
290
292
|
return { upserts, deletes };
|
|
291
293
|
}
|