@crowdedkingdomstudios/crowdyjs 5.1.0 → 5.2.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/MIGRATION.md +64 -0
- package/README.md +19 -0
- package/dist/client.d.ts +98 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -5
- package/dist/crowdy-client.d.ts +31 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +8 -0
- package/dist/domains/actors.d.ts +88 -5
- package/dist/domains/actors.d.ts.map +1 -1
- package/dist/domains/actors.js +89 -6
- package/dist/domains/apps.d.ts +95 -41
- package/dist/domains/apps.d.ts.map +1 -1
- package/dist/domains/apps.js +80 -33
- package/dist/domains/auth.d.ts +139 -19
- package/dist/domains/auth.d.ts.map +1 -1
- package/dist/domains/auth.js +137 -17
- package/dist/domains/channels.d.ts +264 -5
- package/dist/domains/channels.d.ts.map +1 -1
- package/dist/domains/channels.js +264 -5
- package/dist/domains/chunks.d.ts +116 -3
- package/dist/domains/chunks.d.ts.map +1 -1
- package/dist/domains/chunks.js +116 -3
- package/dist/domains/gameModel.d.ts +412 -6
- package/dist/domains/gameModel.d.ts.map +1 -1
- package/dist/domains/gameModel.js +412 -6
- package/dist/domains/platform.d.ts +36 -20
- package/dist/domains/platform.d.ts.map +1 -1
- package/dist/domains/platform.js +29 -18
- package/dist/domains/serverStatus.d.ts +74 -6
- package/dist/domains/serverStatus.d.ts.map +1 -1
- package/dist/domains/serverStatus.js +74 -6
- package/dist/domains/state.d.ts +50 -2
- package/dist/domains/state.d.ts.map +1 -1
- package/dist/domains/state.js +50 -2
- package/dist/domains/teams.d.ts +265 -7
- package/dist/domains/teams.d.ts.map +1 -1
- package/dist/domains/teams.js +267 -9
- package/dist/domains/teleport.d.ts +30 -2
- package/dist/domains/teleport.d.ts.map +1 -1
- package/dist/domains/teleport.js +30 -2
- package/dist/domains/udp.d.ts +341 -5
- package/dist/domains/udp.d.ts.map +1 -1
- package/dist/domains/udp.js +341 -5
- package/dist/domains/users.d.ts +42 -11
- package/dist/domains/users.d.ts.map +1 -1
- package/dist/domains/users.js +41 -10
- package/dist/domains/voxels.d.ts +107 -2
- package/dist/domains/voxels.d.ts.map +1 -1
- package/dist/domains/voxels.js +107 -2
- package/dist/errors.d.ts +116 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +100 -0
- package/dist/generated/graphql.d.ts +1787 -110
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +75 -9
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/realtime.d.ts +226 -0
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +90 -0
- package/dist/session.d.ts +46 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +35 -0
- package/dist/types.d.ts +429 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +53 -0
- package/dist/utils.d.ts +86 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +86 -0
- package/dist/world.d.ts +192 -0
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +170 -0
- package/package.json +1 -1
package/dist/domains/voxels.d.ts
CHANGED
|
@@ -1,17 +1,122 @@
|
|
|
1
1
|
import type { GraphQLClient } from '../client.js';
|
|
2
2
|
import { type ListVoxelsQuery, type ListVoxelsQueryVariables, type ListVoxelUpdatesByDistanceQuery, type ListVoxelUpdatesByDistanceQueryVariables, type UpdateVoxelMutation, type UpdateVoxelMutationVariables, type VoxelUpdateHistoryQuery, type VoxelUpdateHistoryQueryVariables, type RollbackVoxelUpdatesMutation, type RollbackVoxelUpdatesMutationVariables } from '../generated/graphql.js';
|
|
3
3
|
/**
|
|
4
|
-
* Voxel queries and mutations
|
|
4
|
+
* Voxel-edit queries and mutations for an app's world on the **game-api**: list,
|
|
5
|
+
* distance scans, history, rollback, and single-voxel writes. Exposed as
|
|
6
|
+
* `client.voxels`.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
8
|
+
* A "voxel edit" is one row of the `voxel_updates` log (a {@link Voxel}): the
|
|
9
|
+
* app / chunk / local position that changed, the new voxel type, an optional
|
|
10
|
+
* base64 state blob, and who/when. A background maintenance job later folds these
|
|
11
|
+
* edits into the chunk's packed grid (see {@link ChunksAPI}). For high-frequency
|
|
12
|
+
* realtime edits prefer the UDP path (`client.udp.sendVoxelUpdate(...)`); use
|
|
13
|
+
* this API for authoritative reads, audit history, and administrative rollback.
|
|
14
|
+
*
|
|
15
|
+
* Coordinate & encoding conventions:
|
|
16
|
+
* - **Chunk coordinates** are int64 **decimal strings**; **voxel positions**
|
|
17
|
+
* (`location`) are signed 16-bit ints, `0-15` per axis for in-bounds voxels.
|
|
18
|
+
* - `appId` / `userId` are `BigInt` sent and received as decimal strings.
|
|
19
|
+
* - Voxel `state` blobs are **base64-encoded** binary.
|
|
20
|
+
*
|
|
21
|
+
* Every method requires an authenticated session (a Bearer token set via
|
|
22
|
+
* `client.auth.login()` or `client.setToken()`); an app-scoped token may only
|
|
23
|
+
* touch its own app, otherwise {@link CrowdyGraphQLError} is thrown
|
|
24
|
+
* (`UNAUTHENTICATED` / `FORBIDDEN`). {@link VoxelsAPI.update} additionally
|
|
25
|
+
* requires the `update_voxel_data` runtime permission and
|
|
26
|
+
* {@link VoxelsAPI.rollback} the `manage_apps` permission
|
|
27
|
+
* (`SCOPE_MISSING` / `FORBIDDEN`).
|
|
7
28
|
*/
|
|
8
29
|
export declare class VoxelsAPI {
|
|
9
30
|
private gql;
|
|
10
31
|
constructor(gql: GraphQLClient);
|
|
32
|
+
/**
|
|
33
|
+
* List recorded voxel edits for a single chunk, newest first (optionally only
|
|
34
|
+
* those at/after a timestamp). Read-only.
|
|
35
|
+
*
|
|
36
|
+
* @param input - {@link ListVoxelsInput}: `appId`, chunk `coordinates`, and an
|
|
37
|
+
* optional inclusive `since` lower time bound (only edits with
|
|
38
|
+
* `createdAt >= since`).
|
|
39
|
+
* @returns The matching {@link Voxel} edits, newest first (each `state` blob
|
|
40
|
+
* base64-encoded).
|
|
41
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
|
|
42
|
+
*/
|
|
11
43
|
list(input: ListVoxelsQueryVariables['input']): Promise<ListVoxelsQuery['listVoxels']>;
|
|
44
|
+
/**
|
|
45
|
+
* List recorded voxel edits for all chunks within a cubic (Chebyshev) radius of
|
|
46
|
+
* a center chunk, grouped per chunk and ordered by increasing distance,
|
|
47
|
+
* paginated over chunks. Read-only.
|
|
48
|
+
*
|
|
49
|
+
* @param input - {@link ListVoxelUpdatesByDistanceInput}: `appId`,
|
|
50
|
+
* `centerCoordinate`, `maxDistance` (in chunk units, integer `1-8`), optional
|
|
51
|
+
* `limit` (max **chunks**, not voxels — default 1000) / `skip` (default 0),
|
|
52
|
+
* and an optional `since` lower time bound.
|
|
53
|
+
* @returns A {@link VoxelUpdatesByDistanceResponse}: per-chunk groups of voxel
|
|
54
|
+
* edits ordered by increasing distance from `centerCoordinate`, plus an echo
|
|
55
|
+
* of the applied `limit`/`skip`.
|
|
56
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` (e.g. `maxDistance` outside
|
|
57
|
+
* `1-8`), `UNAUTHENTICATED`, or `FORBIDDEN`.
|
|
58
|
+
*/
|
|
12
59
|
listByDistance(input: ListVoxelUpdatesByDistanceQueryVariables['input']): Promise<ListVoxelUpdatesByDistanceQuery['listVoxelUpdatesByDistance']>;
|
|
60
|
+
/**
|
|
61
|
+
* Record (upsert) a single voxel edit in the `voxel_updates` log for one chunk.
|
|
62
|
+
* **Writes world state**; a background job later folds the edit into the
|
|
63
|
+
* chunk's packed grid. Requires voxel-edit permission for the target region:
|
|
64
|
+
* active app access plus the `update_voxel_data` runtime permission (and, where
|
|
65
|
+
* grids cover the chunk, `update_voxel_data` on a covering grid).
|
|
66
|
+
*
|
|
67
|
+
* @param input - {@link UpdateVoxelInput}: `appId`, chunk `coordinates`, the
|
|
68
|
+
* local voxel `location` (`0-15` per axis), the `voxelType` to write
|
|
69
|
+
* (`0-255`), and an optional base64 `state` blob.
|
|
70
|
+
* @returns The resulting {@link Voxel}.
|
|
71
|
+
* @throws {CrowdyGraphQLError} `SCOPE_MISSING` / `FORBIDDEN` (missing
|
|
72
|
+
* `update_voxel_data`), `BAD_USER_INPUT`, or `UNAUTHENTICATED`.
|
|
73
|
+
*/
|
|
13
74
|
update(input: UpdateVoxelMutationVariables['input']): Promise<UpdateVoxelMutation['updateVoxel']>;
|
|
75
|
+
/**
|
|
76
|
+
* Read entries from the immutable voxel edit history (`voxel_updates_history`)
|
|
77
|
+
* for an app, newest first, optionally filtered by user id and a changed-at
|
|
78
|
+
* time window. Read-only.
|
|
79
|
+
*
|
|
80
|
+
* @param args - Query variables:
|
|
81
|
+
* - `appId` — app whose history to read (`BigInt` decimal string).
|
|
82
|
+
* - `userId` — optional filter: only edits made by this user (decimal string).
|
|
83
|
+
* - `from` / `to` — optional inclusive changed-at time window (ISO-8601).
|
|
84
|
+
* - `limit` — **deprecated** max entries (default 500, range `1-50000`).
|
|
85
|
+
* - `offset` — **deprecated** entries to skip (default 0, range `0-1000000`).
|
|
86
|
+
* @returns The matching {@link VoxelUpdateHistoryEvent} entries, newest first.
|
|
87
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
|
|
88
|
+
* @remarks The `limit`/`offset` arguments use deprecated offset pagination.
|
|
89
|
+
* For large histories prefer the Relay-style `voxelUpdateHistoryConnection(first:,
|
|
90
|
+
* after:)` query (available on the schema via `client.graphql`) — page with
|
|
91
|
+
* `first` plus the previous page's `after` cursor. See
|
|
92
|
+
* https://docs.crowdedkingdoms.com/overview/pagination.
|
|
93
|
+
*/
|
|
14
94
|
history(args: VoxelUpdateHistoryQueryVariables): Promise<VoxelUpdateHistoryQuery['voxelUpdateHistory']>;
|
|
95
|
+
/**
|
|
96
|
+
* Revert every voxel edit made by `userId` in `appId` between `from` and `to`,
|
|
97
|
+
* returning one result per affected voxel. **Defaults to a dry run**
|
|
98
|
+
* (`dryRun: true`) that only PREVIEWS the planned reversions without writing;
|
|
99
|
+
* pass `dryRun: false` to actually apply them (**destructive** — mutates world
|
|
100
|
+
* state). Privileged: requires the `manage_apps` permission on the org that
|
|
101
|
+
* owns `appId` (super admins bypass). Requires game-api ≥ v0.10.3.
|
|
102
|
+
*
|
|
103
|
+
* Pass `idempotencyKey` to make retries safe: replaying with the same key and
|
|
104
|
+
* identical input returns the first result instead of re-applying, while the
|
|
105
|
+
* same key with **different** input throws {@link CrowdyGraphQLError} with
|
|
106
|
+
* `code === 'IDEMPOTENCY_CONFLICT'`. Keys expire server-side after 24h. Unlike
|
|
107
|
+
* {@link ActorsAPI.delete}, the key is a **field on the input object**
|
|
108
|
+
* ({@link RollbackVoxelUpdatesInput}), not a separate argument.
|
|
109
|
+
*
|
|
110
|
+
* @param input - {@link RollbackVoxelUpdatesInput}: `appId`, `userId` (decimal
|
|
111
|
+
* strings), the inclusive `from`/`to` window, `dryRun` (default `true`), and
|
|
112
|
+
* an optional `idempotencyKey`.
|
|
113
|
+
* @returns One {@link RollbackVoxelEventResult} per affected voxel; each
|
|
114
|
+
* `applied` flag is `true` only when actually written (always `false` in a
|
|
115
|
+
* dry run).
|
|
116
|
+
* @throws {CrowdyGraphQLError} `IDEMPOTENCY_CONFLICT`, `SCOPE_MISSING` /
|
|
117
|
+
* `FORBIDDEN` (missing `manage_apps`), `BAD_USER_INPUT`, or
|
|
118
|
+
* `UNAUTHENTICATED`.
|
|
119
|
+
*/
|
|
15
120
|
rollback(input: RollbackVoxelUpdatesMutationVariables['input']): Promise<RollbackVoxelUpdatesMutation['rollbackVoxelUpdates']>;
|
|
16
121
|
}
|
|
17
122
|
//# sourceMappingURL=voxels.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voxels.d.ts","sourceRoot":"","sources":["../../src/domains/voxels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAE7B,KAAK,+BAA+B,EACpC,KAAK,wCAAwC,EAE7C,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EAEjC,KAAK,uBAAuB,EAC5B,KAAK,gCAAgC,EAErC,KAAK,4BAA4B,EACjC,KAAK,qCAAqC,EAC3C,MAAM,yBAAyB,CAAC;AAEjC
|
|
1
|
+
{"version":3,"file":"voxels.d.ts","sourceRoot":"","sources":["../../src/domains/voxels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAE7B,KAAK,+BAA+B,EACpC,KAAK,wCAAwC,EAE7C,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EAEjC,KAAK,uBAAuB,EAC5B,KAAK,gCAAgC,EAErC,KAAK,4BAA4B,EACjC,KAAK,qCAAqC,EAC3C,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,aAAa;IAEtC;;;;;;;;;;OAUG;IACG,IAAI,CACR,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,GACvC,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAKzC;;;;;;;;;;;;;;OAcG;IACG,cAAc,CAClB,KAAK,EAAE,wCAAwC,CAAC,OAAO,CAAC,GACvD,OAAO,CAAC,+BAA+B,CAAC,4BAA4B,CAAC,CAAC;IAKzE;;;;;;;;;;;;;OAaG;IACG,MAAM,CACV,KAAK,EAAE,4BAA4B,CAAC,OAAO,CAAC,GAC3C,OAAO,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAK9C;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CACX,IAAI,EAAE,gCAAgC,GACrC,OAAO,CAAC,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;IAKzD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,QAAQ,CACZ,KAAK,EAAE,qCAAqC,CAAC,OAAO,CAAC,GACpD,OAAO,CAAC,4BAA4B,CAAC,sBAAsB,CAAC,CAAC;CAIjE"}
|
package/dist/domains/voxels.js
CHANGED
|
@@ -1,29 +1,134 @@
|
|
|
1
1
|
import { ListVoxelsDocument, ListVoxelUpdatesByDistanceDocument, UpdateVoxelDocument, VoxelUpdateHistoryDocument, RollbackVoxelUpdatesDocument, } from '../generated/graphql.js';
|
|
2
2
|
/**
|
|
3
|
-
* Voxel queries and mutations
|
|
3
|
+
* Voxel-edit queries and mutations for an app's world on the **game-api**: list,
|
|
4
|
+
* distance scans, history, rollback, and single-voxel writes. Exposed as
|
|
5
|
+
* `client.voxels`.
|
|
4
6
|
*
|
|
5
|
-
*
|
|
7
|
+
* A "voxel edit" is one row of the `voxel_updates` log (a {@link Voxel}): the
|
|
8
|
+
* app / chunk / local position that changed, the new voxel type, an optional
|
|
9
|
+
* base64 state blob, and who/when. A background maintenance job later folds these
|
|
10
|
+
* edits into the chunk's packed grid (see {@link ChunksAPI}). For high-frequency
|
|
11
|
+
* realtime edits prefer the UDP path (`client.udp.sendVoxelUpdate(...)`); use
|
|
12
|
+
* this API for authoritative reads, audit history, and administrative rollback.
|
|
13
|
+
*
|
|
14
|
+
* Coordinate & encoding conventions:
|
|
15
|
+
* - **Chunk coordinates** are int64 **decimal strings**; **voxel positions**
|
|
16
|
+
* (`location`) are signed 16-bit ints, `0-15` per axis for in-bounds voxels.
|
|
17
|
+
* - `appId` / `userId` are `BigInt` sent and received as decimal strings.
|
|
18
|
+
* - Voxel `state` blobs are **base64-encoded** binary.
|
|
19
|
+
*
|
|
20
|
+
* Every method requires an authenticated session (a Bearer token set via
|
|
21
|
+
* `client.auth.login()` or `client.setToken()`); an app-scoped token may only
|
|
22
|
+
* touch its own app, otherwise {@link CrowdyGraphQLError} is thrown
|
|
23
|
+
* (`UNAUTHENTICATED` / `FORBIDDEN`). {@link VoxelsAPI.update} additionally
|
|
24
|
+
* requires the `update_voxel_data` runtime permission and
|
|
25
|
+
* {@link VoxelsAPI.rollback} the `manage_apps` permission
|
|
26
|
+
* (`SCOPE_MISSING` / `FORBIDDEN`).
|
|
6
27
|
*/
|
|
7
28
|
export class VoxelsAPI {
|
|
8
29
|
constructor(gql) {
|
|
9
30
|
this.gql = gql;
|
|
10
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* List recorded voxel edits for a single chunk, newest first (optionally only
|
|
34
|
+
* those at/after a timestamp). Read-only.
|
|
35
|
+
*
|
|
36
|
+
* @param input - {@link ListVoxelsInput}: `appId`, chunk `coordinates`, and an
|
|
37
|
+
* optional inclusive `since` lower time bound (only edits with
|
|
38
|
+
* `createdAt >= since`).
|
|
39
|
+
* @returns The matching {@link Voxel} edits, newest first (each `state` blob
|
|
40
|
+
* base64-encoded).
|
|
41
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
|
|
42
|
+
*/
|
|
11
43
|
async list(input) {
|
|
12
44
|
const data = await this.gql.request(ListVoxelsDocument, { input });
|
|
13
45
|
return data.listVoxels;
|
|
14
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* List recorded voxel edits for all chunks within a cubic (Chebyshev) radius of
|
|
49
|
+
* a center chunk, grouped per chunk and ordered by increasing distance,
|
|
50
|
+
* paginated over chunks. Read-only.
|
|
51
|
+
*
|
|
52
|
+
* @param input - {@link ListVoxelUpdatesByDistanceInput}: `appId`,
|
|
53
|
+
* `centerCoordinate`, `maxDistance` (in chunk units, integer `1-8`), optional
|
|
54
|
+
* `limit` (max **chunks**, not voxels — default 1000) / `skip` (default 0),
|
|
55
|
+
* and an optional `since` lower time bound.
|
|
56
|
+
* @returns A {@link VoxelUpdatesByDistanceResponse}: per-chunk groups of voxel
|
|
57
|
+
* edits ordered by increasing distance from `centerCoordinate`, plus an echo
|
|
58
|
+
* of the applied `limit`/`skip`.
|
|
59
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` (e.g. `maxDistance` outside
|
|
60
|
+
* `1-8`), `UNAUTHENTICATED`, or `FORBIDDEN`.
|
|
61
|
+
*/
|
|
15
62
|
async listByDistance(input) {
|
|
16
63
|
const data = await this.gql.request(ListVoxelUpdatesByDistanceDocument, { input });
|
|
17
64
|
return data.listVoxelUpdatesByDistance;
|
|
18
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Record (upsert) a single voxel edit in the `voxel_updates` log for one chunk.
|
|
68
|
+
* **Writes world state**; a background job later folds the edit into the
|
|
69
|
+
* chunk's packed grid. Requires voxel-edit permission for the target region:
|
|
70
|
+
* active app access plus the `update_voxel_data` runtime permission (and, where
|
|
71
|
+
* grids cover the chunk, `update_voxel_data` on a covering grid).
|
|
72
|
+
*
|
|
73
|
+
* @param input - {@link UpdateVoxelInput}: `appId`, chunk `coordinates`, the
|
|
74
|
+
* local voxel `location` (`0-15` per axis), the `voxelType` to write
|
|
75
|
+
* (`0-255`), and an optional base64 `state` blob.
|
|
76
|
+
* @returns The resulting {@link Voxel}.
|
|
77
|
+
* @throws {CrowdyGraphQLError} `SCOPE_MISSING` / `FORBIDDEN` (missing
|
|
78
|
+
* `update_voxel_data`), `BAD_USER_INPUT`, or `UNAUTHENTICATED`.
|
|
79
|
+
*/
|
|
19
80
|
async update(input) {
|
|
20
81
|
const data = await this.gql.request(UpdateVoxelDocument, { input });
|
|
21
82
|
return data.updateVoxel;
|
|
22
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Read entries from the immutable voxel edit history (`voxel_updates_history`)
|
|
86
|
+
* for an app, newest first, optionally filtered by user id and a changed-at
|
|
87
|
+
* time window. Read-only.
|
|
88
|
+
*
|
|
89
|
+
* @param args - Query variables:
|
|
90
|
+
* - `appId` — app whose history to read (`BigInt` decimal string).
|
|
91
|
+
* - `userId` — optional filter: only edits made by this user (decimal string).
|
|
92
|
+
* - `from` / `to` — optional inclusive changed-at time window (ISO-8601).
|
|
93
|
+
* - `limit` — **deprecated** max entries (default 500, range `1-50000`).
|
|
94
|
+
* - `offset` — **deprecated** entries to skip (default 0, range `0-1000000`).
|
|
95
|
+
* @returns The matching {@link VoxelUpdateHistoryEvent} entries, newest first.
|
|
96
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
|
|
97
|
+
* @remarks The `limit`/`offset` arguments use deprecated offset pagination.
|
|
98
|
+
* For large histories prefer the Relay-style `voxelUpdateHistoryConnection(first:,
|
|
99
|
+
* after:)` query (available on the schema via `client.graphql`) — page with
|
|
100
|
+
* `first` plus the previous page's `after` cursor. See
|
|
101
|
+
* https://docs.crowdedkingdoms.com/overview/pagination.
|
|
102
|
+
*/
|
|
23
103
|
async history(args) {
|
|
24
104
|
const data = await this.gql.request(VoxelUpdateHistoryDocument, args);
|
|
25
105
|
return data.voxelUpdateHistory;
|
|
26
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Revert every voxel edit made by `userId` in `appId` between `from` and `to`,
|
|
109
|
+
* returning one result per affected voxel. **Defaults to a dry run**
|
|
110
|
+
* (`dryRun: true`) that only PREVIEWS the planned reversions without writing;
|
|
111
|
+
* pass `dryRun: false` to actually apply them (**destructive** — mutates world
|
|
112
|
+
* state). Privileged: requires the `manage_apps` permission on the org that
|
|
113
|
+
* owns `appId` (super admins bypass). Requires game-api ≥ v0.10.3.
|
|
114
|
+
*
|
|
115
|
+
* Pass `idempotencyKey` to make retries safe: replaying with the same key and
|
|
116
|
+
* identical input returns the first result instead of re-applying, while the
|
|
117
|
+
* same key with **different** input throws {@link CrowdyGraphQLError} with
|
|
118
|
+
* `code === 'IDEMPOTENCY_CONFLICT'`. Keys expire server-side after 24h. Unlike
|
|
119
|
+
* {@link ActorsAPI.delete}, the key is a **field on the input object**
|
|
120
|
+
* ({@link RollbackVoxelUpdatesInput}), not a separate argument.
|
|
121
|
+
*
|
|
122
|
+
* @param input - {@link RollbackVoxelUpdatesInput}: `appId`, `userId` (decimal
|
|
123
|
+
* strings), the inclusive `from`/`to` window, `dryRun` (default `true`), and
|
|
124
|
+
* an optional `idempotencyKey`.
|
|
125
|
+
* @returns One {@link RollbackVoxelEventResult} per affected voxel; each
|
|
126
|
+
* `applied` flag is `true` only when actually written (always `false` in a
|
|
127
|
+
* dry run).
|
|
128
|
+
* @throws {CrowdyGraphQLError} `IDEMPOTENCY_CONFLICT`, `SCOPE_MISSING` /
|
|
129
|
+
* `FORBIDDEN` (missing `manage_apps`), `BAD_USER_INPUT`, or
|
|
130
|
+
* `UNAUTHENTICATED`.
|
|
131
|
+
*/
|
|
27
132
|
async rollback(input) {
|
|
28
133
|
const data = await this.gql.request(RollbackVoxelUpdatesDocument, { input });
|
|
29
134
|
return data.rollbackVoxelUpdates;
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,35 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error classes thrown by CrowdyJS.
|
|
3
|
+
*
|
|
4
|
+
* Every failure the SDK raises is an instance of {@link CrowdyError} (which
|
|
5
|
+
* extends the native `Error`), so you can catch the base class and branch on
|
|
6
|
+
* the concrete subclass with `instanceof`. Transport-level problems
|
|
7
|
+
* (`CrowdyHttpError`, `CrowdyNetworkError`, `CrowdyTimeoutError`) are distinct
|
|
8
|
+
* from API-level problems (`CrowdyGraphQLError`), which lets you retry network
|
|
9
|
+
* blips without retrying a rejected mutation.
|
|
10
|
+
*
|
|
11
|
+
* For API errors prefer branching on the **stable** `extensions.code`
|
|
12
|
+
* (e.g. `UNAUTHENTICATED`, `SCOPE_MISSING`, `FORBIDDEN`, `IDEMPOTENCY_CONFLICT`,
|
|
13
|
+
* `RATE_LIMITED`) rather than the human-readable message — see the
|
|
14
|
+
* [error-code reference](https://docs.crowdedkingdoms.com/overview/error-codes).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { CrowdyGraphQLError, CrowdyTimeoutError } from '@crowdedkingdomstudios/crowdyjs';
|
|
19
|
+
* try {
|
|
20
|
+
* await client.actors.delete(uuid, key);
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (err instanceof CrowdyGraphQLError && err.code === 'IDEMPOTENCY_CONFLICT') {
|
|
23
|
+
* // same key was already used with different arguments — don't retry blindly
|
|
24
|
+
* } else if (err instanceof CrowdyTimeoutError) {
|
|
25
|
+
* // safe to retry with the same idempotency key
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
/** A single GraphQL error entry as returned in a response's `errors[]` array. */
|
|
1
31
|
export interface CrowdyGraphQLErrorPayload {
|
|
32
|
+
/** Human-readable message. Do not branch on this — use {@link extensions}.code. */
|
|
2
33
|
message: string;
|
|
34
|
+
/** Source locations in the operation document, when the server reports them. */
|
|
3
35
|
locations?: readonly unknown[];
|
|
36
|
+
/** Response path to the field that errored (e.g. `['createCheckout']`). */
|
|
4
37
|
path?: readonly (string | number)[];
|
|
38
|
+
/**
|
|
39
|
+
* Server-provided metadata. Carries the stable `code` plus, where applicable,
|
|
40
|
+
* `remediation` (a short hint on how to resolve it) and `requiredPermission`
|
|
41
|
+
* (the scope the caller is missing). See the published error-code reference.
|
|
42
|
+
*/
|
|
5
43
|
extensions?: Record<string, unknown>;
|
|
6
44
|
}
|
|
45
|
+
/** Options accepted by the {@link CrowdyError} base constructor. */
|
|
7
46
|
export interface CrowdyErrorOptions {
|
|
47
|
+
/** Message passed to the native `Error`. */
|
|
8
48
|
message: string;
|
|
49
|
+
/** Underlying cause (an inner error, rejected promise value, etc.). */
|
|
9
50
|
cause?: unknown;
|
|
10
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Base class for every error thrown by the SDK. Catch this to handle any
|
|
54
|
+
* CrowdyJS failure uniformly; `error.name` is set to the concrete subclass
|
|
55
|
+
* name. Prefer `instanceof` checks on the subclasses below for branching.
|
|
56
|
+
*/
|
|
11
57
|
export declare class CrowdyError extends Error {
|
|
58
|
+
/** The underlying cause, if this error wraps another. */
|
|
12
59
|
readonly cause?: unknown;
|
|
13
60
|
constructor(options: CrowdyErrorOptions);
|
|
14
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* A GraphQL endpoint returned a non-2xx HTTP status. This is a transport-level
|
|
64
|
+
* failure (the request never reached resolver execution cleanly) — distinct
|
|
65
|
+
* from {@link CrowdyGraphQLError}, which carries structured `errors[]` from a
|
|
66
|
+
* 200 response. Typical causes: a `401` from an expired token at the gateway,
|
|
67
|
+
* a `413`/`400` malformed request, or a `5xx`.
|
|
68
|
+
*/
|
|
15
69
|
export declare class CrowdyHttpError extends CrowdyError {
|
|
70
|
+
/** HTTP status code of the response. */
|
|
16
71
|
readonly status: number;
|
|
72
|
+
/** Raw response body (often JSON text or an error page). */
|
|
17
73
|
readonly body: string;
|
|
18
74
|
constructor(status: number, body: string);
|
|
19
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The server returned a 200 response whose `errors[]` array was non-empty.
|
|
78
|
+
* This is the SDK's primary API-error type: authentication, authorization,
|
|
79
|
+
* validation, idempotency conflicts, and business-rule rejections all surface
|
|
80
|
+
* here.
|
|
81
|
+
*
|
|
82
|
+
* Branch on {@link code} (the first error's `extensions.code`) — it is a stable
|
|
83
|
+
* contract; the message text is not. The full array is preserved on
|
|
84
|
+
* {@link graphqlErrors} for multi-error responses.
|
|
85
|
+
*/
|
|
20
86
|
export declare class CrowdyGraphQLError extends CrowdyError {
|
|
87
|
+
/** Every GraphQL error entry from the response, in server order. */
|
|
21
88
|
readonly graphqlErrors: CrowdyGraphQLErrorPayload[];
|
|
22
89
|
constructor(errors: CrowdyGraphQLErrorPayload[]);
|
|
90
|
+
/**
|
|
91
|
+
* Stable machine-readable code of the first error (its `extensions.code`),
|
|
92
|
+
* e.g. `'UNAUTHENTICATED'`, `'SCOPE_MISSING'`, `'FORBIDDEN'`,
|
|
93
|
+
* `'IDEMPOTENCY_CONFLICT'`, `'RATE_LIMITED'`, `'BAD_USER_INPUT'`. Returns
|
|
94
|
+
* `undefined` when the server didn't attach a code. Branch on this rather
|
|
95
|
+
* than parsing {@link message}.
|
|
96
|
+
*/
|
|
23
97
|
get code(): unknown;
|
|
98
|
+
/**
|
|
99
|
+
* The `extensions` bag of the first error: may include `remediation` (a hint
|
|
100
|
+
* on how to fix it) and `requiredPermission` (the missing scope for
|
|
101
|
+
* `FORBIDDEN`/`SCOPE_MISSING`).
|
|
102
|
+
*/
|
|
103
|
+
get extensions(): Record<string, unknown> | undefined;
|
|
24
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* A network-level failure before any HTTP response was received: DNS failure,
|
|
107
|
+
* TLS error, connection refused, or an aborted `fetch`. Generally retryable
|
|
108
|
+
* with backoff. The original failure is on {@link CrowdyError.cause}.
|
|
109
|
+
*/
|
|
25
110
|
export declare class CrowdyNetworkError extends CrowdyError {
|
|
26
111
|
constructor(cause: unknown);
|
|
27
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* An HTTP request to a GraphQL endpoint exceeded the configured `timeout`.
|
|
115
|
+
*
|
|
116
|
+
* Note: realtime `...AndWait` echo timeouts do **not** throw this — they reject
|
|
117
|
+
* with {@link CrowdyRealtimeError} (`code === 'UDP_SEQUENCE_TIMEOUT'`). For
|
|
118
|
+
* idempotent operations — or any mutation you passed an `idempotencyKey` — a
|
|
119
|
+
* retry is safe; the server replays the first result.
|
|
120
|
+
*/
|
|
28
121
|
export declare class CrowdyTimeoutError extends CrowdyError {
|
|
29
122
|
constructor(timeoutMs: number);
|
|
30
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* A realtime/WebSocket failure: a subscription couldn't be established, was
|
|
126
|
+
* rejected, or dropped — or an `...AndWait` spatial send didn't receive its
|
|
127
|
+
* matching echo in time.
|
|
128
|
+
*
|
|
129
|
+
* Branch on {@link code}:
|
|
130
|
+
* - `'UDP_SEQUENCE_TIMEOUT'` — an `...AndWait` send timed out (retryable).
|
|
131
|
+
* - `'APP_ID_REQUIRED'` — subscribed without an `appId` (not retryable).
|
|
132
|
+
* - `'AUTH_REQUIRED'` / `'AUTH_CLEARED'` — no/!cleared session token.
|
|
133
|
+
* - `'WEBSOCKET_ERROR'` / `'SUBSCRIPTION_FAILED'` — transport-level drops.
|
|
134
|
+
*
|
|
135
|
+
* When an `...AndWait` send is answered by a server `GenericErrorResponse`,
|
|
136
|
+
* {@link code} carries that server error code instead. Use {@link retryable}
|
|
137
|
+
* to decide whether to reconnect/retry.
|
|
138
|
+
*/
|
|
31
139
|
export declare class CrowdyRealtimeError extends CrowdyError {
|
|
140
|
+
/** Server- or client-assigned reason code, when available. */
|
|
32
141
|
readonly code?: string;
|
|
142
|
+
/** Whether reconnecting is expected to succeed (transient vs. fatal). */
|
|
33
143
|
readonly retryable?: boolean;
|
|
34
144
|
constructor(message: string, options?: {
|
|
35
145
|
code?: string;
|
|
@@ -37,6 +147,12 @@ export declare class CrowdyRealtimeError extends CrowdyError {
|
|
|
37
147
|
cause?: unknown;
|
|
38
148
|
});
|
|
39
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* A server response failed the SDK's structural validation — the payload was
|
|
152
|
+
* shaped unexpectedly (e.g. a missing required field on a notification). Almost
|
|
153
|
+
* always indicates an SDK/server version mismatch; check the server
|
|
154
|
+
* compatibility floor in the README.
|
|
155
|
+
*/
|
|
40
156
|
export declare class CrowdyProtocolError extends CrowdyError {
|
|
41
157
|
}
|
|
42
158
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,kBAAkB;CAKxC;AAED,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAKzC;AAED,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,CAAC,aAAa,EAAE,yBAAyB,EAAE,CAAC;gBAExC,MAAM,EAAE,yBAAyB,EAAE;IAK/C,IAAI,IAAI,IAAI,OAAO,CAElB;CACF;AAED,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,KAAK,EAAE,OAAO;CAG3B;AAED,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,SAAS,EAAE,MAAM;CAG9B;AAED,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAKnG;AAED,qBAAa,mBAAoB,SAAQ,WAAW;CAAG"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,iFAAiF;AACjF,MAAM,WAAW,yBAAyB;IACxC,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,kBAAkB;CAKxC;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAKzC;AAED;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,yBAAyB,EAAE,CAAC;gBAExC,MAAM,EAAE,yBAAyB,EAAE;IAK/C;;;;;;OAMG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IAED;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAEpD;CACF;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,KAAK,EAAE,OAAO;CAG3B;AAED;;;;;;;GAOG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,SAAS,EAAE,MAAM;CAG9B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAKnG;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;CAAG"}
|
package/dist/errors.js
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error classes thrown by CrowdyJS.
|
|
3
|
+
*
|
|
4
|
+
* Every failure the SDK raises is an instance of {@link CrowdyError} (which
|
|
5
|
+
* extends the native `Error`), so you can catch the base class and branch on
|
|
6
|
+
* the concrete subclass with `instanceof`. Transport-level problems
|
|
7
|
+
* (`CrowdyHttpError`, `CrowdyNetworkError`, `CrowdyTimeoutError`) are distinct
|
|
8
|
+
* from API-level problems (`CrowdyGraphQLError`), which lets you retry network
|
|
9
|
+
* blips without retrying a rejected mutation.
|
|
10
|
+
*
|
|
11
|
+
* For API errors prefer branching on the **stable** `extensions.code`
|
|
12
|
+
* (e.g. `UNAUTHENTICATED`, `SCOPE_MISSING`, `FORBIDDEN`, `IDEMPOTENCY_CONFLICT`,
|
|
13
|
+
* `RATE_LIMITED`) rather than the human-readable message — see the
|
|
14
|
+
* [error-code reference](https://docs.crowdedkingdoms.com/overview/error-codes).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { CrowdyGraphQLError, CrowdyTimeoutError } from '@crowdedkingdomstudios/crowdyjs';
|
|
19
|
+
* try {
|
|
20
|
+
* await client.actors.delete(uuid, key);
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (err instanceof CrowdyGraphQLError && err.code === 'IDEMPOTENCY_CONFLICT') {
|
|
23
|
+
* // same key was already used with different arguments — don't retry blindly
|
|
24
|
+
* } else if (err instanceof CrowdyTimeoutError) {
|
|
25
|
+
* // safe to retry with the same idempotency key
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Base class for every error thrown by the SDK. Catch this to handle any
|
|
32
|
+
* CrowdyJS failure uniformly; `error.name` is set to the concrete subclass
|
|
33
|
+
* name. Prefer `instanceof` checks on the subclasses below for branching.
|
|
34
|
+
*/
|
|
1
35
|
export class CrowdyError extends Error {
|
|
2
36
|
constructor(options) {
|
|
3
37
|
super(options.message);
|
|
@@ -5,6 +39,13 @@ export class CrowdyError extends Error {
|
|
|
5
39
|
this.cause = options.cause;
|
|
6
40
|
}
|
|
7
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* A GraphQL endpoint returned a non-2xx HTTP status. This is a transport-level
|
|
44
|
+
* failure (the request never reached resolver execution cleanly) — distinct
|
|
45
|
+
* from {@link CrowdyGraphQLError}, which carries structured `errors[]` from a
|
|
46
|
+
* 200 response. Typical causes: a `401` from an expired token at the gateway,
|
|
47
|
+
* a `413`/`400` malformed request, or a `5xx`.
|
|
48
|
+
*/
|
|
8
49
|
export class CrowdyHttpError extends CrowdyError {
|
|
9
50
|
constructor(status, body) {
|
|
10
51
|
super({ message: `HTTP ${status}: ${body}` });
|
|
@@ -12,25 +53,78 @@ export class CrowdyHttpError extends CrowdyError {
|
|
|
12
53
|
this.body = body;
|
|
13
54
|
}
|
|
14
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The server returned a 200 response whose `errors[]` array was non-empty.
|
|
58
|
+
* This is the SDK's primary API-error type: authentication, authorization,
|
|
59
|
+
* validation, idempotency conflicts, and business-rule rejections all surface
|
|
60
|
+
* here.
|
|
61
|
+
*
|
|
62
|
+
* Branch on {@link code} (the first error's `extensions.code`) — it is a stable
|
|
63
|
+
* contract; the message text is not. The full array is preserved on
|
|
64
|
+
* {@link graphqlErrors} for multi-error responses.
|
|
65
|
+
*/
|
|
15
66
|
export class CrowdyGraphQLError extends CrowdyError {
|
|
16
67
|
constructor(errors) {
|
|
17
68
|
super({ message: errors.map((error) => error.message).join('; ') });
|
|
18
69
|
this.graphqlErrors = errors;
|
|
19
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Stable machine-readable code of the first error (its `extensions.code`),
|
|
73
|
+
* e.g. `'UNAUTHENTICATED'`, `'SCOPE_MISSING'`, `'FORBIDDEN'`,
|
|
74
|
+
* `'IDEMPOTENCY_CONFLICT'`, `'RATE_LIMITED'`, `'BAD_USER_INPUT'`. Returns
|
|
75
|
+
* `undefined` when the server didn't attach a code. Branch on this rather
|
|
76
|
+
* than parsing {@link message}.
|
|
77
|
+
*/
|
|
20
78
|
get code() {
|
|
21
79
|
return this.graphqlErrors[0]?.extensions?.code;
|
|
22
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* The `extensions` bag of the first error: may include `remediation` (a hint
|
|
83
|
+
* on how to fix it) and `requiredPermission` (the missing scope for
|
|
84
|
+
* `FORBIDDEN`/`SCOPE_MISSING`).
|
|
85
|
+
*/
|
|
86
|
+
get extensions() {
|
|
87
|
+
return this.graphqlErrors[0]?.extensions;
|
|
88
|
+
}
|
|
23
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* A network-level failure before any HTTP response was received: DNS failure,
|
|
92
|
+
* TLS error, connection refused, or an aborted `fetch`. Generally retryable
|
|
93
|
+
* with backoff. The original failure is on {@link CrowdyError.cause}.
|
|
94
|
+
*/
|
|
24
95
|
export class CrowdyNetworkError extends CrowdyError {
|
|
25
96
|
constructor(cause) {
|
|
26
97
|
super({ message: `Network error: ${String(cause)}`, cause });
|
|
27
98
|
}
|
|
28
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* An HTTP request to a GraphQL endpoint exceeded the configured `timeout`.
|
|
102
|
+
*
|
|
103
|
+
* Note: realtime `...AndWait` echo timeouts do **not** throw this — they reject
|
|
104
|
+
* with {@link CrowdyRealtimeError} (`code === 'UDP_SEQUENCE_TIMEOUT'`). For
|
|
105
|
+
* idempotent operations — or any mutation you passed an `idempotencyKey` — a
|
|
106
|
+
* retry is safe; the server replays the first result.
|
|
107
|
+
*/
|
|
29
108
|
export class CrowdyTimeoutError extends CrowdyError {
|
|
30
109
|
constructor(timeoutMs) {
|
|
31
110
|
super({ message: `Request timed out after ${timeoutMs}ms` });
|
|
32
111
|
}
|
|
33
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* A realtime/WebSocket failure: a subscription couldn't be established, was
|
|
115
|
+
* rejected, or dropped — or an `...AndWait` spatial send didn't receive its
|
|
116
|
+
* matching echo in time.
|
|
117
|
+
*
|
|
118
|
+
* Branch on {@link code}:
|
|
119
|
+
* - `'UDP_SEQUENCE_TIMEOUT'` — an `...AndWait` send timed out (retryable).
|
|
120
|
+
* - `'APP_ID_REQUIRED'` — subscribed without an `appId` (not retryable).
|
|
121
|
+
* - `'AUTH_REQUIRED'` / `'AUTH_CLEARED'` — no/!cleared session token.
|
|
122
|
+
* - `'WEBSOCKET_ERROR'` / `'SUBSCRIPTION_FAILED'` — transport-level drops.
|
|
123
|
+
*
|
|
124
|
+
* When an `...AndWait` send is answered by a server `GenericErrorResponse`,
|
|
125
|
+
* {@link code} carries that server error code instead. Use {@link retryable}
|
|
126
|
+
* to decide whether to reconnect/retry.
|
|
127
|
+
*/
|
|
34
128
|
export class CrowdyRealtimeError extends CrowdyError {
|
|
35
129
|
constructor(message, options = {}) {
|
|
36
130
|
super({ message, cause: options.cause });
|
|
@@ -38,5 +132,11 @@ export class CrowdyRealtimeError extends CrowdyError {
|
|
|
38
132
|
this.retryable = options.retryable;
|
|
39
133
|
}
|
|
40
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* A server response failed the SDK's structural validation — the payload was
|
|
137
|
+
* shaped unexpectedly (e.g. a missing required field on a notification). Almost
|
|
138
|
+
* always indicates an SDK/server version mismatch; check the server
|
|
139
|
+
* compatibility floor in the README.
|
|
140
|
+
*/
|
|
41
141
|
export class CrowdyProtocolError extends CrowdyError {
|
|
42
142
|
}
|