stash-graphql-client 0.0.0-stage → 0.31.2
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/LICENSE +21 -0
- package/README.md +247 -2
- package/dist/client.d.ts +15 -0
- package/dist/client.js +29 -0
- package/dist/generated/roots.d.ts +6 -0
- package/dist/generated/roots.js +281 -0
- package/dist/generated/schema.d.ts +4491 -0
- package/dist/generated/schema.js +0 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +3 -0
- package/dist/request.d.ts +23 -0
- package/dist/request.js +131 -0
- package/dist/transport.d.ts +40 -0
- package/dist/transport.js +140 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.js +0 -0
- package/package.json +54 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shalemore
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,248 @@
|
|
|
1
|
-
#
|
|
1
|
+
# stash-graphql-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/stash-graphql-client)
|
|
4
|
+
[](https://github.com/shalemore/stash-graphql-client/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A fully typed client for the [Stash](https://github.com/stashapp/stash) GraphQL API, without writing GraphQL.
|
|
8
|
+
|
|
9
|
+
> This version of the package is generated from the GraphQL schema of [Stash v0.31.1](https://github.com/stashapp/stash/releases/tag/v0.31.1).
|
|
10
|
+
|
|
11
|
+
- **Typed field selection.** Fields are selected with callbacks, and the result type contains exactly the selected fields.
|
|
12
|
+
- **Generated from Stash's own schema** (the latest release, see [Stash versions](#stash-versions)), so the names match.
|
|
13
|
+
- **Small.** Built on `fetch`, about 6 KB gzipped. The only dependency, `graphql-ws`, is loaded on the first subscription.
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install stash-graphql-client
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createStash } from "stash-graphql-client";
|
|
23
|
+
|
|
24
|
+
const stash = createStash({
|
|
25
|
+
endpoint: "http://localhost:9999/graphql",
|
|
26
|
+
apiKey: process.env.STASH_API_KEY,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Every root field is a method: (arguments, what to select)
|
|
30
|
+
const { count, performers } = await stash.findPerformers(
|
|
31
|
+
{ filter: { per_page: 20, sort: "name", direction: "ASC" } },
|
|
32
|
+
(result) => ({
|
|
33
|
+
...result.$pick("count"),
|
|
34
|
+
performers: result.performers((performer) => performer.$pick("id", "name", "favorite")),
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
// count: number
|
|
38
|
+
// performers: { id: string; name: string; favorite: boolean }[]
|
|
39
|
+
|
|
40
|
+
await stash.findPerformers((result) => result.$pick("cont"));
|
|
41
|
+
// ~~~~~~ unknown field
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Selecting fields
|
|
45
|
+
|
|
46
|
+
`$pick` selects scalar fields by name; an object field is called with its own selection:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const scene = await stash.findScene({ id: "42" }, (found) => ({
|
|
50
|
+
...found.$pick("id", "title"), // title: string | null, same as in the schema
|
|
51
|
+
studio: found.studio((studio) => studio.$pick("id", "name")),
|
|
52
|
+
}));
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A scalar can also be read directly, which selects it under the same name:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const scene = await stash.findScene({ id: "42" }, (found) => ({
|
|
59
|
+
id: found.id,
|
|
60
|
+
title: found.title,
|
|
61
|
+
studio: found.studio((studio) => ({ id: studio.id, name: studio.name })),
|
|
62
|
+
}));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use a different key to rename a field. A field with arguments can be selected more than once under different keys:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const { groups } = await stash.findGroups((result) => ({
|
|
69
|
+
groups: result.groups((group) => ({
|
|
70
|
+
...group.$pick("id"),
|
|
71
|
+
rating: group.rating100,
|
|
72
|
+
directScenes: group.scene_count({ depth: 0 }),
|
|
73
|
+
allScenes: group.scene_count({ depth: -1 }),
|
|
74
|
+
})),
|
|
75
|
+
}));
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For unions and interfaces, use `$on` to pick fields of one type. `__typename` is added automatically, so the result can be narrowed on it:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const image = await stash.findImage({ id: "7" }, (found) => ({
|
|
82
|
+
visual_files: found.visual_files((file) => ({
|
|
83
|
+
...file.$on("ImageFile", (picture) => picture.$pick("path", "width")),
|
|
84
|
+
...file.$on("VideoFile", (video) => video.$pick("path", "duration")),
|
|
85
|
+
})),
|
|
86
|
+
}));
|
|
87
|
+
|
|
88
|
+
for (const file of image?.visual_files ?? []) {
|
|
89
|
+
if (file.__typename === "ImageFile") console.log(file.width);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Enums and input types are exported with the same names as in the schema:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import type { CriterionModifier, SceneFilterType } from "stash-graphql-client";
|
|
97
|
+
|
|
98
|
+
const favorites: SceneFilterType = {
|
|
99
|
+
performer_favorite: true,
|
|
100
|
+
rating100: { value: 80, modifier: "GREATER_THAN" satisfies CriterionModifier },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
await stash.findScenes({ scene_filter: favorites }, (result) => result.$pick("count"));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Reusing selections
|
|
107
|
+
|
|
108
|
+
A selection is a plain function, so it can be shared like a GraphQL fragment. `Fields` and `Result` are types only and have no runtime cost:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import type { Args, Fields, Result } from "stash-graphql-client";
|
|
112
|
+
|
|
113
|
+
const tagFields = (tag: Fields<"Tag">) => tag.$pick("id", "name");
|
|
114
|
+
|
|
115
|
+
export const performerCard = (performer: Fields<"Performer">) => ({
|
|
116
|
+
...performer.$pick("id", "name"),
|
|
117
|
+
image: performer.image_path,
|
|
118
|
+
tags: performer.tags(tagFields),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export type PerformerCard = Result<typeof performerCard>;
|
|
122
|
+
// { id: string; name: string; image: string | null; tags: { id: string; name: string }[] }
|
|
123
|
+
|
|
124
|
+
// Add parameters to make it configurable
|
|
125
|
+
const sceneCard = (scene: Fields<"Scene">, withFiles: boolean) => ({
|
|
126
|
+
...scene.$pick("id"),
|
|
127
|
+
tags: scene.tags(tagFields),
|
|
128
|
+
...(withFiles ? { files: scene.files((file) => file.$pick("path", "size")) } : {}), // files?: ...
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Args is the argument type of a root field, handy for wrapping a call in your own function
|
|
132
|
+
const listScenes = (args: Args<"findScenes">) =>
|
|
133
|
+
stash.findScenes(args, (result) => ({
|
|
134
|
+
...result.$pick("count"),
|
|
135
|
+
scenes: result.scenes((scene) => sceneCard(scene, false)),
|
|
136
|
+
}));
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Callbacks run once, only to build the request. They must return only fields, nested selections and `$on` spreads. Don't `await` or compute anything inside them; do that with the result instead.
|
|
140
|
+
|
|
141
|
+
> [!WARNING]
|
|
142
|
+
> Don't use `...rest` on the callback parameter. It is always empty, so nothing is selected.
|
|
143
|
+
|
|
144
|
+
## Several root fields in one request
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const totals = await stash.query((query) => ({
|
|
148
|
+
scenes: query.findScenes((result) => result.$pick("count")),
|
|
149
|
+
favorites: query.findScenes({ scene_filter: { performer_favorite: true } }, (result) =>
|
|
150
|
+
result.$pick("count"),
|
|
151
|
+
),
|
|
152
|
+
performers: query.findPerformers((result) => result.$pick("count")),
|
|
153
|
+
}));
|
|
154
|
+
|
|
155
|
+
totals.favorites.count; // number
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This sends a single HTTP request, and the keys become aliases. `mutation` works the same way and runs the fields in the order written. A query and a mutation can't share a request, and Stash doesn't accept batched HTTP, so use `Promise.all` to run them concurrently.
|
|
159
|
+
|
|
160
|
+
## Mutations and file uploads
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { openAsBlob } from "node:fs";
|
|
164
|
+
|
|
165
|
+
const updated = await stash.performerUpdate(
|
|
166
|
+
{ input: { id: "3", favorite: true, rating100: 90 } },
|
|
167
|
+
(performer) => performer.$pick("id", "favorite"),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Returns a plain boolean, so there's nothing to select
|
|
171
|
+
const deleted: boolean = await stash.performerDestroy({ input: { id: "3" } });
|
|
172
|
+
|
|
173
|
+
// Pass a Blob or File for uploads: openAsBlob on Node, Bun.file on Bun, or a file input in the browser
|
|
174
|
+
const jobId = await stash.importObjects({
|
|
175
|
+
input: {
|
|
176
|
+
file: await openAsBlob("export.zip"),
|
|
177
|
+
duplicateBehaviour: "IGNORE",
|
|
178
|
+
missingRefBehaviour: "IGNORE",
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Subscriptions
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
// Returns an async iterator; leaving the loop unsubscribes
|
|
187
|
+
const jobs = stash.jobsSubscribe((update) => ({
|
|
188
|
+
...update.$pick("type"),
|
|
189
|
+
job: update.job((job) => job.$pick("id", "progress")),
|
|
190
|
+
}));
|
|
191
|
+
|
|
192
|
+
for await (const update of jobs) {
|
|
193
|
+
console.log(update.type, update.job.progress);
|
|
194
|
+
if (update.type === "REMOVE") break;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Subscriptions go over a WebSocket through [`graphql-ws`](https://github.com/enisdenjo/graphql-ws). The client is created on the first subscription, at the same address as `endpoint` (`http` becomes `ws`, `https` becomes `wss`).
|
|
199
|
+
|
|
200
|
+
- **Authentication.** On Node.js and Bun, `apiKey` and `headers` are sent with the WebSocket handshake too. Browsers can't set headers on a WebSocket, so there Stash has to recognize the session cookie.
|
|
201
|
+
- **Needs a `WebSocket`.** That is global in browsers, on Node.js 22+ and on Bun. On older versions, or to configure reconnecting, pass your own `graphql-ws` client. A custom client must also handle authentication.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { createClient } from "graphql-ws";
|
|
205
|
+
|
|
206
|
+
const stash = createStash({
|
|
207
|
+
endpoint: "http://localhost:9999/graphql",
|
|
208
|
+
subscriptions: createClient({
|
|
209
|
+
url: "ws://localhost:9999/graphql",
|
|
210
|
+
webSocketImpl: WebSocket, // e.g. the `ws` package on older Node.js
|
|
211
|
+
retryAttempts: Infinity,
|
|
212
|
+
}),
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Raw GraphQL and errors
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { StashError } from "stash-graphql-client";
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
// For what the typed API can't express; the result is untyped
|
|
223
|
+
await stash.request(`query ($id: ID!) { scene: findScene(id: $id) { id title } }`, { id: "42" });
|
|
224
|
+
} catch (error) {
|
|
225
|
+
// If part of the request worked, that data is in error.data
|
|
226
|
+
if (error instanceof StashError) console.error(error.status, error.errors);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Options
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
createStash({
|
|
234
|
+
endpoint: "https://stash.example.com/graphql",
|
|
235
|
+
apiKey: "...",
|
|
236
|
+
headers: { "X-Proxy-Token": "..." }, // e.g. for a reverse proxy
|
|
237
|
+
fetch: (url, init) => fetch(url, { ...init, signal: AbortSignal.timeout(10_000) }), // or any fetch-like function
|
|
238
|
+
// subscriptions: your own graphql-ws client, see Subscriptions
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Stash versions
|
|
243
|
+
|
|
244
|
+
Package `0.31.x` tracks the Stash `v0.31` series; patch numbers are independent. `STASH_VERSION` is the Stash release the schema comes from.
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
[MIT](LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type StashOptions } from "./transport.ts";
|
|
2
|
+
import type { Fields, Output, RootMethods, Selection } from "./types.ts";
|
|
3
|
+
/** A client with one method per root field, plus `query`, `mutation` and `request`. */
|
|
4
|
+
export interface StashClient extends RootMethods {
|
|
5
|
+
/**
|
|
6
|
+
* Sends several queries in one request. The keys become the result keys, so the same root
|
|
7
|
+
* field can be selected twice with different arguments.
|
|
8
|
+
*/
|
|
9
|
+
query<S extends Selection>(select: (query: Fields<"Query">) => S): Promise<Output<"Query", S>>;
|
|
10
|
+
/** Sends several mutations in one request; Stash runs them in order. */
|
|
11
|
+
mutation<S extends Selection>(select: (mutation: Fields<"Mutation">) => S): Promise<Output<"Mutation", S>>;
|
|
12
|
+
/** Sends any GraphQL document as is and returns the untyped `data`. */
|
|
13
|
+
request(query: string, variables?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createStash(options: StashOptions): StashClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ROOTS } from "./generated/roots.js";
|
|
2
|
+
import { buildRequest, field, fields } from "./request.js";
|
|
3
|
+
import { createTransport } from "./transport.js";
|
|
4
|
+
export function createStash(options) {
|
|
5
|
+
const transport = createTransport(options);
|
|
6
|
+
// Async, so that errors in selection callbacks reject instead of throwing.
|
|
7
|
+
const send = async (kind, select) => {
|
|
8
|
+
const { request, upload } = buildRequest(kind, select());
|
|
9
|
+
return transport.send(request, upload);
|
|
10
|
+
};
|
|
11
|
+
const operation = (kind) => (select) => send(kind, () => select(fields));
|
|
12
|
+
const methods = Object.fromEntries(Object.entries(ROOTS).map(([name, [kind]]) => {
|
|
13
|
+
const root = (args, select) => ({ [name]: field(name)(args, select) });
|
|
14
|
+
return [
|
|
15
|
+
name,
|
|
16
|
+
kind === "subscription"
|
|
17
|
+
? (args, select) => transport.subscribe(buildRequest(kind, root(args, select)).request, name)
|
|
18
|
+
: async (args, select) => (await send(kind, () => root(args, select)))[name],
|
|
19
|
+
];
|
|
20
|
+
}));
|
|
21
|
+
const client = {
|
|
22
|
+
...methods,
|
|
23
|
+
query: operation("query"),
|
|
24
|
+
mutation: operation("mutation"),
|
|
25
|
+
request: transport.request,
|
|
26
|
+
};
|
|
27
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- one method per entry in ROOTS
|
|
28
|
+
return client;
|
|
29
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Generated by scripts/generate.ts from the schema of Stash v0.31.1. Do not edit.
|
|
2
|
+
export const STASH_VERSION = "v0.31.1";
|
|
3
|
+
export const ROOTS = {
|
|
4
|
+
findSavedFilter: ["query", { id: "ID!" }],
|
|
5
|
+
findSavedFilters: ["query", { mode: "FilterMode" }],
|
|
6
|
+
findDefaultFilter: ["query", { mode: "FilterMode!" }],
|
|
7
|
+
findFile: ["query", { id: "ID", path: "String" }],
|
|
8
|
+
findFiles: ["query", { file_filter: "FileFilterType", filter: "FindFilterType", ids: "[ID!]" }],
|
|
9
|
+
findFolder: ["query", { id: "ID", path: "String" }],
|
|
10
|
+
findFolders: [
|
|
11
|
+
"query",
|
|
12
|
+
{ folder_filter: "FolderFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
13
|
+
],
|
|
14
|
+
findScene: ["query", { id: "ID", checksum: "String" }],
|
|
15
|
+
findSceneByHash: ["query", { input: "SceneHashInput!" }],
|
|
16
|
+
findScenes: [
|
|
17
|
+
"query",
|
|
18
|
+
{
|
|
19
|
+
scene_filter: "SceneFilterType",
|
|
20
|
+
scene_ids: "[Int!]",
|
|
21
|
+
ids: "[ID!]",
|
|
22
|
+
filter: "FindFilterType",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
findScenesByPathRegex: ["query", { filter: "FindFilterType" }],
|
|
26
|
+
findDuplicateScenes: ["query", { distance: "Int", duration_diff: "Float" }],
|
|
27
|
+
sceneStreams: ["query", { id: "ID" }],
|
|
28
|
+
parseSceneFilenames: ["query", { filter: "FindFilterType", config: "SceneParserInput!" }],
|
|
29
|
+
findSceneMarkers: [
|
|
30
|
+
"query",
|
|
31
|
+
{ scene_marker_filter: "SceneMarkerFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
32
|
+
],
|
|
33
|
+
findImage: ["query", { id: "ID", checksum: "String" }],
|
|
34
|
+
findImages: [
|
|
35
|
+
"query",
|
|
36
|
+
{
|
|
37
|
+
image_filter: "ImageFilterType",
|
|
38
|
+
image_ids: "[Int!]",
|
|
39
|
+
ids: "[ID!]",
|
|
40
|
+
filter: "FindFilterType",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
findPerformer: ["query", { id: "ID!" }],
|
|
44
|
+
findPerformers: [
|
|
45
|
+
"query",
|
|
46
|
+
{
|
|
47
|
+
performer_filter: "PerformerFilterType",
|
|
48
|
+
filter: "FindFilterType",
|
|
49
|
+
performer_ids: "[Int!]",
|
|
50
|
+
ids: "[ID!]",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
findStudio: ["query", { id: "ID!" }],
|
|
54
|
+
findStudios: [
|
|
55
|
+
"query",
|
|
56
|
+
{ studio_filter: "StudioFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
57
|
+
],
|
|
58
|
+
findMovie: ["query", { id: "ID!" }],
|
|
59
|
+
findMovies: [
|
|
60
|
+
"query",
|
|
61
|
+
{ movie_filter: "MovieFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
62
|
+
],
|
|
63
|
+
findGroup: ["query", { id: "ID!" }],
|
|
64
|
+
findGroups: [
|
|
65
|
+
"query",
|
|
66
|
+
{ group_filter: "GroupFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
67
|
+
],
|
|
68
|
+
findGallery: ["query", { id: "ID!" }],
|
|
69
|
+
findGalleries: [
|
|
70
|
+
"query",
|
|
71
|
+
{ gallery_filter: "GalleryFilterType", filter: "FindFilterType", ids: "[ID!]" },
|
|
72
|
+
],
|
|
73
|
+
findTag: ["query", { id: "ID!" }],
|
|
74
|
+
findTags: ["query", { tag_filter: "TagFilterType", filter: "FindFilterType", ids: "[ID!]" }],
|
|
75
|
+
markerWall: ["query", { q: "String" }],
|
|
76
|
+
sceneWall: ["query", { q: "String" }],
|
|
77
|
+
markerStrings: ["query", { q: "String", sort: "String" }],
|
|
78
|
+
stats: ["query", {}],
|
|
79
|
+
sceneMarkerTags: ["query", { scene_id: "ID!" }],
|
|
80
|
+
logs: ["query", {}],
|
|
81
|
+
listScrapers: ["query", { types: "[ScrapeContentType!]!" }],
|
|
82
|
+
scrapeSingleScene: ["query", { source: "ScraperSourceInput!", input: "ScrapeSingleSceneInput!" }],
|
|
83
|
+
scrapeMultiScenes: ["query", { source: "ScraperSourceInput!", input: "ScrapeMultiScenesInput!" }],
|
|
84
|
+
scrapeSingleStudio: [
|
|
85
|
+
"query",
|
|
86
|
+
{ source: "ScraperSourceInput!", input: "ScrapeSingleStudioInput!" },
|
|
87
|
+
],
|
|
88
|
+
scrapeSingleTag: ["query", { source: "ScraperSourceInput!", input: "ScrapeSingleTagInput!" }],
|
|
89
|
+
scrapeSinglePerformer: [
|
|
90
|
+
"query",
|
|
91
|
+
{ source: "ScraperSourceInput!", input: "ScrapeSinglePerformerInput!" },
|
|
92
|
+
],
|
|
93
|
+
scrapeMultiPerformers: [
|
|
94
|
+
"query",
|
|
95
|
+
{ source: "ScraperSourceInput!", input: "ScrapeMultiPerformersInput!" },
|
|
96
|
+
],
|
|
97
|
+
scrapeSingleGallery: [
|
|
98
|
+
"query",
|
|
99
|
+
{ source: "ScraperSourceInput!", input: "ScrapeSingleGalleryInput!" },
|
|
100
|
+
],
|
|
101
|
+
scrapeSingleMovie: ["query", { source: "ScraperSourceInput!", input: "ScrapeSingleMovieInput!" }],
|
|
102
|
+
scrapeSingleGroup: ["query", { source: "ScraperSourceInput!", input: "ScrapeSingleGroupInput!" }],
|
|
103
|
+
scrapeSingleImage: ["query", { source: "ScraperSourceInput!", input: "ScrapeSingleImageInput!" }],
|
|
104
|
+
scrapeURL: ["query", { url: "String!", ty: "ScrapeContentType!" }],
|
|
105
|
+
scrapePerformerURL: ["query", { url: "String!" }],
|
|
106
|
+
scrapeSceneURL: ["query", { url: "String!" }],
|
|
107
|
+
scrapeGalleryURL: ["query", { url: "String!" }],
|
|
108
|
+
scrapeImageURL: ["query", { url: "String!" }],
|
|
109
|
+
scrapeMovieURL: ["query", { url: "String!" }],
|
|
110
|
+
scrapeGroupURL: ["query", { url: "String!" }],
|
|
111
|
+
plugins: ["query", {}],
|
|
112
|
+
pluginTasks: ["query", {}],
|
|
113
|
+
installedPackages: ["query", { type: "PackageType!" }],
|
|
114
|
+
availablePackages: ["query", { type: "PackageType!", source: "String!" }],
|
|
115
|
+
configuration: ["query", {}],
|
|
116
|
+
directory: ["query", { path: "String", locale: "String" }],
|
|
117
|
+
validateStashBoxCredentials: ["query", { input: "StashBoxInput!" }],
|
|
118
|
+
systemStatus: ["query", {}],
|
|
119
|
+
jobQueue: ["query", {}],
|
|
120
|
+
findJob: ["query", { input: "FindJobInput!" }],
|
|
121
|
+
dlnaStatus: ["query", {}],
|
|
122
|
+
allScenes: ["query", {}],
|
|
123
|
+
allSceneMarkers: ["query", {}],
|
|
124
|
+
allImages: ["query", {}],
|
|
125
|
+
allGalleries: ["query", {}],
|
|
126
|
+
allPerformers: ["query", {}],
|
|
127
|
+
allTags: ["query", {}],
|
|
128
|
+
allStudios: ["query", {}],
|
|
129
|
+
allMovies: ["query", {}],
|
|
130
|
+
version: ["query", {}],
|
|
131
|
+
latestversion: ["query", {}],
|
|
132
|
+
setup: ["mutation", { input: "SetupInput!" }],
|
|
133
|
+
migrate: ["mutation", { input: "MigrateInput!" }],
|
|
134
|
+
downloadFFMpeg: ["mutation", {}],
|
|
135
|
+
sceneCreate: ["mutation", { input: "SceneCreateInput!" }],
|
|
136
|
+
sceneUpdate: ["mutation", { input: "SceneUpdateInput!" }],
|
|
137
|
+
sceneMerge: ["mutation", { input: "SceneMergeInput!" }],
|
|
138
|
+
bulkSceneUpdate: ["mutation", { input: "BulkSceneUpdateInput!" }],
|
|
139
|
+
sceneDestroy: ["mutation", { input: "SceneDestroyInput!" }],
|
|
140
|
+
scenesDestroy: ["mutation", { input: "ScenesDestroyInput!" }],
|
|
141
|
+
scenesUpdate: ["mutation", { input: "[SceneUpdateInput!]!" }],
|
|
142
|
+
sceneIncrementO: ["mutation", { id: "ID!" }],
|
|
143
|
+
sceneDecrementO: ["mutation", { id: "ID!" }],
|
|
144
|
+
sceneAddO: ["mutation", { id: "ID!", times: "[Timestamp!]" }],
|
|
145
|
+
sceneDeleteO: ["mutation", { id: "ID!", times: "[Timestamp!]" }],
|
|
146
|
+
sceneResetO: ["mutation", { id: "ID!" }],
|
|
147
|
+
sceneSaveActivity: ["mutation", { id: "ID!", resume_time: "Float", playDuration: "Float" }],
|
|
148
|
+
sceneResetActivity: [
|
|
149
|
+
"mutation",
|
|
150
|
+
{ id: "ID!", reset_resume: "Boolean", reset_duration: "Boolean" },
|
|
151
|
+
],
|
|
152
|
+
sceneIncrementPlayCount: ["mutation", { id: "ID!" }],
|
|
153
|
+
sceneAddPlay: ["mutation", { id: "ID!", times: "[Timestamp!]" }],
|
|
154
|
+
sceneDeletePlay: ["mutation", { id: "ID!", times: "[Timestamp!]" }],
|
|
155
|
+
sceneResetPlayCount: ["mutation", { id: "ID!" }],
|
|
156
|
+
sceneGenerateScreenshot: ["mutation", { id: "ID!", at: "Float" }],
|
|
157
|
+
sceneMarkerCreate: ["mutation", { input: "SceneMarkerCreateInput!" }],
|
|
158
|
+
sceneMarkerUpdate: ["mutation", { input: "SceneMarkerUpdateInput!" }],
|
|
159
|
+
bulkSceneMarkerUpdate: ["mutation", { input: "BulkSceneMarkerUpdateInput!" }],
|
|
160
|
+
sceneMarkerDestroy: ["mutation", { id: "ID!" }],
|
|
161
|
+
sceneMarkersDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
162
|
+
sceneAssignFile: ["mutation", { input: "AssignSceneFileInput!" }],
|
|
163
|
+
imageUpdate: ["mutation", { input: "ImageUpdateInput!" }],
|
|
164
|
+
bulkImageUpdate: ["mutation", { input: "BulkImageUpdateInput!" }],
|
|
165
|
+
imageDestroy: ["mutation", { input: "ImageDestroyInput!" }],
|
|
166
|
+
imagesDestroy: ["mutation", { input: "ImagesDestroyInput!" }],
|
|
167
|
+
imagesUpdate: ["mutation", { input: "[ImageUpdateInput!]!" }],
|
|
168
|
+
imageIncrementO: ["mutation", { id: "ID!" }],
|
|
169
|
+
imageDecrementO: ["mutation", { id: "ID!" }],
|
|
170
|
+
imageResetO: ["mutation", { id: "ID!" }],
|
|
171
|
+
galleryCreate: ["mutation", { input: "GalleryCreateInput!" }],
|
|
172
|
+
galleryUpdate: ["mutation", { input: "GalleryUpdateInput!" }],
|
|
173
|
+
bulkGalleryUpdate: ["mutation", { input: "BulkGalleryUpdateInput!" }],
|
|
174
|
+
galleryDestroy: ["mutation", { input: "GalleryDestroyInput!" }],
|
|
175
|
+
galleriesUpdate: ["mutation", { input: "[GalleryUpdateInput!]!" }],
|
|
176
|
+
addGalleryImages: ["mutation", { input: "GalleryAddInput!" }],
|
|
177
|
+
removeGalleryImages: ["mutation", { input: "GalleryRemoveInput!" }],
|
|
178
|
+
setGalleryCover: ["mutation", { input: "GallerySetCoverInput!" }],
|
|
179
|
+
resetGalleryCover: ["mutation", { input: "GalleryResetCoverInput!" }],
|
|
180
|
+
galleryChapterCreate: ["mutation", { input: "GalleryChapterCreateInput!" }],
|
|
181
|
+
galleryChapterUpdate: ["mutation", { input: "GalleryChapterUpdateInput!" }],
|
|
182
|
+
galleryChapterDestroy: ["mutation", { id: "ID!" }],
|
|
183
|
+
performerCreate: ["mutation", { input: "PerformerCreateInput!" }],
|
|
184
|
+
performerUpdate: ["mutation", { input: "PerformerUpdateInput!" }],
|
|
185
|
+
performerDestroy: ["mutation", { input: "PerformerDestroyInput!" }],
|
|
186
|
+
performersDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
187
|
+
bulkPerformerUpdate: ["mutation", { input: "BulkPerformerUpdateInput!" }],
|
|
188
|
+
performerMerge: ["mutation", { input: "PerformerMergeInput!" }],
|
|
189
|
+
studioCreate: ["mutation", { input: "StudioCreateInput!" }],
|
|
190
|
+
studioUpdate: ["mutation", { input: "StudioUpdateInput!" }],
|
|
191
|
+
studioDestroy: ["mutation", { input: "StudioDestroyInput!" }],
|
|
192
|
+
studiosDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
193
|
+
bulkStudioUpdate: ["mutation", { input: "BulkStudioUpdateInput!" }],
|
|
194
|
+
movieCreate: ["mutation", { input: "MovieCreateInput!" }],
|
|
195
|
+
movieUpdate: ["mutation", { input: "MovieUpdateInput!" }],
|
|
196
|
+
movieDestroy: ["mutation", { input: "MovieDestroyInput!" }],
|
|
197
|
+
moviesDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
198
|
+
bulkMovieUpdate: ["mutation", { input: "BulkMovieUpdateInput!" }],
|
|
199
|
+
groupCreate: ["mutation", { input: "GroupCreateInput!" }],
|
|
200
|
+
groupUpdate: ["mutation", { input: "GroupUpdateInput!" }],
|
|
201
|
+
groupDestroy: ["mutation", { input: "GroupDestroyInput!" }],
|
|
202
|
+
groupsDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
203
|
+
bulkGroupUpdate: ["mutation", { input: "BulkGroupUpdateInput!" }],
|
|
204
|
+
addGroupSubGroups: ["mutation", { input: "GroupSubGroupAddInput!" }],
|
|
205
|
+
removeGroupSubGroups: ["mutation", { input: "GroupSubGroupRemoveInput!" }],
|
|
206
|
+
reorderSubGroups: ["mutation", { input: "ReorderSubGroupsInput!" }],
|
|
207
|
+
tagCreate: ["mutation", { input: "TagCreateInput!" }],
|
|
208
|
+
tagUpdate: ["mutation", { input: "TagUpdateInput!" }],
|
|
209
|
+
tagDestroy: ["mutation", { input: "TagDestroyInput!" }],
|
|
210
|
+
tagsDestroy: ["mutation", { ids: "[ID!]!" }],
|
|
211
|
+
tagsMerge: ["mutation", { input: "TagsMergeInput!" }],
|
|
212
|
+
bulkTagUpdate: ["mutation", { input: "BulkTagUpdateInput!" }],
|
|
213
|
+
moveFiles: ["mutation", { input: "MoveFilesInput!" }],
|
|
214
|
+
deleteFiles: ["mutation", { ids: "[ID!]!" }],
|
|
215
|
+
destroyFiles: ["mutation", { ids: "[ID!]!" }],
|
|
216
|
+
fileSetFingerprints: ["mutation", { input: "FileSetFingerprintsInput!" }],
|
|
217
|
+
revealFileInFileManager: ["mutation", { id: "ID!" }],
|
|
218
|
+
revealFolderInFileManager: ["mutation", { id: "ID!" }],
|
|
219
|
+
saveFilter: ["mutation", { input: "SaveFilterInput!" }],
|
|
220
|
+
destroySavedFilter: ["mutation", { input: "DestroyFilterInput!" }],
|
|
221
|
+
setDefaultFilter: ["mutation", { input: "SetDefaultFilterInput!" }],
|
|
222
|
+
configureGeneral: ["mutation", { input: "ConfigGeneralInput!" }],
|
|
223
|
+
configureInterface: ["mutation", { input: "ConfigInterfaceInput!" }],
|
|
224
|
+
configureDLNA: ["mutation", { input: "ConfigDLNAInput!" }],
|
|
225
|
+
configureScraping: ["mutation", { input: "ConfigScrapingInput!" }],
|
|
226
|
+
configureDefaults: ["mutation", { input: "ConfigDefaultSettingsInput!" }],
|
|
227
|
+
configurePlugin: ["mutation", { plugin_id: "ID!", input: "Map!" }],
|
|
228
|
+
configureUI: ["mutation", { input: "Map", partial: "Map" }],
|
|
229
|
+
configureUISetting: ["mutation", { key: "String!", value: "Any" }],
|
|
230
|
+
generateAPIKey: ["mutation", { input: "GenerateAPIKeyInput!" }],
|
|
231
|
+
exportObjects: ["mutation", { input: "ExportObjectsInput!" }],
|
|
232
|
+
importObjects: ["mutation", { input: "ImportObjectsInput!" }, true],
|
|
233
|
+
metadataImport: ["mutation", {}],
|
|
234
|
+
metadataExport: ["mutation", {}],
|
|
235
|
+
metadataScan: ["mutation", { input: "ScanMetadataInput!" }],
|
|
236
|
+
metadataGenerate: ["mutation", { input: "GenerateMetadataInput!" }],
|
|
237
|
+
metadataAutoTag: ["mutation", { input: "AutoTagMetadataInput!" }],
|
|
238
|
+
metadataClean: ["mutation", { input: "CleanMetadataInput!" }],
|
|
239
|
+
metadataCleanGenerated: ["mutation", { input: "CleanGeneratedInput!" }],
|
|
240
|
+
metadataIdentify: ["mutation", { input: "IdentifyMetadataInput!" }],
|
|
241
|
+
migrateHashNaming: ["mutation", {}],
|
|
242
|
+
migrateSceneScreenshots: ["mutation", { input: "MigrateSceneScreenshotsInput!" }],
|
|
243
|
+
migrateBlobs: ["mutation", { input: "MigrateBlobsInput!" }],
|
|
244
|
+
anonymiseDatabase: ["mutation", { input: "AnonymiseDatabaseInput!" }],
|
|
245
|
+
optimiseDatabase: ["mutation", {}],
|
|
246
|
+
reloadScrapers: ["mutation", {}],
|
|
247
|
+
setPluginsEnabled: ["mutation", { enabledMap: "BoolMap!" }],
|
|
248
|
+
runPluginTask: [
|
|
249
|
+
"mutation",
|
|
250
|
+
{
|
|
251
|
+
plugin_id: "ID!",
|
|
252
|
+
task_name: "String",
|
|
253
|
+
description: "String",
|
|
254
|
+
args: "[PluginArgInput!]",
|
|
255
|
+
args_map: "Map",
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
runPluginOperation: ["mutation", { plugin_id: "ID!", args: "Map" }],
|
|
259
|
+
reloadPlugins: ["mutation", {}],
|
|
260
|
+
installPackages: ["mutation", { type: "PackageType!", packages: "[PackageSpecInput!]!" }],
|
|
261
|
+
updatePackages: ["mutation", { type: "PackageType!", packages: "[PackageSpecInput!]" }],
|
|
262
|
+
uninstallPackages: ["mutation", { type: "PackageType!", packages: "[PackageSpecInput!]!" }],
|
|
263
|
+
stopJob: ["mutation", { job_id: "ID!" }],
|
|
264
|
+
stopAllJobs: ["mutation", {}],
|
|
265
|
+
submitStashBoxFingerprints: ["mutation", { input: "StashBoxFingerprintSubmissionInput!" }],
|
|
266
|
+
submitStashBoxSceneDraft: ["mutation", { input: "StashBoxDraftSubmissionInput!" }],
|
|
267
|
+
submitStashBoxPerformerDraft: ["mutation", { input: "StashBoxDraftSubmissionInput!" }],
|
|
268
|
+
backupDatabase: ["mutation", { input: "BackupDatabaseInput!" }],
|
|
269
|
+
querySQL: ["mutation", { sql: "String!", args: "[Any]" }],
|
|
270
|
+
execSQL: ["mutation", { sql: "String!", args: "[Any]" }],
|
|
271
|
+
stashBoxBatchPerformerTag: ["mutation", { input: "StashBoxBatchTagInput!" }],
|
|
272
|
+
stashBoxBatchStudioTag: ["mutation", { input: "StashBoxBatchTagInput!" }],
|
|
273
|
+
stashBoxBatchTagTag: ["mutation", { input: "StashBoxBatchTagInput!" }],
|
|
274
|
+
enableDLNA: ["mutation", { input: "EnableDLNAInput!" }],
|
|
275
|
+
disableDLNA: ["mutation", { input: "DisableDLNAInput!" }],
|
|
276
|
+
addTempDLNAIP: ["mutation", { input: "AddTempDLNAIPInput!" }],
|
|
277
|
+
removeTempDLNAIP: ["mutation", { input: "RemoveTempDLNAIPInput!" }],
|
|
278
|
+
jobsSubscribe: ["subscription", {}],
|
|
279
|
+
loggingSubscribe: ["subscription", {}],
|
|
280
|
+
scanCompleteSubscribe: ["subscription", {}],
|
|
281
|
+
};
|