@crowdedkingdoms/crowdyjs 1.0.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.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/MIGRATION.md +247 -0
  3. package/README.md +303 -0
  4. package/dist/auth-state.d.ts +11 -0
  5. package/dist/auth-state.d.ts.map +1 -0
  6. package/dist/auth-state.js +13 -0
  7. package/dist/client.d.ts +135 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +150 -0
  10. package/dist/crowdy-client.d.ts +182 -0
  11. package/dist/crowdy-client.d.ts.map +1 -0
  12. package/dist/crowdy-client.js +146 -0
  13. package/dist/domains/actors.d.ts +117 -0
  14. package/dist/domains/actors.d.ts.map +1 -0
  15. package/dist/domains/actors.js +140 -0
  16. package/dist/domains/admin.d.ts +61 -0
  17. package/dist/domains/admin.d.ts.map +1 -0
  18. package/dist/domains/admin.js +33 -0
  19. package/dist/domains/appAccess.d.ts +141 -0
  20. package/dist/domains/appAccess.d.ts.map +1 -0
  21. package/dist/domains/appAccess.js +198 -0
  22. package/dist/domains/apps.d.ts +192 -0
  23. package/dist/domains/apps.d.ts.map +1 -0
  24. package/dist/domains/apps.js +217 -0
  25. package/dist/domains/auth.d.ts +163 -0
  26. package/dist/domains/auth.d.ts.map +1 -0
  27. package/dist/domains/auth.js +208 -0
  28. package/dist/domains/avatars.d.ts +94 -0
  29. package/dist/domains/avatars.d.ts.map +1 -0
  30. package/dist/domains/avatars.js +137 -0
  31. package/dist/domains/billing.d.ts +97 -0
  32. package/dist/domains/billing.d.ts.map +1 -0
  33. package/dist/domains/billing.js +131 -0
  34. package/dist/domains/channels.d.ts +293 -0
  35. package/dist/domains/channels.d.ts.map +1 -0
  36. package/dist/domains/channels.js +353 -0
  37. package/dist/domains/chunks.d.ts +133 -0
  38. package/dist/domains/chunks.d.ts.map +1 -0
  39. package/dist/domains/chunks.js +153 -0
  40. package/dist/domains/controlPlane.d.ts +174 -0
  41. package/dist/domains/controlPlane.d.ts.map +1 -0
  42. package/dist/domains/controlPlane.js +252 -0
  43. package/dist/domains/environments.d.ts +155 -0
  44. package/dist/domains/environments.d.ts.map +1 -0
  45. package/dist/domains/environments.js +223 -0
  46. package/dist/domains/gameApps.d.ts +114 -0
  47. package/dist/domains/gameApps.d.ts.map +1 -0
  48. package/dist/domains/gameApps.js +169 -0
  49. package/dist/domains/gameModel.d.ts +668 -0
  50. package/dist/domains/gameModel.d.ts.map +1 -0
  51. package/dist/domains/gameModel.js +816 -0
  52. package/dist/domains/host.d.ts +35 -0
  53. package/dist/domains/host.d.ts.map +1 -0
  54. package/dist/domains/host.js +40 -0
  55. package/dist/domains/organizations.d.ts +179 -0
  56. package/dist/domains/organizations.d.ts.map +1 -0
  57. package/dist/domains/organizations.js +269 -0
  58. package/dist/domains/payments.d.ts +104 -0
  59. package/dist/domains/payments.d.ts.map +1 -0
  60. package/dist/domains/payments.js +129 -0
  61. package/dist/domains/platform.d.ts +49 -0
  62. package/dist/domains/platform.d.ts.map +1 -0
  63. package/dist/domains/platform.js +50 -0
  64. package/dist/domains/quotas.d.ts +62 -0
  65. package/dist/domains/quotas.d.ts.map +1 -0
  66. package/dist/domains/quotas.js +79 -0
  67. package/dist/domains/serverStatus.d.ts +90 -0
  68. package/dist/domains/serverStatus.d.ts.map +1 -0
  69. package/dist/domains/serverStatus.js +104 -0
  70. package/dist/domains/sharedEnvironment.d.ts +133 -0
  71. package/dist/domains/sharedEnvironment.d.ts.map +1 -0
  72. package/dist/domains/sharedEnvironment.js +179 -0
  73. package/dist/domains/state.d.ts +64 -0
  74. package/dist/domains/state.d.ts.map +1 -0
  75. package/dist/domains/state.js +75 -0
  76. package/dist/domains/teams.d.ts +292 -0
  77. package/dist/domains/teams.d.ts.map +1 -0
  78. package/dist/domains/teams.js +352 -0
  79. package/dist/domains/teleport.d.ts +41 -0
  80. package/dist/domains/teleport.d.ts.map +1 -0
  81. package/dist/domains/teleport.js +43 -0
  82. package/dist/domains/udp.d.ts +405 -0
  83. package/dist/domains/udp.d.ts.map +1 -0
  84. package/dist/domains/udp.js +457 -0
  85. package/dist/domains/usage.d.ts +76 -0
  86. package/dist/domains/usage.d.ts.map +1 -0
  87. package/dist/domains/usage.js +110 -0
  88. package/dist/domains/users.d.ts +147 -0
  89. package/dist/domains/users.d.ts.map +1 -0
  90. package/dist/domains/users.js +195 -0
  91. package/dist/domains/voxels.d.ts +136 -0
  92. package/dist/domains/voxels.d.ts.map +1 -0
  93. package/dist/domains/voxels.js +153 -0
  94. package/dist/errors.d.ts +158 -0
  95. package/dist/errors.d.ts.map +1 -0
  96. package/dist/errors.js +142 -0
  97. package/dist/generated/graphql.d.ts +12206 -0
  98. package/dist/generated/graphql.d.ts.map +1 -0
  99. package/dist/generated/graphql.js +474 -0
  100. package/dist/index.d.ts +84 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +85 -0
  103. package/dist/logger.d.ts +8 -0
  104. package/dist/logger.d.ts.map +1 -0
  105. package/dist/logger.js +1 -0
  106. package/dist/realtime.d.ts +319 -0
  107. package/dist/realtime.d.ts.map +1 -0
  108. package/dist/realtime.js +390 -0
  109. package/dist/session.d.ts +73 -0
  110. package/dist/session.d.ts.map +1 -0
  111. package/dist/session.js +96 -0
  112. package/dist/subscriptions.d.ts +2 -0
  113. package/dist/subscriptions.d.ts.map +1 -0
  114. package/dist/subscriptions.js +1 -0
  115. package/dist/types.d.ts +658 -0
  116. package/dist/types.d.ts.map +1 -0
  117. package/dist/types.js +61 -0
  118. package/dist/utils.d.ts +98 -0
  119. package/dist/utils.d.ts.map +1 -0
  120. package/dist/utils.js +136 -0
  121. package/dist/world.d.ts +236 -0
  122. package/dist/world.d.ts.map +1 -0
  123. package/dist/world.js +275 -0
  124. package/package.json +73 -0
