@powly/sdk 0.4.1 → 0.8.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/README.md +17 -2
- package/dist/powly.d.ts +210 -6
- package/dist/powly.js +372 -14
- package/dist/powly.mjs +372 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The SDK for games on [Powly](https://powly.gg): the launch handshake with Powly, the player's
|
|
4
4
|
profile, session tokens and the platform services (saves, leaderboards, achievements, friends,
|
|
5
|
-
invites, multiplayer rooms, Twitch chat).
|
|
5
|
+
invites, multiplayer rooms, Twitch chat, sound settings).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -31,7 +31,7 @@ await powly.leaderboards.submit("high-score", 1200);
|
|
|
31
31
|
Without a bundler, load the classic script instead; it defines `window.Powly`:
|
|
32
32
|
|
|
33
33
|
```html
|
|
34
|
-
<script src="https://cdn.jsdelivr.net/npm/@powly/sdk@0.
|
|
34
|
+
<script src="https://cdn.jsdelivr.net/npm/@powly/sdk@0.8.0/dist/powly.js"></script>
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Testing
|
|
@@ -54,3 +54,18 @@ await Powly.init({ powlyOrigin: "https://games.example.com" });
|
|
|
54
54
|
The game runs in the player's browser, so nothing here is a security boundary. Saves and
|
|
55
55
|
leaderboard scores are written by your backend unless the studio allows browser writes for them;
|
|
56
56
|
your backend verifies session tokens or exchanges them for an access token.
|
|
57
|
+
|
|
58
|
+
## This repository
|
|
59
|
+
|
|
60
|
+
The SDK is developed in Powly's main repository and mirrored here with each release; this is
|
|
61
|
+
`@powly/sdk` 0.8.0. Issues are welcome; changes land through the main repository.
|
|
62
|
+
|
|
63
|
+
To build it yourself (Node.js 24 or newer):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install
|
|
67
|
+
npm run build
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`dist/powly.mjs`, `dist/powly.js` and `dist/powly.d.ts` are what npm ships. `examples/` has
|
|
71
|
+
Starfall, a small example game, and the SDK playground (every SDK function behind a button).
|
package/dist/powly.d.ts
CHANGED
|
@@ -1,9 +1,51 @@
|
|
|
1
|
-
/* Powly SDK 0.
|
|
1
|
+
/* Powly SDK 0.8.0: types for powly.js and powly.mjs */
|
|
2
2
|
/** This SDK's version; Powly's Studio shows it next to the downloads. */
|
|
3
|
-
export declare const SDK_VERSION = "0.
|
|
3
|
+
export declare const SDK_VERSION = "0.8.0";
|
|
4
4
|
|
|
5
5
|
export declare const PROTOCOL = "powly-sdk";
|
|
6
6
|
export declare const PROTOCOL_VERSION = 1;
|
|
7
|
+
/** The corners Powly's options button (its mascot, which opens the player's options) can be in. */
|
|
8
|
+
export declare const OPTIONS_BUTTON_CORNERS: readonly ["top-left", "top-right", "bottom-left", "bottom-right"];
|
|
9
|
+
export type OptionsButtonCorner = (typeof OPTIONS_BUTTON_CORNERS)[number];
|
|
10
|
+
export declare const isOptionsButtonCorner: (value: unknown) => value is OptionsButtonCorner;
|
|
11
|
+
/**
|
|
12
|
+
* A kind of sound the game has (music, drawing sounds…), which Powly's sound menu shows with a
|
|
13
|
+
* volume slider (`volume`, default true), an on/off switch (`toggle`, default true), or both.
|
|
14
|
+
*/
|
|
15
|
+
export type AudioChannel = {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
volume?: boolean;
|
|
19
|
+
toggle?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/** One channel's setting: its volume, 0 to 1, and whether it's on. */
|
|
22
|
+
export type ChannelState = {
|
|
23
|
+
volume: number;
|
|
24
|
+
on: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** Channel ids: letters, digits, _ and -, starting with a letter, up to 32. */
|
|
27
|
+
export declare const AUDIO_CHANNEL_ID: RegExp;
|
|
28
|
+
export declare const MAX_AUDIO_CHANNELS = 8;
|
|
29
|
+
export declare const MAX_AUDIO_LABEL = 32;
|
|
30
|
+
/**
|
|
31
|
+
* The player's sound settings from Powly's sound menu. `volume` (0 to 1) is the player's overall
|
|
32
|
+
* volume, `channels` the game's own (by channel id); `muted` silences everything.
|
|
33
|
+
*/
|
|
34
|
+
export type AudioState = {
|
|
35
|
+
volume: number;
|
|
36
|
+
muted: boolean;
|
|
37
|
+
channels: Record<string, ChannelState>;
|
|
38
|
+
};
|
|
39
|
+
/** The channels a game sent, cleaned up: valid ids, short labels, no repeats, at most 8. */
|
|
40
|
+
export declare function audioChannelsOf(value: unknown): AudioChannel[];
|
|
41
|
+
/** What a game changes from its own sound menu; channels by id, only the fields given. */
|
|
42
|
+
export type AudioChanges = {
|
|
43
|
+
volume?: number;
|
|
44
|
+
muted?: boolean;
|
|
45
|
+
channels?: Record<string, Partial<ChannelState>>;
|
|
46
|
+
};
|
|
47
|
+
/** A volume between 0 and 1, or null. */
|
|
48
|
+
export declare const volumeOf: (value: unknown) => number | null;
|
|
7
49
|
export type InitMessage = {
|
|
8
50
|
protocol: typeof PROTOCOL;
|
|
9
51
|
version: number;
|
|
@@ -14,6 +56,18 @@ export type InitMessage = {
|
|
|
14
56
|
* SDKs leave it out.
|
|
15
57
|
*/
|
|
16
58
|
pac?: 1;
|
|
59
|
+
/**
|
|
60
|
+
* Where the game wants Powly's options button to start (`Powly.init({ optionsButton })`); the
|
|
61
|
+
* player's own choice wins. Left out: Powly's default (top left).
|
|
62
|
+
*/
|
|
63
|
+
optionsButton?: OptionsButtonCorner;
|
|
64
|
+
/**
|
|
65
|
+
* The SDK follows Powly's sound menu (SDK 0.8.0 and later): `channels` are the game's own
|
|
66
|
+
* volume controls, shown as sliders. Older SDKs leave it out.
|
|
67
|
+
*/
|
|
68
|
+
audio?: {
|
|
69
|
+
channels: AudioChannel[];
|
|
70
|
+
};
|
|
17
71
|
};
|
|
18
72
|
export type PlayerProfile = {
|
|
19
73
|
/** This player's ID in this game: stable, and different in every game. */
|
|
@@ -40,12 +94,19 @@ export type ReadyMessage = {
|
|
|
40
94
|
pac?: {
|
|
41
95
|
guard: boolean;
|
|
42
96
|
};
|
|
97
|
+
/** The player's sound settings when the game starts. Missing from older Powly hosts. */
|
|
98
|
+
audio?: AudioState;
|
|
43
99
|
};
|
|
44
100
|
export type FailedMessage = {
|
|
45
101
|
type: "failed";
|
|
46
102
|
error: string;
|
|
47
103
|
};
|
|
48
|
-
|
|
104
|
+
/** What a game may ask the Powly page for. */
|
|
105
|
+
export declare const HOST_METHODS: readonly ["getSessionToken", "purchases.open", "fullscreen.toggle", "invites.open", "players.open", "twitch.connect", "audio.set", "audio.channels", "quit"];
|
|
106
|
+
export type HostMethod = (typeof HOST_METHODS)[number];
|
|
107
|
+
/** "players.open": what Powly's player dialog opens on. */
|
|
108
|
+
export declare const PLAYER_VIEWS: readonly ["profile", "report"];
|
|
109
|
+
export type PlayerView = (typeof PLAYER_VIEWS)[number];
|
|
49
110
|
export type RequestMessage = {
|
|
50
111
|
type: "request";
|
|
51
112
|
id: number;
|
|
@@ -57,11 +118,33 @@ export type RequestMessage = {
|
|
|
57
118
|
* dialog shows them as in the party, without an Invite button.
|
|
58
119
|
*/
|
|
59
120
|
members?: string[];
|
|
121
|
+
/** "players.open": the player (their player ID in this game) to show. */
|
|
122
|
+
playerId?: string;
|
|
123
|
+
/** "players.open": open on the profile (the default) or straight on reporting them. */
|
|
124
|
+
view?: PlayerView;
|
|
125
|
+
/** "audio.set": what the game's own sound menu changed. */
|
|
126
|
+
audio?: AudioChanges;
|
|
127
|
+
/** "audio.channels": every channel the game has now (registered later than init). */
|
|
128
|
+
channels?: AudioChannel[];
|
|
60
129
|
};
|
|
61
130
|
/** What "invites.open" answers once Powly's dialog closed: the friends the player invited. */
|
|
62
131
|
export type InvitesOpenResult = {
|
|
63
132
|
invited: string[];
|
|
64
133
|
};
|
|
134
|
+
/**
|
|
135
|
+
* What "players.open" answers once Powly's player dialog closed: whether the player has that
|
|
136
|
+
* player blocked now (the game may hide their chat, say). Whether they reported them stays private.
|
|
137
|
+
*/
|
|
138
|
+
export type PlayersOpenResult = {
|
|
139
|
+
blocked: boolean;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* What "twitch.connect" answers once Powly's Connect Twitch dialog closed: whether the player's
|
|
143
|
+
* Twitch is connected now (the SDK then reads GET /twitch again).
|
|
144
|
+
*/
|
|
145
|
+
export type TwitchConnectResult = {
|
|
146
|
+
connected: boolean;
|
|
147
|
+
};
|
|
65
148
|
export type ResponseMessage = {
|
|
66
149
|
type: "response";
|
|
67
150
|
id: number;
|
|
@@ -73,13 +156,28 @@ export type ResponseMessage = {
|
|
|
73
156
|
ok: false;
|
|
74
157
|
error: string;
|
|
75
158
|
};
|
|
76
|
-
|
|
159
|
+
/**
|
|
160
|
+
* "shown": Powly's loading screen is gone and the game is on screen (once per launch). "pause" /
|
|
161
|
+
* "resume": Powly UI covers the game or the tab is hidden, and back. "ended": the launch ended.
|
|
162
|
+
*/
|
|
163
|
+
export type HostEventName = "shown" | "pause" | "resume" | "ended";
|
|
77
164
|
export type EventMessage = {
|
|
78
165
|
type: "event";
|
|
79
166
|
event: HostEventName;
|
|
167
|
+
}
|
|
168
|
+
/** The player changed the sound settings (Powly's sound menu, or its M key). */
|
|
169
|
+
| {
|
|
170
|
+
type: "event";
|
|
171
|
+
event: "audio";
|
|
172
|
+
audio: AudioState;
|
|
80
173
|
};
|
|
81
174
|
export type HostMessage = ReadyMessage | FailedMessage | ResponseMessage | EventMessage;
|
|
82
175
|
export declare const isInitMessage: (data: unknown) => data is InitMessage;
|
|
176
|
+
/** A request with a method this Powly doesn't know (from a newer SDK): answered with an error. */
|
|
177
|
+
export declare const isRequestShaped: (data: unknown) => data is {
|
|
178
|
+
type: "request";
|
|
179
|
+
id: number;
|
|
180
|
+
};
|
|
83
181
|
export declare const isRequestMessage: (data: unknown) => data is RequestMessage;
|
|
84
182
|
|
|
85
183
|
export declare const POWLY_ORIGINS: readonly string[];
|
|
@@ -113,6 +211,8 @@ export type PacSample = {
|
|
|
113
211
|
keyIntervalSd: number | null;
|
|
114
212
|
clickIntervals: number;
|
|
115
213
|
clickIntervalSd: number | null;
|
|
214
|
+
/** Every trusted interaction: key presses, clicks, taps, pointer movement, wheel, gamepads. */
|
|
215
|
+
activity: number;
|
|
116
216
|
};
|
|
117
217
|
};
|
|
118
218
|
export declare const isPacSample: (data: unknown) => data is PacSample;
|
|
@@ -466,14 +566,21 @@ type Events = {
|
|
|
466
566
|
};
|
|
467
567
|
state: TwitchChatState;
|
|
468
568
|
};
|
|
569
|
+
export type ConnectOptions = {
|
|
570
|
+
/** Ask the player to connect Twitch in Powly's dialog when they haven't. Default false. */
|
|
571
|
+
prompt?: boolean;
|
|
572
|
+
};
|
|
469
573
|
export type TwitchApi = {
|
|
470
574
|
/** The game's setting and the player's channel, without opening chat. */
|
|
471
575
|
info(): Promise<TwitchInfo>;
|
|
472
576
|
/**
|
|
473
577
|
* Opens the player's chat when they have a channel to read (`status: "connected"`). Resolves
|
|
474
578
|
* with the info, once chat is joined (or failed to; it keeps retrying in the background).
|
|
579
|
+
* `prompt`: when the player hasn't connected Twitch, Powly first asks them to in its own dialog
|
|
580
|
+
* (they can connect it there without leaving the game); `status` is still "not_connected" if
|
|
581
|
+
* they closed it.
|
|
475
582
|
*/
|
|
476
|
-
connect(): Promise<TwitchInfo>;
|
|
583
|
+
connect(options?: ConnectOptions): Promise<TwitchInfo>;
|
|
477
584
|
/** Closes chat; `connect()` opens it again. */
|
|
478
585
|
disconnect(): void;
|
|
479
586
|
readonly state: TwitchChatState;
|
|
@@ -494,6 +601,8 @@ export declare function parseIrcLine(line: string): IrcMessage | null;
|
|
|
494
601
|
export declare function chatMessageOf(message: IrcMessage): TwitchChatMessage | null;
|
|
495
602
|
export declare function createTwitch(options: {
|
|
496
603
|
getInfo: () => Promise<TwitchInfo>;
|
|
604
|
+
/** Opens Powly's Connect Twitch dialog; resolves with whether Twitch is connected now. */
|
|
605
|
+
prompt?: () => Promise<boolean>;
|
|
497
606
|
/** Twitch chat's WebSocket URL (tests point it elsewhere). */
|
|
498
607
|
url?: string;
|
|
499
608
|
}): TwitchApi & {
|
|
@@ -501,6 +610,58 @@ export declare function createTwitch(options: {
|
|
|
501
610
|
};
|
|
502
611
|
|
|
503
612
|
|
|
613
|
+
export type AudioOptions = {
|
|
614
|
+
/**
|
|
615
|
+
* The game's kinds of sound, shown in Powly's sound menu (up to 8): `{ id, label }`, with a
|
|
616
|
+
* volume slider (`volume: false` leaves it out) and an on/off switch (`toggle: false`).
|
|
617
|
+
*/
|
|
618
|
+
channels?: AudioChannel[];
|
|
619
|
+
/**
|
|
620
|
+
* Apply the overall volume and mute to the page's sound by itself. Default true; turn it off
|
|
621
|
+
* when the game applies `level()` to everything itself.
|
|
622
|
+
*/
|
|
623
|
+
auto?: boolean;
|
|
624
|
+
};
|
|
625
|
+
export type AudioApi = {
|
|
626
|
+
/** The player's overall volume, 0 to 1. */
|
|
627
|
+
readonly volume: number;
|
|
628
|
+
/** Everything silenced (Powly's mute, or its M key). */
|
|
629
|
+
readonly muted: boolean;
|
|
630
|
+
/** The game's channels by id: their volume (0 to 1) and whether they're on. */
|
|
631
|
+
readonly channels: Record<string, ChannelState>;
|
|
632
|
+
/**
|
|
633
|
+
* What to play at, 0 to 1: a channel's volume (0 while it's off), or (no channel) full volume.
|
|
634
|
+
* With `auto` off, the overall volume and mute are in it too.
|
|
635
|
+
*/
|
|
636
|
+
level(channel?: string): number;
|
|
637
|
+
/**
|
|
638
|
+
* Adds a channel to Powly's sound menu after init (or changes its label or controls), e.g.
|
|
639
|
+
* once a mode with its own sounds starts. Up to 8 channels.
|
|
640
|
+
*/
|
|
641
|
+
register(channel: AudioChannel): Promise<void>;
|
|
642
|
+
/**
|
|
643
|
+
* Changes the settings from the game's own sound menu, so Powly's stays the same:
|
|
644
|
+
* `{ volume, muted, channels: { music: { volume: 0.5 }, drawing: { on: false } } }`. Unknown
|
|
645
|
+
* channels are ignored.
|
|
646
|
+
*/
|
|
647
|
+
set(changes: AudioChanges): Promise<void>;
|
|
648
|
+
/** The settings changed (in Powly's sound menu, or with `set`). */
|
|
649
|
+
on(event: "change", listener: (audio: AudioState) => void): () => void;
|
|
650
|
+
};
|
|
651
|
+
/** Volume of the page's sound overall: 0 when muted. */
|
|
652
|
+
export declare const masterLevel: (state: AudioState) => number;
|
|
653
|
+
/**
|
|
654
|
+
* Puts a volume control in front of the page's speakers: Web Audio connections to a real-time
|
|
655
|
+
* AudioContext's destination go through a gain node per context, and media elements' volume is
|
|
656
|
+
* scaled (the volume the game set still reads back unchanged; elements played through Web Audio
|
|
657
|
+
* are left to the gain node). Returns how to set it.
|
|
658
|
+
*/
|
|
659
|
+
export declare function installMasterGain(win?: Window & typeof globalThis): {
|
|
660
|
+
set(level: number): void;
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
504
665
|
|
|
505
666
|
|
|
506
667
|
|
|
@@ -515,6 +676,18 @@ export type InitOptions = {
|
|
|
515
676
|
powlyOrigin?: string | string[];
|
|
516
677
|
/** How long to wait for Powly to answer (ms). Default 10 s. */
|
|
517
678
|
timeoutMs?: number;
|
|
679
|
+
/**
|
|
680
|
+
* Which corner Powly's options button (its mascot, which opens the player's options) starts in:
|
|
681
|
+
* "top-left" (the default), "top-right", "bottom-left" or "bottom-right". Pick the one your own
|
|
682
|
+
* UI leaves free. Players can still move it, and their choice wins.
|
|
683
|
+
*/
|
|
684
|
+
optionsButton?: OptionsButtonCorner;
|
|
685
|
+
/**
|
|
686
|
+
* Powly's sound menu (src/audio.ts): the game's own volume `channels` (sliders next to the
|
|
687
|
+
* player's overall volume), and whether the SDK applies the overall volume and mute to the
|
|
688
|
+
* page's sound itself (`auto`, default true).
|
|
689
|
+
*/
|
|
690
|
+
audio?: AudioOptions;
|
|
518
691
|
};
|
|
519
692
|
export type LeaderboardEntry = {
|
|
520
693
|
rank: number;
|
|
@@ -586,6 +759,25 @@ export type PowlySession = {
|
|
|
586
759
|
invited: string[];
|
|
587
760
|
}>;
|
|
588
761
|
};
|
|
762
|
+
/**
|
|
763
|
+
* Other players of this game, by their player ID (from rooms, leaderboards, friends…).
|
|
764
|
+
* `open` shows Powly's own dialog over the game (drawn by Powly, not the game) with their
|
|
765
|
+
* profile, where the player can add them as a friend, block or report them; with
|
|
766
|
+
* `{ view: "report" }` it opens straight on reporting them. Games can't file reports
|
|
767
|
+
* themselves: the player always confirms in Powly's dialog. Resolves when it closes, with
|
|
768
|
+
* whether the player has them blocked now (hide their chat, say). Fails for player IDs that
|
|
769
|
+
* aren't from this game.
|
|
770
|
+
*/
|
|
771
|
+
players: {
|
|
772
|
+
open(playerId: string, options?: {
|
|
773
|
+
view?: PlayerView;
|
|
774
|
+
}): Promise<PlayersOpenResult>;
|
|
775
|
+
};
|
|
776
|
+
/**
|
|
777
|
+
* The player's sound settings from Powly's options bar: overall volume, mute and the game's
|
|
778
|
+
* channels (`Powly.init({ audio: { channels } })`). Play each channel at `level(channel)`.
|
|
779
|
+
*/
|
|
780
|
+
audio: AudioApi;
|
|
589
781
|
/** Realtime rooms (parties) with other players of this game. */
|
|
590
782
|
rooms: RoomsApi;
|
|
591
783
|
/**
|
|
@@ -647,8 +839,20 @@ export type PowlySession = {
|
|
|
647
839
|
fullscreen: {
|
|
648
840
|
toggle(): Promise<void>;
|
|
649
841
|
};
|
|
650
|
-
/**
|
|
842
|
+
/**
|
|
843
|
+
* Closes the game, like the exit button in Powly's options bar: the player goes back to the
|
|
844
|
+
* game's store page and the launch ends ("ended" fires). Save the player's progress first.
|
|
845
|
+
*/
|
|
846
|
+
quit(): Promise<void>;
|
|
847
|
+
/**
|
|
848
|
+
* Powly's loading screen is gone and the game is on screen ("shown": start the intro or music
|
|
849
|
+
* here), Powly UI opened over the game ("pause"), closed ("resume"), or the launch ended
|
|
850
|
+
* ("ended"). "shown" comes once per launch; listening for it later calls the listener right
|
|
851
|
+
* away.
|
|
852
|
+
*/
|
|
651
853
|
on(event: HostEventName, listener: () => void): () => void;
|
|
854
|
+
/** Whether Powly's loading screen is gone and the game is on screen ("shown" came). */
|
|
855
|
+
readonly shown: boolean;
|
|
652
856
|
};
|
|
653
857
|
/** Starts the SDK. Rejects when the game wasn't launched from Powly. */
|
|
654
858
|
export declare function init(options?: InitOptions): Promise<PowlySession>;
|