@simeonradivoev/gameflow-sdk 1.5.1 → 1.6.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 +15 -0
- package/build.ts +27 -0
- package/hooks/app.ts +12 -0
- package/hooks/auth.ts +10 -0
- package/hooks/emulators.ts +39 -0
- package/hooks/games.ts +174 -0
- package/hooks/store.ts +10 -0
- package/index.ts +92 -0
- package/package.json +50 -53
- package/sdk.tsconfig.json +22 -0
- package/shared.ts +631 -0
- package/task-queue.ts +307 -0
- package/index.d.ts +0 -1219
package/README.md
CHANGED
|
@@ -13,3 +13,18 @@ The package must expose a main script gameflow will import and validate. It must
|
|
|
13
13
|
|
|
14
14
|
For the plugin to show up in the UI for download. It must be published to NPM with the `gameflow-plugin` keyword. Gameflow uses bun to install plugins as packages from npmjs.
|
|
15
15
|
Follow publishing instruction check the [NPM Docs](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry)
|
|
16
|
+
|
|
17
|
+
## Dependencies
|
|
18
|
+
|
|
19
|
+
Peer dependencies will not be installed when the run adds the plugin package. They are provided by gameflow.
|
|
20
|
+
All peer dependencies can be marked as external as gameflow provides it. There is a helper build script that does all that for you, to run it use.
|
|
21
|
+
|
|
22
|
+
`bunx gameflow-build --entry=index.ts`
|
|
23
|
+
|
|
24
|
+
supported arguments are
|
|
25
|
+
`--entry` the entry of the app to build
|
|
26
|
+
`--outdir` Where to build. Default is 'dist'
|
|
27
|
+
`--minify` Minify the code. Default is 'false'
|
|
28
|
+
`--sourcemap` Include a source map. Default is 'none'
|
|
29
|
+
|
|
30
|
+
If you want to include dependencies that gameflow does not provide you have to bundle them in. Gameflow does not load dependencies for you.
|
package/build.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import pkg from './package.json';
|
|
4
|
+
|
|
5
|
+
import { parseArgs } from "util";
|
|
6
|
+
|
|
7
|
+
const { values } = parseArgs({
|
|
8
|
+
args: Bun.argv.slice(2),
|
|
9
|
+
options: {
|
|
10
|
+
outdir: { type: "string", default: "dist" },
|
|
11
|
+
minify: { type: "boolean", default: false },
|
|
12
|
+
sourcemap: { type: "string", default: "none" }, // "none" | "inline" | "external"
|
|
13
|
+
entry: { type: "string", default: "src/index.ts" },
|
|
14
|
+
},
|
|
15
|
+
allowPositionals: true,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await Bun.build({
|
|
19
|
+
entrypoints: [values.entry],
|
|
20
|
+
outdir: values.outdir,
|
|
21
|
+
minify: values.minify,
|
|
22
|
+
sourcemap: values.sourcemap as any,
|
|
23
|
+
external: [...Object.keys(pkg.peerDependencies), pkg.name],
|
|
24
|
+
target: "bun",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log(`✅ Built to ${values.outdir}`);
|
package/hooks/app.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import AuthHooks from "./auth";
|
|
2
|
+
import EmulatorHooks from "./emulators";
|
|
3
|
+
import GameHooks from "./games";
|
|
4
|
+
import StoreHooks from "./store";
|
|
5
|
+
|
|
6
|
+
export class GameflowHooks
|
|
7
|
+
{
|
|
8
|
+
games = new GameHooks();
|
|
9
|
+
emulators = new EmulatorHooks();
|
|
10
|
+
auth = new AuthHooks();
|
|
11
|
+
store = new StoreHooks();
|
|
12
|
+
}
|
package/hooks/auth.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
import { AsyncSeriesHook } from "tapable";
|
|
3
|
+
import { DownloadFileEntry } from "../shared";
|
|
4
|
+
|
|
5
|
+
export default class AuthHooks
|
|
6
|
+
{
|
|
7
|
+
loginComplete = new AsyncSeriesHook<[ctx: {
|
|
8
|
+
service: string;
|
|
9
|
+
}], { auth?: string, files: DownloadFileEntry[]; } | undefined>(['ctx']);
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
import { EmulatorPostInstallContextType } from "../index";
|
|
3
|
+
import { DownloadFileEntry, EmulatorSourceEntryType, EmulatorSystem } from "../shared";
|
|
4
|
+
import { AsyncSeriesBailHook, AsyncSeriesHook } from "tapable";
|
|
5
|
+
|
|
6
|
+
export default class EmulatorHooks
|
|
7
|
+
{
|
|
8
|
+
fetchBiosDownload = new AsyncSeriesBailHook<[ctx: {
|
|
9
|
+
emulator: string;
|
|
10
|
+
systems: EmulatorSystem[];
|
|
11
|
+
biosFolder: string;
|
|
12
|
+
}], { auth?: string, files: DownloadFileEntry[]; } | undefined>(['ctx']);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Triggered when emulator is downloaded or updated
|
|
16
|
+
*/
|
|
17
|
+
emulatorPostInstall = new AsyncSeriesHook<[ctx: EmulatorPostInstallContextType], { emulator: string; }>(['ctx']);
|
|
18
|
+
findEmulatorSource = new AsyncSeriesHook<[ctx: { emulator: string; sources: EmulatorSourceEntryType[]; }]>(['ctx']);
|
|
19
|
+
findEmulatorForSystem = new AsyncSeriesHook<[ctx: { system: string; emulators: string[]; }]>(['ctx']);
|
|
20
|
+
|
|
21
|
+
constructor()
|
|
22
|
+
{
|
|
23
|
+
this.emulatorPostInstall.intercept({
|
|
24
|
+
register (tap)
|
|
25
|
+
{
|
|
26
|
+
return {
|
|
27
|
+
...tap,
|
|
28
|
+
fn: async (ctx: EmulatorPostInstallContextType, ...rest: any[]) =>
|
|
29
|
+
{
|
|
30
|
+
if (ctx.emulator === tap.emulator)
|
|
31
|
+
{
|
|
32
|
+
tap.fn(ctx, ...rest);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
package/hooks/games.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
|
|
2
|
+
import { EmulatorPackageType, GameListFilterType, CommandEntry, DownloadInfo, EmulatorSourceEntryType, EmulatorSupport, EmulatorSystem, FrontEndCollection, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailed, FrontEndGameTypeWithIds, FrontEndId, FrontEndPlatformType, GameLookup, SaveFileChange, SaveSlots } from '../shared';
|
|
3
|
+
import { SyncBailHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesWaterfallHook } from 'tapable';
|
|
4
|
+
|
|
5
|
+
export default class GameHooks
|
|
6
|
+
{
|
|
7
|
+
buildLaunchCommands = new AsyncSeriesBailHook<[ctx: {
|
|
8
|
+
source: string | null;
|
|
9
|
+
sourceId: string | null;
|
|
10
|
+
id: FrontEndId;
|
|
11
|
+
systemSlug: string;
|
|
12
|
+
gamePath: string | null,
|
|
13
|
+
mainGlob?: string | null,
|
|
14
|
+
}], CommandEntry[] | Error | undefined>(['ctx']);
|
|
15
|
+
/** override the launch command for an emulator
|
|
16
|
+
* @param ctx.autoValidCommands The auto generated command for example based on the ES-DE listing
|
|
17
|
+
* @param ctx.emulator The emulator ID if any
|
|
18
|
+
* @param ctx.game.source The source of the game
|
|
19
|
+
* @param ctx.game.sourceId The ID of the source. This could be for example the ROMM ID the game was
|
|
20
|
+
* @returns The argument list to be used when running the emulator.
|
|
21
|
+
* If no emulator bin in the command entry is found the actual command will be used as the bin.
|
|
22
|
+
*/
|
|
23
|
+
emulatorLaunch = new AsyncSeriesBailHook<[ctx: {
|
|
24
|
+
autoValidCommand: CommandEntry;
|
|
25
|
+
dryRun: boolean,
|
|
26
|
+
game: {
|
|
27
|
+
source?: string;
|
|
28
|
+
sourceId?: string;
|
|
29
|
+
id: FrontEndId;
|
|
30
|
+
platformSlug?: string;
|
|
31
|
+
};
|
|
32
|
+
}], { args: string[], savesPath?: SaveSlots; env?: Record<string, string>; } | undefined, { emulator: string; }>(['ctx']);
|
|
33
|
+
/**
|
|
34
|
+
* Is the given emulator for the given command supported
|
|
35
|
+
* @returns The current support level. Partial means it can affect some functionality. Full means fully integrated for example with portable ones where you can control all aspects.
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
emulatorLaunchSupport = new SyncBailHook<[ctx: {
|
|
39
|
+
emulator: string;
|
|
40
|
+
source?: EmulatorSourceEntryType;
|
|
41
|
+
}], EmulatorSupport | undefined, { emulator: string; }>(['ctx']);
|
|
42
|
+
/**
|
|
43
|
+
* Fetches and returns a list of games converted to frontend.
|
|
44
|
+
* @param ctx.localGameIds This is local game ids in the format '<source>@<sourceId>'
|
|
45
|
+
*/
|
|
46
|
+
fetchGames = new AsyncSeriesHook<[ctx: {
|
|
47
|
+
query: GameListFilterType;
|
|
48
|
+
games: FrontEndGameTypeWithIds[];
|
|
49
|
+
}]>(['ctx']);
|
|
50
|
+
fetchFilters = new AsyncSeriesHook<[ctx: {
|
|
51
|
+
source?: string;
|
|
52
|
+
filters: FrontEndFilterSets;
|
|
53
|
+
}]>(['ctx']);
|
|
54
|
+
fetchGame = new AsyncSeriesBailHook<[ctx: {
|
|
55
|
+
source: string;
|
|
56
|
+
localGame?: FrontEndGameTypeDetailed;
|
|
57
|
+
id: string;
|
|
58
|
+
}], FrontEndGameTypeDetailed | undefined>(['ctx']);
|
|
59
|
+
searchGame = new AsyncSeriesBailHook<[ctx: {
|
|
60
|
+
source: string;
|
|
61
|
+
igdb_id?: number;
|
|
62
|
+
ra_id?: number;
|
|
63
|
+
}], FrontEndGameTypeDetailed | undefined>(['ctx']);
|
|
64
|
+
/** Get download file URLs
|
|
65
|
+
* @param ctx.checksum Check if file already exists using checksums
|
|
66
|
+
*/
|
|
67
|
+
fetchDownloads = new AsyncSeriesBailHook<[ctx: {
|
|
68
|
+
source: string;
|
|
69
|
+
id: string;
|
|
70
|
+
downloadId?: string;
|
|
71
|
+
}], DownloadInfo[] | undefined>(['ctx']);
|
|
72
|
+
fetchRomFiles = new AsyncSeriesBailHook<[ctx: {
|
|
73
|
+
source: string;
|
|
74
|
+
id: string;
|
|
75
|
+
}], string[] | undefined>(['ctx']);
|
|
76
|
+
fetchRecommendedGamesForGame = new AsyncSeriesHook<[ctx: {
|
|
77
|
+
game: FrontEndGameTypeDetailed,
|
|
78
|
+
games: (FrontEndGameType & { metadata?: any; })[];
|
|
79
|
+
}]>(['ctx']);
|
|
80
|
+
fetchRecommendedGamesForEmulator = new AsyncSeriesHook<[cts: {
|
|
81
|
+
emulator: EmulatorPackageType;
|
|
82
|
+
systems: EmulatorSystem[];
|
|
83
|
+
games: FrontEndGameType[];
|
|
84
|
+
}]>(['ctx']);
|
|
85
|
+
fetchPlatform = new AsyncSeriesBailHook<[ctx: {
|
|
86
|
+
source: string;
|
|
87
|
+
id: string;
|
|
88
|
+
}], FrontEndPlatformType | undefined>(['ctx']);
|
|
89
|
+
platformLookup = new AsyncSeriesBailHook<[ctx: {
|
|
90
|
+
source?: string;
|
|
91
|
+
id?: string;
|
|
92
|
+
slug?: string;
|
|
93
|
+
}], {
|
|
94
|
+
slug: string;
|
|
95
|
+
url_logo?: string | null;
|
|
96
|
+
name?: string;
|
|
97
|
+
family_name?: string;
|
|
98
|
+
} | undefined>(['ctx']);
|
|
99
|
+
gameLookup = new AsyncSeriesWaterfallHook<[matches: Map<string, GameLookup[]>, ctx: {
|
|
100
|
+
source?: string,
|
|
101
|
+
id?: string;
|
|
102
|
+
search?: string;
|
|
103
|
+
}]>(['matches', 'ctx']);
|
|
104
|
+
fetchPlatforms = new AsyncSeriesHook<[ctx: {
|
|
105
|
+
platforms: FrontEndPlatformType[];
|
|
106
|
+
}]>(['ctx']);
|
|
107
|
+
prePlay = new AsyncSeriesHook<[ctx: {
|
|
108
|
+
source: string,
|
|
109
|
+
id: string;
|
|
110
|
+
saveFolderSlots: Record<string, { cwd: string; }>;
|
|
111
|
+
setProgress: (progress: number, state: string) => void,
|
|
112
|
+
command: CommandEntry;
|
|
113
|
+
gameInfo: {
|
|
114
|
+
platformSlug?: string;
|
|
115
|
+
};
|
|
116
|
+
}]>(["ctx"]);
|
|
117
|
+
/**
|
|
118
|
+
* @param changedSaveFiles Auto detected changed files. This is mainly used to see what changed during gameplay
|
|
119
|
+
* @param validChangedSaveFiles This will be final valid changes to be saved using save integrations like rclone
|
|
120
|
+
*/
|
|
121
|
+
postPlay = new AsyncSeriesHook<[ctx: {
|
|
122
|
+
source: string,
|
|
123
|
+
id: string;
|
|
124
|
+
saveFolderSlots?: SaveSlots;
|
|
125
|
+
changedSaveFiles: { subPath: string, cwd: string; }[],
|
|
126
|
+
validChangedSaveFiles: Record<string, SaveFileChange>,
|
|
127
|
+
command: CommandEntry;
|
|
128
|
+
gameInfo: {
|
|
129
|
+
platformSlug?: string;
|
|
130
|
+
};
|
|
131
|
+
}]>(["ctx"]);
|
|
132
|
+
postInstall = new AsyncSeriesHook<[ctx: {
|
|
133
|
+
source: string,
|
|
134
|
+
id: string;
|
|
135
|
+
files: string[];
|
|
136
|
+
info: DownloadInfo;
|
|
137
|
+
}]>(['ctx']);
|
|
138
|
+
fetchCollections = new AsyncSeriesHook<[ctx: { collections: FrontEndCollection[]; }]>(['ctx']);
|
|
139
|
+
fetchCollection = new AsyncSeriesBailHook<[ctx: { source: string, id: string; }], FrontEndCollection | undefined>(['ctx']);
|
|
140
|
+
|
|
141
|
+
constructor()
|
|
142
|
+
{
|
|
143
|
+
this.emulatorLaunchSupport.intercept({
|
|
144
|
+
register (tap)
|
|
145
|
+
{
|
|
146
|
+
return {
|
|
147
|
+
...tap,
|
|
148
|
+
fn: (e: any, ...rest: any[]) =>
|
|
149
|
+
{
|
|
150
|
+
if (e.emulator === tap.emulator)
|
|
151
|
+
{
|
|
152
|
+
return tap.fn(e, ...rest);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
this.emulatorLaunch.intercept({
|
|
159
|
+
register (tap)
|
|
160
|
+
{
|
|
161
|
+
return {
|
|
162
|
+
...tap,
|
|
163
|
+
fn: async (e: any, ...rest: any[]) =>
|
|
164
|
+
{
|
|
165
|
+
if ((e.autoValidCommand as CommandEntry).emulator === tap.emulator)
|
|
166
|
+
{
|
|
167
|
+
return tap.fn(e, ...rest);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
package/hooks/store.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FrontEndEmulator, FrontEndEmulatorDetailed, FrontEndGameTypeDetailed, EmulatorDownloadInfoType } from "../shared";
|
|
2
|
+
import { AsyncSeriesBailHook, AsyncSeriesHook } from "tapable";
|
|
3
|
+
|
|
4
|
+
export default class StoreHooks
|
|
5
|
+
{
|
|
6
|
+
fetchFeaturedGames = new AsyncSeriesHook<[ctx: { games: FrontEndGameTypeDetailed[]; }]>(['ctx']);
|
|
7
|
+
fetchEmulators = new AsyncSeriesHook<[ctx: { emulators: FrontEndEmulator[]; search?: string; }]>(['ctx']);
|
|
8
|
+
fetchEmulator = new AsyncSeriesBailHook<[ctx: { id: string; }], FrontEndEmulatorDetailed | undefined>(['ctx']);
|
|
9
|
+
fetchDownload = new AsyncSeriesBailHook<[ctx: { id: string; }], (EmulatorDownloadInfoType & { hasUpdate: boolean; }) | undefined>(['ctx']);
|
|
10
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { GameflowHooks } from "./hooks/app";
|
|
3
|
+
import { EmulatorDownloadInfoSchema, EmulatorPackageSchema, FrontendNotification, SettingsType } from "./shared";
|
|
4
|
+
import { $ZodRegistry } from "zod/v4/core";
|
|
5
|
+
import Conf from "conf";
|
|
6
|
+
import { EventEmitter } from 'node:events';
|
|
7
|
+
import { TaskQueue } from "./task-queue";
|
|
8
|
+
|
|
9
|
+
export * from "./hooks/app";
|
|
10
|
+
export * from "./task-queue";
|
|
11
|
+
|
|
12
|
+
export interface AppEventMap
|
|
13
|
+
{
|
|
14
|
+
exitapp: [];
|
|
15
|
+
notification: [FrontendNotification];
|
|
16
|
+
focus: [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const PluginContextSchema = z.object({
|
|
20
|
+
hooks: z.instanceof(GameflowHooks)
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const PluginLoadingContextSchema = z.object({
|
|
24
|
+
setProgress: z.function().input([z.number(), z.string()]).output(z.void()),
|
|
25
|
+
config: z.instanceof(Conf).describe("Per plugin config. It will use the settings schema defined in the plugin class"),
|
|
26
|
+
zodRegistry: z.instanceof($ZodRegistry).describe("Used by the settings to register metadata for the UI"),
|
|
27
|
+
app: z.object({
|
|
28
|
+
config: z.instanceof(Conf<SettingsType>),
|
|
29
|
+
events: z.instanceof(EventEmitter<AppEventMap>),
|
|
30
|
+
taskQueue: z.instanceof(TaskQueue)
|
|
31
|
+
})
|
|
32
|
+
}).extend(PluginContextSchema.shape);
|
|
33
|
+
|
|
34
|
+
export const PluginDescriptionSchema = z.object({
|
|
35
|
+
name: z.string(),
|
|
36
|
+
displayName: z.string().optional(),
|
|
37
|
+
version: z.string(),
|
|
38
|
+
description: z.string().optional(),
|
|
39
|
+
icon: z.url().optional().describe("Can be an external URL to an image or a data url"),
|
|
40
|
+
keywords: z.array(z.string()).optional(),
|
|
41
|
+
peerDependencies: z.record(z.string(), z.string()).optional(),
|
|
42
|
+
category: z.string().default("other"),
|
|
43
|
+
main: z.string().describe("The main entry. It must export a default class implementing PluginType"),
|
|
44
|
+
canDisable: z.boolean().default(true).optional().describe("Can the plugin be disabled or enabled by the user")
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const PluginSchema = z.object({
|
|
48
|
+
load: z.function().input([PluginLoadingContextSchema]).output(z.promise(z.void())).describe("Called when the plugin is loaded or reloaded"),
|
|
49
|
+
cleanup: z.function().output(z.promise(z.void())).optional().describe("Called when the plugin is unloaded or before it's reloaded"),
|
|
50
|
+
settingsSchema: z.instanceof(z.ZodObject).optional().describe("The settings schema. Gameflow will show settings in the UI."),
|
|
51
|
+
settingsMigrations: z.record(z.string(), z.function().input([z.instanceof(Conf)]).output(z.void())).optional(),
|
|
52
|
+
eventsNames: z.object({
|
|
53
|
+
id: z.string(),
|
|
54
|
+
title: z.string().optional(),
|
|
55
|
+
description: z.string().optional(),
|
|
56
|
+
action: z.string()
|
|
57
|
+
}).array().optional().describe("Events will be called when the user presses the button in plugin settings. Each event creates a button."),
|
|
58
|
+
onEvent: z.function().input([z.string()]).output(z.object({
|
|
59
|
+
openTab: z.string().optional(),
|
|
60
|
+
reload: z.boolean().optional()
|
|
61
|
+
}).or(z.record(z.string(), z.any()))).optional()
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const ActiveGameSchema = z.object({
|
|
65
|
+
process: z.any().optional(),
|
|
66
|
+
gameId: z.object({ id: z.string(), source: z.string() }),
|
|
67
|
+
source: z.string().optional(),
|
|
68
|
+
sourceId: z.string().optional(),
|
|
69
|
+
name: z.string(),
|
|
70
|
+
command: z.object({ command: z.string().or(z.string().array()), startDir: z.string().optional() })
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export const EmulatorPostInstallContextSchema = z.object({
|
|
74
|
+
emulator: z.string(),
|
|
75
|
+
emulatorPackage: EmulatorPackageSchema.optional(),
|
|
76
|
+
path: z.string(),
|
|
77
|
+
update: z.boolean(),
|
|
78
|
+
info: EmulatorDownloadInfoSchema,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export type ActiveGameType = z.infer<typeof ActiveGameSchema>;
|
|
82
|
+
export type PluginDescriptionType = z.infer<typeof PluginDescriptionSchema>;
|
|
83
|
+
export type PluginContextType = z.infer<typeof PluginContextSchema>;
|
|
84
|
+
export type PluginLoadingContextType<TSettings extends Record<string, any> = Record<string, any>> = z.infer<typeof PluginLoadingContextSchema> & {
|
|
85
|
+
config: Conf<TSettings>;
|
|
86
|
+
};
|
|
87
|
+
export type PluginType<T extends Record<string, any> = Record<string, any>> = Omit<z.infer<typeof PluginSchema>, "load" | 'settingsMigrations'> & {
|
|
88
|
+
load: (ctx: PluginLoadingContextType<T>) => Promise<void>;
|
|
89
|
+
settingsMigrations?: Record<string, (conf: Conf<T>) => void>;
|
|
90
|
+
};
|
|
91
|
+
export type EmulatorPostInstallContextType = z.infer<typeof EmulatorPostInstallContextSchema>;
|
|
92
|
+
|
package/package.json
CHANGED
|
@@ -1,54 +1,51 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"zod": "^4.4.3"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
2
|
+
"name": "@simeonradivoev/gameflow-sdk",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"types": "index.d.ts",
|
|
5
|
+
"description": "plugin SDK for the Gameflow Deck Launcher",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.ts",
|
|
8
|
+
"./shared": "./shared.ts"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"gameflow-build": "build.ts"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"7zip-bin": "^5.2.0",
|
|
15
|
+
"@auth/core": "^0.34.3",
|
|
16
|
+
"@elysiajs/cors": "^1.4.2",
|
|
17
|
+
"@elysiajs/eden": "^1.4.9",
|
|
18
|
+
"@jimp/wasm-webp": "^1.6.1",
|
|
19
|
+
"@phalcode/ts-igdb-client": "^1.0.26",
|
|
20
|
+
"cheerio": "^1.2.0",
|
|
21
|
+
"conf": "^15.1.0",
|
|
22
|
+
"drizzle-orm": "^0.45.2",
|
|
23
|
+
"elysia": "^1.4.28",
|
|
24
|
+
"fs-extra": "^11.3.5",
|
|
25
|
+
"get-folder-size": "^5.0.0",
|
|
26
|
+
"ini": "^6.0.0",
|
|
27
|
+
"jimp": "^1.6.1",
|
|
28
|
+
"mustache": "^4.2.0",
|
|
29
|
+
"node-7z": "^3.0.0",
|
|
30
|
+
"node-disk-info": "^1.3.0",
|
|
31
|
+
"node-downloader-helper": "^2.1.11",
|
|
32
|
+
"node-stream-zip": "^1.15.0",
|
|
33
|
+
"node-unrar-js": "^2.0.2",
|
|
34
|
+
"open": "^11.0.0",
|
|
35
|
+
"p-queue": "^9.2.0",
|
|
36
|
+
"pathe": "^2.0.3",
|
|
37
|
+
"slugify": "^1.6.9",
|
|
38
|
+
"smol-toml": "^1.6.1",
|
|
39
|
+
"systeminformation": "^5.31.5",
|
|
40
|
+
"tapable": "^2.3.3",
|
|
41
|
+
"tough-cookie": "^6.0.1",
|
|
42
|
+
"tough-cookie-file-store": "^3.3.0",
|
|
43
|
+
"unzip-stream": "^0.3.4",
|
|
44
|
+
"webview-bun": "^2.4.0",
|
|
45
|
+
"zod": "^4.4.3"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"gameflow",
|
|
49
|
+
"sdk"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2024"
|
|
7
|
+
],
|
|
8
|
+
"module": "ESNext",
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"emitDeclarationOnly": true,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"strict": true,
|
|
17
|
+
"outDir": "../../dist-sdk",
|
|
18
|
+
"types": [
|
|
19
|
+
"node"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|