@@ -0,0 +1,198 @@
1
+ import { AppAccessTiersDocument, MyAppAccessDocument, AppUserAccessByAppDocument, AppUserAccessConnectionDocument, RuntimePermissionsDocument, AppGrantMemberCandidatesDocument, ClaimFreeAppAccessDocument, GrantMyAppAccessDocument, CreateAccessTierDocument, UpdateAccessTierDocument, ArchiveAccessTierDocument, GrantAppAccessDocument, RevokeAppAccessDocument, } from '../generated/graphql.js';
2
+ /**
3
+ * App access tiers + per-user access grants — exposed as `client.appAccess`
4
+ * (and grouped under `client.admin`).
5
+ *
6
+ * Targets the **management-api**. Tiers define the runtime-permission bundles
7
+ * (`access`, `teleport`, `update_voxel_data`, `use_voice_chat`, ...) a player
8
+ * gets; grants attach a user to a tier. New apps auto-provision an open default
9
+ * tier, so most players need no explicit grant.
10
+ *
11
+ * Reads of the tier catalog ({@link tiers}) are public; {@link myAccess} needs
12
+ * a session; tier admin and grant/revoke require the `manage_access_tiers` app
13
+ * permission. `BigInt` ids are decimal strings.
14
+ *
15
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN` / `SCOPE_MISSING`
16
+ * per the permission notes above.
17
+ */
18
+ export class AppAccessAPI {
19
+ constructor(management) {
20
+ this.management = management;
21
+ }
22
+ /**
23
+ * List the access tiers defined for an app. **Public.**
24
+ *
25
+ * @param appId - Numeric app id (`BigInt` as a decimal string).
26
+ * @returns The app's tiers, ordered.
27
+ */
28
+ async tiers(appId) {
29
+ const data = await this.management.request(AppAccessTiersDocument, {
30
+ appId,
31
+ });
32
+ return data.appAccessTiers;
33
+ }
34
+ /**
35
+ * Return the authenticated caller's access record for an app (which tier they
36
+ * hold and its status), or `null` if they have none.
37
+ *
38
+ * @param appId - Numeric app id.
39
+ * @returns The caller's {@link AppUserAccess}, or `null`.
40
+ */
41
+ async myAccess(appId) {
42
+ const data = await this.management.request(MyAppAccessDocument, { appId });
43
+ return data.myAppAccess;
44
+ }
45
+ /**
46
+ * List the users who hold access to an app (paginated). Requires the
47
+ * `manage_access_tiers` app permission.
48
+ *
49
+ * @param appId - Numeric app id.
50
+ * @param opts - Optional `status` filter and `limit` / `offset` (default
51
+ * limit 50).
52
+ * @returns The matching access records.
53
+ */
54
+ async usersByApp(appId, opts = {}) {
55
+ const data = await this.management.request(AppUserAccessByAppDocument, {
56
+ appId,
57
+ status: opts.status,
58
+ limit: opts.limit,
59
+ offset: opts.offset,
60
+ });
61
+ return data.appUserAccessByApp;
62
+ }
63
+ /**
64
+ * Relay-style cursor pagination over an app's access grants — the preferred
65
+ * alternative to {@link usersByApp}. Page with `first` plus the previous
66
+ * page's `pageInfo.endCursor` as `after`; optional `status` filter. Requires
67
+ * the `manage_access_tiers` app permission. See
68
+ * https://docs.crowdedkingdoms.com/overview/pagination.
69
+ *
70
+ * @param args - `appId` plus optional `status`, `first`, and `after`.
71
+ * @returns An {@link AppUserAccessConnection}.
72
+ */
73
+ async usersByAppConnection(args) {
74
+ const data = await this.management.request(AppUserAccessConnectionDocument, args);
75
+ return data.appUserAccessConnection;
76
+ }
77
+ /**
78
+ * List every valid runtime permission key (e.g. `access`, `teleport`,
79
+ * `update_voxel_data`, `use_voice_chat`) that a tier or grid grant can
80
+ * reference. **Public.**
81
+ *
82
+ * @returns The runtime permission keys.
83
+ */
84
+ async runtimePermissions() {
85
+ const data = await this.management.request(RuntimePermissionsDocument);
86
+ return data.runtimePermissions;
87
+ }
88
+ /**
89
+ * List org members eligible for a manual app-access grant (those without an
90
+ * active grant yet). Requires the `manage_access_tiers` app permission. Pair
91
+ * with {@link grant} to grant the chosen candidate.
92
+ *
93
+ * @param appId - Numeric app id.
94
+ * @returns The candidate users (id + email/gamertag where known).
95
+ */
96
+ async grantMemberCandidates(appId) {
97
+ const data = await this.management.request(AppGrantMemberCandidatesDocument, { appId });
98
+ return data.appGrantMemberCandidates;
99
+ }
100
+ /**
101
+ * Self-service: claim the app's free/default tier for the authenticated
102
+ * caller (no admin permission required). Use when an app exposes a free tier
103
+ * a player can opt into themselves.
104
+ *
105
+ * @param appId - Numeric app id.
106
+ * @returns The caller's new {@link AppUserAccess} record.
107
+ */
108
+ async claimFree(appId) {
109
+ const data = await this.management.request(ClaimFreeAppAccessDocument, {
110
+ appId,
111
+ });
112
+ return data.claimFreeAppAccess;
113
+ }
114
+ /**
115
+ * Self-grant access to an app via its default tier for the authenticated
116
+ * caller, when the caller is an org member of the app's owning org.
117
+ *
118
+ * @param appId - Numeric app id.
119
+ * @returns The caller's new {@link AppUserAccess} record.
120
+ */
121
+ async grantMine(appId) {
122
+ const data = await this.management.request(GrantMyAppAccessDocument, {
123
+ appId,
124
+ });
125
+ return data.grantMyAppAccess;
126
+ }
127
+ /**
128
+ * Create a new access tier for an app. Requires the `manage_access_tiers` app
129
+ * permission.
130
+ *
131
+ * @param input - {@link CreateAccessTierInput}: `appId`, `name`, runtime
132
+ * `permissions`, pricing/free flags.
133
+ * @returns The created tier.
134
+ */
135
+ async createTier(input) {
136
+ const data = await this.management.request(CreateAccessTierDocument, {
137
+ input,
138
+ });
139
+ return data.createAccessTier;
140
+ }
141
+ /**
142
+ * Update an existing access tier. Requires the `manage_access_tiers` app
143
+ * permission.
144
+ *
145
+ * @param tierId - Numeric tier id.
146
+ * @param input - {@link UpdateAccessTierInput} fields to change.
147
+ * @returns The updated tier.
148
+ */
149
+ async updateTier(tierId, input) {
150
+ const data = await this.management.request(UpdateAccessTierDocument, {
151
+ tierId,
152
+ input,
153
+ });
154
+ return data.updateAccessTier;
155
+ }
156
+ /**
157
+ * Archive (soft-delete) an access tier so it can no longer be granted.
158
+ * Requires the `manage_access_tiers` app permission.
159
+ *
160
+ * @param tierId - Numeric tier id.
161
+ * @returns The archived tier's new status.
162
+ */
163
+ async archiveTier(tierId) {
164
+ const data = await this.management.request(ArchiveAccessTierDocument, {
165
+ tierId,
166
+ });
167
+ return data.archiveAccessTier;
168
+ }
169
+ /**
170
+ * Grant a user access to an app at a given tier. Requires the
171
+ * `manage_access_tiers` app permission. Triggers replica-sync so the grant
172
+ * (and its grid permissions) reaches the game DB / Buddy.
173
+ *
174
+ * @param input - {@link GrantAppAccessInput}: `appId`, `userId`, `tierId`.
175
+ * @returns The created/updated access record.
176
+ */
177
+ async grant(input) {
178
+ const data = await this.management.request(GrantAppAccessDocument, {
179
+ input,
180
+ });
181
+ return data.grantAppAccess;
182
+ }
183
+ /**
184
+ * Revoke a user's access to an app. Requires the `manage_access_tiers` app
185
+ * permission.
186
+ *
187
+ * @param appId - Numeric app id.
188
+ * @param userId - Numeric id of the user whose access is revoked.
189
+ * @returns `true` on success.
190
+ */
191
+ async revoke(appId, userId) {
192
+ const data = await this.management.request(RevokeAppAccessDocument, {
193
+ appId,
194
+ userId,
195
+ });
196
+ return data.revokeAppAccess;
197
+ }
198
+ }
@@ -0,0 +1,192 @@
1
+ import type { GraphQLClient } from '../client.js';
2
+ import { type AppQuery, type AppBySlugQuery, type MyAppsQuery, type AppsForOrgQuery, type MarketplaceAppsQuery, type MarketplaceAppsQueryVariables, type AppsConnectionQuery, type AppsConnectionQueryVariables, type CreateAppMutation, type UpdateAppMutation, type ArchiveAppMutation, type SetAppVisibilityMutation, type CreateAppInput, type UpdateAppInput, type AppVisibility } from '../generated/graphql.js';
3
+ /**
4
+ * The minimal routing tuple the SDK derives from an `App` row: just enough to
5
+ * decide which game-api endpoint should serve a given app. Returned by
6
+ * {@link AppsAPI.routeFor}.
7
+ */
8
+ export interface AppRoute {
9
+ /** Numeric id of the app (`BigInt` as a decimal string). */
10
+ appId: string;
11
+ /**
12
+ * `true` when the app's runtime data lives in a dedicated per-tenant game-api
13
+ * database rather than the shared game-api. Used together with `gameApiUrl` to
14
+ * route gameplay calls.
15
+ */
16
+ splitMode: boolean;
17
+ /**
18
+ * Where the app runs: `'none'` (draft / not deployed), `'shared'` (the shared
19
+ * game-api), or `'dedicated'` (a provisioned per-tenant environment). `null`
20
+ * until the schema/codegen expose it.
21
+ */
22
+ deploymentTarget: string | null;
23
+ /**
24
+ * The game-api base URL to route gameplay to. Set for BOTH dedicated
25
+ * (split-mode) and shared-environment apps. When non-null, build a game-api
26
+ * client against it; when `null`, fall back to the constructor `httpUrl`.
27
+ */
28
+ gameApiUrl: string | null;
29
+ }
30
+ /**
31
+ * App discovery & game-api routing — exposed as `client.apps`.
32
+ *
33
+ * Targets the **management-api** (every call routes to `managementUrl`), where
34
+ * the apps catalog lives. After the database split an app may be served by its
35
+ * own per-tenant cks-game-api; the catalog returns each app's `gameApiUrl` so
36
+ * you can build a per-app `CrowdyClient` against the correct endpoint (see
37
+ * {@link routeFor} / {@link AppRoute}).
38
+ *
39
+ * Auth: {@link appBySlug} is **public** (no session; resolves unlisted or draft
40
+ * apps when the exact slugs are known). {@link app}, {@link myApps}, and
41
+ * {@link routeFor} require authentication (any signed-in user) and otherwise
42
+ * throw {@link CrowdyGraphQLError} with `UNAUTHENTICATED`; note {@link app} does
43
+ * not enforce org/app permissions. `BigInt` ids such as `appId` and `orgId` are
44
+ * decimal strings.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const base = createCrowdyClient({
49
+ * managementUrl: 'https://api.example.com',
50
+ * httpUrl: 'https://legacy-game-api.example.com', // pre-split fallback
51
+ * });
52
+ * await base.auth.login({ email, password });
53
+ *
54
+ * const route = await base.apps.routeFor(appId);
55
+ * if (route.gameApiUrl) {
56
+ * // route gameplay to the app's resolved game-api endpoint
57
+ * const perAppClient = createCrowdyClient({
58
+ * managementUrl: 'https://api.example.com',
59
+ * httpUrl: route.gameApiUrl,
60
+ * wsUrl: route.gameApiUrl.replace(/^http/, 'ws'),
61
+ * tokenStore: base.session.tokenStore,
62
+ * });
63
+ * }
64
+ * ```
65
+ */
66
+ export declare class AppsAPI {
67
+ private readonly management;
68
+ constructor(management: GraphQLClient);
69
+ /**
70
+ * Fetch a single app by its numeric id. Requires authentication (any signed-in
71
+ * user); does **not** enforce org/app permissions, so it can read apps the
72
+ * caller does not own, of any visibility/status. Prefer {@link appBySlug} for
73
+ * slug-based marketplace lookups.
74
+ *
75
+ * @param appId - Numeric id of the app (`BigInt` as a decimal string).
76
+ * @returns The {@link App}, or `null` if the id does not exist.
77
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the caller is not signed in.
78
+ */
79
+ app(appId: string): Promise<AppQuery['app']>;
80
+ /**
81
+ * Look up a single app by its org slug + app slug (the marketplace URL path).
82
+ * **Public**: no authentication required, and not filtered by visibility or
83
+ * status — it can resolve unlisted or draft apps when the exact slugs are
84
+ * known.
85
+ *
86
+ * @param orgSlug - URL slug of the owning organization (e.g. `"acme"` in the
87
+ * path `/acme/my-game`).
88
+ * @param appSlug - URL slug of the app within the org (e.g. `"my-game"`);
89
+ * unique per org.
90
+ * @returns The {@link App}, or `null` if no matching app exists.
91
+ * @throws {CrowdyGraphQLError} on transport/validation failures.
92
+ */
93
+ appBySlug(orgSlug: string, appSlug: string): Promise<AppBySlugQuery['appBySlug']>;
94
+ /**
95
+ * List the apps the authenticated caller can see in their account: those owned
96
+ * by an org they are an active member of, OR those where they hold an active
97
+ * access grant. Includes apps of any visibility/status (e.g. accessible
98
+ * drafts), ordered newest-first. Requires authentication.
99
+ *
100
+ * @returns The caller's accessible {@link App}s (an empty array if none).
101
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the caller is not signed in.
102
+ */
103
+ myApps(): Promise<MyAppsQuery['myApps']>;
104
+ /**
105
+ * Convenience wrapper over {@link app} that returns just the {@link AppRoute}
106
+ * routing tuple for an app — i.e. which game-api endpoint should serve it. If
107
+ * the app row is missing or the API does not expose the split-mode fields yet,
108
+ * returns a safe default (`{ appId, splitMode: false, deploymentTarget: null,
109
+ * gameApiUrl: null }`) so the caller keeps using the legacy single-endpoint
110
+ * deployment.
111
+ *
112
+ * @param appId - Numeric id of the app (`BigInt` as a decimal string).
113
+ * @returns The {@link AppRoute}; route gameplay to `gameApiUrl` when non-null,
114
+ * otherwise fall back to the constructor `httpUrl`.
115
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` (it calls {@link app} under
116
+ * the hood).
117
+ */
118
+ routeFor(appId: string): Promise<AppRoute>;
119
+ /**
120
+ * List the apps owned by an organization (by org slug). Studio-admin read —
121
+ * requires the caller to be a member of the org.
122
+ *
123
+ * @param orgSlug - URL slug of the owning organization.
124
+ * @returns The org's {@link App}s.
125
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
126
+ */
127
+ forOrg(orgSlug: string): Promise<AppsForOrgQuery['appsForOrg']>;
128
+ /**
129
+ * List the public marketplace apps (LIVE + PUBLIC only) with offset
130
+ * pagination. **Public** — no session required.
131
+ *
132
+ * @param opts - Optional {@link AppMarketplaceFilterInput} `filter` and
133
+ * `limit` / `offset`.
134
+ * @returns A page of marketplace apps.
135
+ * @remarks Prefer {@link marketplaceConnection} (Relay cursor pagination) for
136
+ * large catalogs; the offset args here are deprecated server-side.
137
+ */
138
+ marketplace(opts?: {
139
+ filter?: MarketplaceAppsQueryVariables['filter'];
140
+ limit?: MarketplaceAppsQueryVariables['limit'];
141
+ offset?: MarketplaceAppsQueryVariables['offset'];
142
+ }): Promise<MarketplaceAppsQuery['apps']>;
143
+ /**
144
+ * Relay-style cursor pagination over the public marketplace — the preferred
145
+ * alternative to {@link marketplace}. **Public.** See
146
+ * https://docs.crowdedkingdoms.com/overview/pagination.
147
+ *
148
+ * @param args - Optional `first`, `after`, and {@link AppMarketplaceFilterInput}.
149
+ * @returns An apps connection.
150
+ */
151
+ marketplaceConnection(args?: AppsConnectionQueryVariables): Promise<AppsConnectionQuery['appsConnection']>;
152
+ /**
153
+ * Create a new app under an organization. Requires the `manage_apps` org
154
+ * permission. The new app auto-provisions an open-by-default access tier.
155
+ *
156
+ * @param input - {@link CreateAppInput}: `orgId`, `name`, `slug`, optional
157
+ * `description`/`visibility`/`metadata`.
158
+ * @returns The created {@link App}.
159
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
160
+ * `manage_apps`, or `BAD_USER_INPUT` (e.g. duplicate slug).
161
+ */
162
+ create(input: CreateAppInput): Promise<CreateAppMutation['createApp']>;
163
+ /**
164
+ * Update an app's mutable fields. Requires the `manage_apps` app permission.
165
+ *
166
+ * @param appId - Numeric app id.
167
+ * @param input - {@link UpdateAppInput} fields to change.
168
+ * @returns The updated {@link App}.
169
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
170
+ * `manage_apps`.
171
+ */
172
+ update(appId: string, input: UpdateAppInput): Promise<UpdateAppMutation['updateApp']>;
173
+ /**
174
+ * Archive (soft-delete) an app. Requires the `manage_apps` app permission.
175
+ *
176
+ * @param appId - Numeric app id.
177
+ * @returns The archived app's new status.
178
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
179
+ * `manage_apps`.
180
+ */
181
+ archive(appId: string): Promise<ArchiveAppMutation['archiveApp']>;
182
+ /**
183
+ * Override an app's marketplace visibility. **Super-admin only.**
184
+ *
185
+ * @param appId - Numeric app id.
186
+ * @param visibility - The new {@link AppVisibility}.
187
+ * @returns The app's updated visibility.
188
+ * @throws {CrowdyGraphQLError} `FORBIDDEN` for non-super-admins.
189
+ */
190
+ setVisibility(appId: string, visibility: AppVisibility): Promise<SetAppVisibilityMutation['setAppVisibility']>;
191
+ }
192
+ //# sourceMappingURL=apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/domains/apps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAWL,KAAK,QAAQ,EAEb,KAAK,cAAc,EAEnB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,aAAa;IAEtD;;;;;;;;;OASG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAQlD;;;;;;;;;;;;OAYG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAQvC;;;;;;;;OAQG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAQ9C;;;;;;;;;;;;;OAaG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAYhD;;;;;;;OAOG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAKrE;;;;;;;;;OASG;IACG,WAAW,CACf,IAAI,GAAE;QACJ,MAAM,CAAC,EAAE,6BAA6B,CAAC,QAAQ,CAAC,CAAC;QACjD,KAAK,CAAC,EAAE,6BAA6B,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,CAAC,EAAE,6BAA6B,CAAC,QAAQ,CAAC,CAAC;KAC7C,GACL,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAKxC;;;;;;;OAOG;IACG,qBAAqB,CACzB,IAAI,GAAE,4BAAiC,GACtC,OAAO,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;IAKjD;;;;;;;;;OASG;IACG,MAAM,CACV,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAK1C;;;;;;;;OAQG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAQ1C;;;;;;;OAOG;IACG,OAAO,CACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAK5C;;;;;;;OAOG;IACG,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,aAAa,GACxB,OAAO,CAAC,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;CAOzD"}
@@ -0,0 +1,217 @@
1
+ import { AppDocument, AppBySlugDocument, MyAppsDocument, AppsForOrgDocument, MarketplaceAppsDocument, AppsConnectionDocument, CreateAppDocument, UpdateAppDocument, ArchiveAppDocument, SetAppVisibilityDocument, } from '../generated/graphql.js';
2
+ function appRouteFromAppRow(row) {
3
+ if (!row || typeof row !== 'object')
4
+ return null;
5
+ const r = row;
6
+ if (typeof r.appId !== 'string')
7
+ return null;
8
+ return {
9
+ appId: r.appId,
10
+ splitMode: typeof r.splitMode === 'boolean' ? r.splitMode : false,
11
+ deploymentTarget: typeof r.deploymentTarget === 'string' ? r.deploymentTarget : null,
12
+ gameApiUrl: typeof r.gameApiUrl === 'string' && r.gameApiUrl ? r.gameApiUrl : null,
13
+ };
14
+ }
15
+ /**
16
+ * App discovery & game-api routing — exposed as `client.apps`.
17
+ *
18
+ * Targets the **management-api** (every call routes to `managementUrl`), where
19
+ * the apps catalog lives. After the database split an app may be served by its
20
+ * own per-tenant cks-game-api; the catalog returns each app's `gameApiUrl` so
21
+ * you can build a per-app `CrowdyClient` against the correct endpoint (see
22
+ * {@link routeFor} / {@link AppRoute}).
23
+ *
24
+ * Auth: {@link appBySlug} is **public** (no session; resolves unlisted or draft
25
+ * apps when the exact slugs are known). {@link app}, {@link myApps}, and
26
+ * {@link routeFor} require authentication (any signed-in user) and otherwise
27
+ * throw {@link CrowdyGraphQLError} with `UNAUTHENTICATED`; note {@link app} does
28
+ * not enforce org/app permissions. `BigInt` ids such as `appId` and `orgId` are
29
+ * decimal strings.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const base = createCrowdyClient({
34
+ * managementUrl: 'https://api.example.com',
35
+ * httpUrl: 'https://legacy-game-api.example.com', // pre-split fallback
36
+ * });
37
+ * await base.auth.login({ email, password });
38
+ *
39
+ * const route = await base.apps.routeFor(appId);
40
+ * if (route.gameApiUrl) {
41
+ * // route gameplay to the app's resolved game-api endpoint
42
+ * const perAppClient = createCrowdyClient({
43
+ * managementUrl: 'https://api.example.com',
44
+ * httpUrl: route.gameApiUrl,
45
+ * wsUrl: route.gameApiUrl.replace(/^http/, 'ws'),
46
+ * tokenStore: base.session.tokenStore,
47
+ * });
48
+ * }
49
+ * ```
50
+ */
51
+ export class AppsAPI {
52
+ constructor(management) {
53
+ this.management = management;
54
+ }
55
+ /**
56
+ * Fetch a single app by its numeric id. Requires authentication (any signed-in
57
+ * user); does **not** enforce org/app permissions, so it can read apps the
58
+ * caller does not own, of any visibility/status. Prefer {@link appBySlug} for
59
+ * slug-based marketplace lookups.
60
+ *
61
+ * @param appId - Numeric id of the app (`BigInt` as a decimal string).
62
+ * @returns The {@link App}, or `null` if the id does not exist.
63
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the caller is not signed in.
64
+ */
65
+ async app(appId) {
66
+ const data = await this.management.request(AppDocument, { appId });
67
+ return data.app;
68
+ }
69
+ /**
70
+ * Look up a single app by its org slug + app slug (the marketplace URL path).
71
+ * **Public**: no authentication required, and not filtered by visibility or
72
+ * status — it can resolve unlisted or draft apps when the exact slugs are
73
+ * known.
74
+ *
75
+ * @param orgSlug - URL slug of the owning organization (e.g. `"acme"` in the
76
+ * path `/acme/my-game`).
77
+ * @param appSlug - URL slug of the app within the org (e.g. `"my-game"`);
78
+ * unique per org.
79
+ * @returns The {@link App}, or `null` if no matching app exists.
80
+ * @throws {CrowdyGraphQLError} on transport/validation failures.
81
+ */
82
+ async appBySlug(orgSlug, appSlug) {
83
+ const data = await this.management.request(AppBySlugDocument, { orgSlug, appSlug });
84
+ return data.appBySlug;
85
+ }
86
+ /**
87
+ * List the apps the authenticated caller can see in their account: those owned
88
+ * by an org they are an active member of, OR those where they hold an active
89
+ * access grant. Includes apps of any visibility/status (e.g. accessible
90
+ * drafts), ordered newest-first. Requires authentication.
91
+ *
92
+ * @returns The caller's accessible {@link App}s (an empty array if none).
93
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the caller is not signed in.
94
+ */
95
+ async myApps() {
96
+ const data = await this.management.request(MyAppsDocument, {});
97
+ return data.myApps;
98
+ }
99
+ /**
100
+ * Convenience wrapper over {@link app} that returns just the {@link AppRoute}
101
+ * routing tuple for an app — i.e. which game-api endpoint should serve it. If
102
+ * the app row is missing or the API does not expose the split-mode fields yet,
103
+ * returns a safe default (`{ appId, splitMode: false, deploymentTarget: null,
104
+ * gameApiUrl: null }`) so the caller keeps using the legacy single-endpoint
105
+ * deployment.
106
+ *
107
+ * @param appId - Numeric id of the app (`BigInt` as a decimal string).
108
+ * @returns The {@link AppRoute}; route gameplay to `gameApiUrl` when non-null,
109
+ * otherwise fall back to the constructor `httpUrl`.
110
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` (it calls {@link app} under
111
+ * the hood).
112
+ */
113
+ async routeFor(appId) {
114
+ const row = await this.app(appId);
115
+ return (appRouteFromAppRow(row) ?? {
116
+ appId,
117
+ splitMode: false,
118
+ deploymentTarget: null,
119
+ gameApiUrl: null,
120
+ });
121
+ }
122
+ /**
123
+ * List the apps owned by an organization (by org slug). Studio-admin read —
124
+ * requires the caller to be a member of the org.
125
+ *
126
+ * @param orgSlug - URL slug of the owning organization.
127
+ * @returns The org's {@link App}s.
128
+ * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN`.
129
+ */
130
+ async forOrg(orgSlug) {
131
+ const data = await this.management.request(AppsForOrgDocument, { orgSlug });
132
+ return data.appsForOrg;
133
+ }
134
+ /**
135
+ * List the public marketplace apps (LIVE + PUBLIC only) with offset
136
+ * pagination. **Public** — no session required.
137
+ *
138
+ * @param opts - Optional {@link AppMarketplaceFilterInput} `filter` and
139
+ * `limit` / `offset`.
140
+ * @returns A page of marketplace apps.
141
+ * @remarks Prefer {@link marketplaceConnection} (Relay cursor pagination) for
142
+ * large catalogs; the offset args here are deprecated server-side.
143
+ */
144
+ async marketplace(opts = {}) {
145
+ const data = await this.management.request(MarketplaceAppsDocument, opts);
146
+ return data.apps;
147
+ }
148
+ /**
149
+ * Relay-style cursor pagination over the public marketplace — the preferred
150
+ * alternative to {@link marketplace}. **Public.** See
151
+ * https://docs.crowdedkingdoms.com/overview/pagination.
152
+ *
153
+ * @param args - Optional `first`, `after`, and {@link AppMarketplaceFilterInput}.
154
+ * @returns An apps connection.
155
+ */
156
+ async marketplaceConnection(args = {}) {
157
+ const data = await this.management.request(AppsConnectionDocument, args);
158
+ return data.appsConnection;
159
+ }
160
+ /**
161
+ * Create a new app under an organization. Requires the `manage_apps` org
162
+ * permission. The new app auto-provisions an open-by-default access tier.
163
+ *
164
+ * @param input - {@link CreateAppInput}: `orgId`, `name`, `slug`, optional
165
+ * `description`/`visibility`/`metadata`.
166
+ * @returns The created {@link App}.
167
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
168
+ * `manage_apps`, or `BAD_USER_INPUT` (e.g. duplicate slug).
169
+ */
170
+ async create(input) {
171
+ const data = await this.management.request(CreateAppDocument, { input });
172
+ return data.createApp;
173
+ }
174
+ /**
175
+ * Update an app's mutable fields. Requires the `manage_apps` app permission.
176
+ *
177
+ * @param appId - Numeric app id.
178
+ * @param input - {@link UpdateAppInput} fields to change.
179
+ * @returns The updated {@link App}.
180
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
181
+ * `manage_apps`.
182
+ */
183
+ async update(appId, input) {
184
+ const data = await this.management.request(UpdateAppDocument, {
185
+ appId,
186
+ input,
187
+ });
188
+ return data.updateApp;
189
+ }
190
+ /**
191
+ * Archive (soft-delete) an app. Requires the `manage_apps` app permission.
192
+ *
193
+ * @param appId - Numeric app id.
194
+ * @returns The archived app's new status.
195
+ * @throws {CrowdyGraphQLError} `FORBIDDEN`/`SCOPE_MISSING` without
196
+ * `manage_apps`.
197
+ */
198
+ async archive(appId) {
199
+ const data = await this.management.request(ArchiveAppDocument, { appId });
200
+ return data.archiveApp;
201
+ }
202
+ /**
203
+ * Override an app's marketplace visibility. **Super-admin only.**
204
+ *
205
+ * @param appId - Numeric app id.
206
+ * @param visibility - The new {@link AppVisibility}.
207
+ * @returns The app's updated visibility.
208
+ * @throws {CrowdyGraphQLError} `FORBIDDEN` for non-super-admins.
209
+ */
210
+ async setVisibility(appId, visibility) {
211
+ const data = await this.management.request(SetAppVisibilityDocument, {
212
+ appId,
213
+ visibility,
214
+ });
215
+ return data.setAppVisibility;
216
+ }
217
+ }