@crowdedkingdoms/crowdyjs 17.10.0-dev.1 → 17.12.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crowdy-studio/controller.d.ts +15 -0
- package/dist/crowdy-studio/controller.d.ts.map +1 -1
- package/dist/crowdy-studio/controller.js +75 -16
- package/dist/crowdy-studio/embed/panel.d.ts +9 -1
- package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
- package/dist/crowdy-studio/embed/panel.js +4 -0
- package/dist/crowdy-studio/index.d.ts +1 -1
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/domains/exec.d.ts +136 -6
- package/dist/domains/exec.d.ts.map +1 -1
- package/dist/domains/exec.js +197 -5
- package/dist/generated/graphql.d.ts +706 -1
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +32 -0
- package/dist/grid-scope.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/domains/exec.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { decode, encode } from '@msgpack/msgpack';
|
|
2
2
|
import { CrowdyError } from '../errors.js';
|
|
3
|
-
import { ExecActivateVersionDocument, ExecAppStatusDocument, ExecConnectAsDeveloperDocument, ExecConnectDocument, ExecDeployDocument, ExecInstancesDocument, ExecLogsDocument, ExecSetEnabledDocument, ExecVersionsDocument, } from '../generated/graphql.js';
|
|
3
|
+
import { ExecActivateVersionDocument, ExecAppStatusDocument, ExecBuildDocument, ExecBuildStatusDocument, ExecConnectAsDeveloperDocument, ExecConnectDocument, ExecDeployDocument, ExecInstancesDocument, ExecLogsDocument, ExecAppModsDocument, ExecModBuildDocument, ExecModBuildStatusDocument, ExecModDeleteDocument, ExecModDeployDocument, ExecModInstallDocument, ExecModListingsDocument, ExecModLogsDocument, ExecModPublishDocument, ExecModScope, ExecModSetEnabledDocument, ExecModSetSwitchDocument, ExecModStarterDocument, ExecModSwitchesDocument, ExecModUnpublishDocument, ExecModsDocument, ExecMyModsDocument, ExecSetEnabledDocument, ExecStartersDocument, ExecVersionsDocument, } from '../generated/graphql.js';
|
|
4
|
+
export { ExecModScope };
|
|
4
5
|
/**
|
|
5
6
|
* ck-exec, the hub-and-spoke execution service (dev-tier preview).
|
|
6
7
|
*
|
|
@@ -512,13 +513,22 @@ async function sha256Hex(bytes) {
|
|
|
512
513
|
const d = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));
|
|
513
514
|
return Array.from(d, (x) => x.toString(16).padStart(2, '0')).join('');
|
|
514
515
|
}
|
|
516
|
+
/** The node type players call a mod by: `mod:<name>`, keyed by its grid id. */
|
|
517
|
+
export function execModType(name) {
|
|
518
|
+
return `mod:${name}`;
|
|
519
|
+
}
|
|
515
520
|
function strip(v) {
|
|
516
521
|
const { __typename: _, ...rest } = v;
|
|
517
522
|
return rest;
|
|
518
523
|
}
|
|
524
|
+
function build(b) {
|
|
525
|
+
const { __typename: _, artifacts, ...rest } = b;
|
|
526
|
+
return { ...rest, artifacts: artifacts.map(strip) };
|
|
527
|
+
}
|
|
519
528
|
/**
|
|
520
|
-
* `client.exec`: connecting players to ck-exec, deploying an app's nodes
|
|
521
|
-
* them (logs, instances, versions, rollback, the kill
|
|
529
|
+
* `client.exec`: connecting players to ck-exec, building and deploying an app's nodes (and
|
|
530
|
+
* the starter packs), and operating them (logs, instances, versions, rollback, the kill
|
|
531
|
+
* switch, developer connections).
|
|
522
532
|
*/
|
|
523
533
|
export class ExecAPI {
|
|
524
534
|
constructor(graphql) {
|
|
@@ -585,6 +595,179 @@ export class ExecAPI {
|
|
|
585
595
|
const data = await this.graphql.request(ExecSetEnabledDocument, { appId, enabled, nodeType });
|
|
586
596
|
return strip(data.execSetEnabled);
|
|
587
597
|
}
|
|
598
|
+
/**
|
|
599
|
+
* The starter packs, which replace the compute templates: a world tick (the root hub), a
|
|
600
|
+
* matchmaker, game sessions and an NPC and mob engine. Build them with {@link build} and
|
|
601
|
+
* deploy the build with `manifest`. Requires `manage_compute`.
|
|
602
|
+
*/
|
|
603
|
+
async starters(appId) {
|
|
604
|
+
const data = await this.graphql.request(ExecStartersDocument, { appId });
|
|
605
|
+
return {
|
|
606
|
+
manifest: JSON.parse(data.execStarters.manifestJson),
|
|
607
|
+
starters: data.execStarters.starters.map((s) => ({
|
|
608
|
+
crate: s.crate,
|
|
609
|
+
nodeType: s.nodeType,
|
|
610
|
+
description: s.description,
|
|
611
|
+
files: s.files.map(strip),
|
|
612
|
+
})),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Builds crates into modules on the platform (`ckx-sdk`, `wasm32-unknown-unknown`), so you
|
|
617
|
+
* need no Rust toolchain. Returns at once with the build queued; wait with
|
|
618
|
+
* {@link waitForBuild}, then {@link deploy} with its `buildId`. Requires `manage_compute`.
|
|
619
|
+
*/
|
|
620
|
+
async build(appId, crates) {
|
|
621
|
+
const data = await this.graphql.request(ExecBuildDocument, {
|
|
622
|
+
input: {
|
|
623
|
+
appId,
|
|
624
|
+
crates: crates.map((c) => ({
|
|
625
|
+
name: c.name,
|
|
626
|
+
files: Array.isArray(c.files)
|
|
627
|
+
? c.files
|
|
628
|
+
: Object.entries(c.files).map(([path, content]) => ({ path, content })),
|
|
629
|
+
})),
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
return build(data.execBuild);
|
|
633
|
+
}
|
|
634
|
+
/** A build's status, log and modules, or null. Requires `view_compute_diagnostics`. */
|
|
635
|
+
async buildStatus(appId, buildId) {
|
|
636
|
+
const data = await this.graphql.request(ExecBuildStatusDocument, { appId, buildId });
|
|
637
|
+
return data.execBuildStatus ? build(data.execBuildStatus) : null;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Polls a build until it succeeds or fails, and returns it either way; a failed build's
|
|
641
|
+
* `log` says why. Throws when it is not done in `timeoutMs` (default 10 minutes).
|
|
642
|
+
*/
|
|
643
|
+
async waitForBuild(appId, buildId, options = {}) {
|
|
644
|
+
const until = Date.now() + (options.timeoutMs ?? 600000);
|
|
645
|
+
for (;;) {
|
|
646
|
+
const b = await this.buildStatus(appId, buildId);
|
|
647
|
+
if (!b)
|
|
648
|
+
throw new CrowdyError({ message: `no build ${buildId} in app ${appId}` });
|
|
649
|
+
if (b.status === 'succeeded' || b.status === 'failed')
|
|
650
|
+
return b;
|
|
651
|
+
if (Date.now() > until)
|
|
652
|
+
throw new CrowdyError({ message: `build ${buildId} is still ${b.status}` });
|
|
653
|
+
await new Promise((r) => setTimeout(r, options.intervalMs ?? 2000));
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
// ---- mods: players' code on grids they own ----
|
|
657
|
+
/** The mod starter (`grid-mod`), a crate to build with {@link modBuild}. Requires access to the app. */
|
|
658
|
+
async modStarter(appId) {
|
|
659
|
+
const data = await this.graphql.request(ExecModStarterDocument, { appId });
|
|
660
|
+
const s = data.execModStarter;
|
|
661
|
+
return { crate: s.crate, nodeType: s.nodeType, description: s.description, files: s.files.map(strip) };
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Builds a mod from one `ckx-sdk` crate, as {@link build} does a developer's. Returns at
|
|
665
|
+
* once; wait with {@link waitForModBuild}, then {@link modDeploy}. One build at a time per
|
|
666
|
+
* player. Requires `write_server_code` in the app.
|
|
667
|
+
*/
|
|
668
|
+
async modBuild(appId, crate) {
|
|
669
|
+
const files = Array.isArray(crate.files)
|
|
670
|
+
? crate.files
|
|
671
|
+
: Object.entries(crate.files).map(([path, content]) => ({ path, content }));
|
|
672
|
+
const data = await this.graphql.request(ExecModBuildDocument, {
|
|
673
|
+
appId,
|
|
674
|
+
crate: { name: crate.name, files },
|
|
675
|
+
});
|
|
676
|
+
return build(data.execModBuild);
|
|
677
|
+
}
|
|
678
|
+
/** A mod build of yours. */
|
|
679
|
+
async modBuildStatus(appId, buildId) {
|
|
680
|
+
const data = await this.graphql.request(ExecModBuildStatusDocument, { appId, buildId });
|
|
681
|
+
return build(data.execModBuildStatus);
|
|
682
|
+
}
|
|
683
|
+
/** Polls a mod build until it succeeds or fails, like {@link waitForBuild}. */
|
|
684
|
+
async waitForModBuild(appId, buildId, options = {}) {
|
|
685
|
+
const until = Date.now() + (options.timeoutMs ?? 600000);
|
|
686
|
+
for (;;) {
|
|
687
|
+
const b = await this.modBuildStatus(appId, buildId);
|
|
688
|
+
if (b.status === 'succeeded' || b.status === 'failed')
|
|
689
|
+
return b;
|
|
690
|
+
if (Date.now() > until)
|
|
691
|
+
throw new CrowdyError({ message: `build ${buildId} is still ${b.status}` });
|
|
692
|
+
await new Promise((r) => setTimeout(r, options.intervalMs ?? 2000));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Deploys a mod build of yours to a grid you own: a new mod starts switched off, and a
|
|
697
|
+
* running one restarts on the new version. Requires being the grid's owner and
|
|
698
|
+
* `write_server_code` on the app tier and the grid.
|
|
699
|
+
*/
|
|
700
|
+
async modDeploy(appId, gridId, name, buildId) {
|
|
701
|
+
const data = await this.graphql.request(ExecModDeployDocument, { appId, gridId, name, buildId });
|
|
702
|
+
return strip(data.execModDeploy);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Switches a mod on your grid on or off. On, it runs as you once the app's code admission
|
|
706
|
+
* admits it. Requires `run_server_code` on the app tier and the grid.
|
|
707
|
+
*/
|
|
708
|
+
async modSetEnabled(appId, gridId, name, enabled) {
|
|
709
|
+
const data = await this.graphql.request(ExecModSetEnabledDocument, { appId, gridId, name, enabled });
|
|
710
|
+
return strip(data.execModSetEnabled);
|
|
711
|
+
}
|
|
712
|
+
/** Stops and removes a mod on your grid, with its state. */
|
|
713
|
+
async modDelete(appId, gridId, name) {
|
|
714
|
+
const data = await this.graphql.request(ExecModDeleteDocument, { appId, gridId, name });
|
|
715
|
+
return data.execModDelete;
|
|
716
|
+
}
|
|
717
|
+
/** A grid's mods, which players in it call as `mod:<name>` with the grid id as key. */
|
|
718
|
+
async mods(appId, gridId) {
|
|
719
|
+
const data = await this.graphql.request(ExecModsDocument, { appId, gridId });
|
|
720
|
+
return data.execMods.map(strip);
|
|
721
|
+
}
|
|
722
|
+
/** Your mods in the app, on every grid. */
|
|
723
|
+
async myMods(appId) {
|
|
724
|
+
const data = await this.graphql.request(ExecMyModsDocument, { appId });
|
|
725
|
+
return data.execMyMods.map(strip);
|
|
726
|
+
}
|
|
727
|
+
/** A mod of yours' guest log lines, newest first. */
|
|
728
|
+
async modLogs(appId, gridId, name, options = {}) {
|
|
729
|
+
const data = await this.graphql.request(ExecModLogsDocument, { appId, gridId, name, ...options });
|
|
730
|
+
return data.execModLogs.map(strip);
|
|
731
|
+
}
|
|
732
|
+
/** Publishes a mod of yours, at its current version, for other grid owners to install. */
|
|
733
|
+
async modPublish(appId, gridId, name, title, description) {
|
|
734
|
+
const data = await this.graphql.request(ExecModPublishDocument, { appId, gridId, name, title, description });
|
|
735
|
+
return strip(data.execModPublish);
|
|
736
|
+
}
|
|
737
|
+
/** The app's listed mods, most installed first. */
|
|
738
|
+
async modListings(appId) {
|
|
739
|
+
const data = await this.graphql.request(ExecModListingsDocument, { appId });
|
|
740
|
+
return data.execModListings.map(strip);
|
|
741
|
+
}
|
|
742
|
+
/** Delists a listing you published; installed copies keep running. */
|
|
743
|
+
async modUnpublish(appId, listingId) {
|
|
744
|
+
const data = await this.graphql.request(ExecModUnpublishDocument, { appId, listingId });
|
|
745
|
+
return data.execModUnpublish;
|
|
746
|
+
}
|
|
747
|
+
/** Installs a listing onto a grid you own as your own mod, switched off. */
|
|
748
|
+
async modInstall(appId, gridId, name, listingId) {
|
|
749
|
+
const data = await this.graphql.request(ExecModInstallDocument, { appId, gridId, name, listingId });
|
|
750
|
+
return strip(data.execModInstall);
|
|
751
|
+
}
|
|
752
|
+
/** The app's mods by grid or owner, or all of them. Requires `view_compute_diagnostics`. */
|
|
753
|
+
async appMods(appId, options = {}) {
|
|
754
|
+
const data = await this.graphql.request(ExecAppModsDocument, { appId, ...options });
|
|
755
|
+
return data.execAppMods.map(strip);
|
|
756
|
+
}
|
|
757
|
+
/** The app's mod switches that are off. Requires `view_compute_diagnostics`. */
|
|
758
|
+
async modSwitches(appId) {
|
|
759
|
+
const data = await this.graphql.request(ExecModSwitchesDocument, { appId });
|
|
760
|
+
return data.execModSwitches.map(strip);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* The mods kill ladder: switch off (or on) one mod (`target`: its mod id), a player's mods
|
|
764
|
+
* (their user id), a grid's (its id), a listing's installs (its id), or every mod in the
|
|
765
|
+
* app (no target). Returns the switches that are off. Requires `manage_compute`.
|
|
766
|
+
*/
|
|
767
|
+
async modSetSwitch(appId, scope, off, options = {}) {
|
|
768
|
+
const data = await this.graphql.request(ExecModSetSwitchDocument, { appId, scope, off, ...options });
|
|
769
|
+
return data.execModSetSwitch.map(strip);
|
|
770
|
+
}
|
|
588
771
|
/** A host for this player and its connect token (valid for about a minute). */
|
|
589
772
|
async endpoint(appId, options = {}) {
|
|
590
773
|
const data = await this.graphql.request(ExecConnectDocument, {
|
|
@@ -606,14 +789,22 @@ export class ExecAPI {
|
|
|
606
789
|
}
|
|
607
790
|
/**
|
|
608
791
|
* Deploys a new version of the app's nodes and makes it active: the manifest, and
|
|
609
|
-
* each distinct module once.
|
|
610
|
-
*
|
|
792
|
+
* each distinct module once. A type gives its module as `wasm`, or names a `crate` of
|
|
793
|
+
* `buildId`, whose modules the platform already holds. Running instances pick it up
|
|
794
|
+
* when they next start. Requires the org `manage_compute` permission.
|
|
611
795
|
*/
|
|
612
796
|
async deploy(options) {
|
|
613
797
|
const types = {};
|
|
614
798
|
const artifacts = new Map();
|
|
615
799
|
for (const [name, t] of Object.entries(options.types)) {
|
|
616
800
|
const { wasm, ...spec } = t;
|
|
801
|
+
if (!wasm) {
|
|
802
|
+
if (!spec.crate || !options.buildId) {
|
|
803
|
+
throw new CrowdyError({ message: `type '${name}' needs its wasm, or a crate of the deploy's buildId` });
|
|
804
|
+
}
|
|
805
|
+
types[name] = spec;
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
617
808
|
const digest = await sha256Hex(wasm);
|
|
618
809
|
if (!artifacts.has(digest))
|
|
619
810
|
artifacts.set(digest, base64(wasm));
|
|
@@ -624,6 +815,7 @@ export class ExecAPI {
|
|
|
624
815
|
appId: options.appId,
|
|
625
816
|
manifestJson: JSON.stringify({ root: options.root, types }),
|
|
626
817
|
artifacts: [...artifacts].map(([digest, wasmBase64]) => ({ digest, wasmBase64 })),
|
|
818
|
+
buildId: options.buildId,
|
|
627
819
|
},
|
|
628
820
|
});
|
|
629
821
|
return data.execDeploy;
|