@playcademy/sdk 0.1.6 → 0.1.8
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/dist/index.d.ts +18 -6
- package/dist/index.js +48 -13
- package/dist/server.d.ts +4 -0
- package/dist/server.js +11 -2
- package/dist/types.d.ts +18 -6
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -3162,6 +3162,8 @@ interface IntegrationsConfig {
|
|
|
3162
3162
|
database?: DatabaseIntegration | boolean;
|
|
3163
3163
|
/** Key-Value storage (optional) */
|
|
3164
3164
|
kv?: boolean;
|
|
3165
|
+
/** Bucket storage (optional) */
|
|
3166
|
+
bucket?: boolean;
|
|
3165
3167
|
}
|
|
3166
3168
|
/**
|
|
3167
3169
|
* Unified Playcademy configuration
|
|
@@ -3212,6 +3214,8 @@ interface BackendDeploymentBundle {
|
|
|
3212
3214
|
bindings?: BackendResourceBindings;
|
|
3213
3215
|
/** Optional schema information for database setup */
|
|
3214
3216
|
schema?: SchemaInfo;
|
|
3217
|
+
/** Optional game secrets */
|
|
3218
|
+
secrets?: Record<string, string>;
|
|
3215
3219
|
}
|
|
3216
3220
|
|
|
3217
3221
|
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
@@ -3715,9 +3719,10 @@ declare class PlaycademyClient {
|
|
|
3715
3719
|
* @param method - HTTP method
|
|
3716
3720
|
* @param body - Request body (optional)
|
|
3717
3721
|
* @param headers - Additional headers (optional)
|
|
3718
|
-
* @returns
|
|
3722
|
+
* @param raw - If true, returns raw Response instead of parsing (optional)
|
|
3723
|
+
* @returns Promise resolving to the response data or raw Response
|
|
3719
3724
|
*/
|
|
3720
|
-
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string
|
|
3725
|
+
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, raw?: boolean): Promise<T>;
|
|
3721
3726
|
/**
|
|
3722
3727
|
* Ensures a gameId is available, throwing an error if not.
|
|
3723
3728
|
*
|
|
@@ -3851,6 +3856,12 @@ declare class PlaycademyClient {
|
|
|
3851
3856
|
};
|
|
3852
3857
|
upsert: (slug: string, metadata: UpsertGameMetadataInput) => Promise<Game>;
|
|
3853
3858
|
delete: (gameId: string) => Promise<void>;
|
|
3859
|
+
secrets: {
|
|
3860
|
+
set: (slug: string, secrets: Record<string, string>) => Promise<string[]>;
|
|
3861
|
+
list: (slug: string) => Promise<string[]>;
|
|
3862
|
+
get: (slug: string) => Promise<Record<string, string>>;
|
|
3863
|
+
delete: (slug: string, key: string) => Promise<void>;
|
|
3864
|
+
};
|
|
3854
3865
|
};
|
|
3855
3866
|
items: {
|
|
3856
3867
|
create: (gameId: string, slug: string, itemData: Omit<InsertItemInput, "slug" | "gameId">) => Promise<Item>;
|
|
@@ -3887,49 +3898,49 @@ declare class PlaycademyClient {
|
|
|
3887
3898
|
};
|
|
3888
3899
|
items: {
|
|
3889
3900
|
create: (props: InsertItemInput) => Promise<{
|
|
3901
|
+
metadata: unknown;
|
|
3890
3902
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
3891
3903
|
slug: string;
|
|
3892
3904
|
id: string;
|
|
3893
3905
|
createdAt: Date;
|
|
3894
3906
|
gameId: string | null;
|
|
3895
3907
|
displayName: string;
|
|
3896
|
-
metadata: unknown;
|
|
3897
3908
|
description: string | null;
|
|
3898
3909
|
isPlaceable: boolean;
|
|
3899
3910
|
imageUrl: string | null;
|
|
3900
3911
|
}>;
|
|
3901
3912
|
get: (itemId: string) => Promise<{
|
|
3913
|
+
metadata: unknown;
|
|
3902
3914
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
3903
3915
|
slug: string;
|
|
3904
3916
|
id: string;
|
|
3905
3917
|
createdAt: Date;
|
|
3906
3918
|
gameId: string | null;
|
|
3907
3919
|
displayName: string;
|
|
3908
|
-
metadata: unknown;
|
|
3909
3920
|
description: string | null;
|
|
3910
3921
|
isPlaceable: boolean;
|
|
3911
3922
|
imageUrl: string | null;
|
|
3912
3923
|
}>;
|
|
3913
3924
|
list: () => Promise<{
|
|
3925
|
+
metadata: unknown;
|
|
3914
3926
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
3915
3927
|
slug: string;
|
|
3916
3928
|
id: string;
|
|
3917
3929
|
createdAt: Date;
|
|
3918
3930
|
gameId: string | null;
|
|
3919
3931
|
displayName: string;
|
|
3920
|
-
metadata: unknown;
|
|
3921
3932
|
description: string | null;
|
|
3922
3933
|
isPlaceable: boolean;
|
|
3923
3934
|
imageUrl: string | null;
|
|
3924
3935
|
}[]>;
|
|
3925
3936
|
update: (itemId: string, props: UpdateItemInput) => Promise<{
|
|
3937
|
+
metadata: unknown;
|
|
3926
3938
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
3927
3939
|
slug: string;
|
|
3928
3940
|
id: string;
|
|
3929
3941
|
createdAt: Date;
|
|
3930
3942
|
gameId: string | null;
|
|
3931
3943
|
displayName: string;
|
|
3932
|
-
metadata: unknown;
|
|
3933
3944
|
description: string | null;
|
|
3934
3945
|
isPlaceable: boolean;
|
|
3935
3946
|
imageUrl: string | null;
|
|
@@ -4165,6 +4176,7 @@ declare class PlaycademyClient {
|
|
|
4165
4176
|
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
4166
4177
|
delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
4167
4178
|
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
4179
|
+
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string>): Promise<Response>;
|
|
4168
4180
|
};
|
|
4169
4181
|
/** Auto-initializes a PlaycademyClient with context from the environment */
|
|
4170
4182
|
static init: typeof init;
|
package/dist/index.js
CHANGED
|
@@ -935,28 +935,42 @@ function checkDevWarnings(data) {
|
|
|
935
935
|
console.warn(`[Playcademy Dev Warning] ${warningType}`);
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
|
+
function prepareRequestBody(body, headers) {
|
|
939
|
+
if (body instanceof FormData) {
|
|
940
|
+
return body;
|
|
941
|
+
}
|
|
942
|
+
if (body instanceof ArrayBuffer || body instanceof Blob || ArrayBuffer.isView(body)) {
|
|
943
|
+
if (!headers["Content-Type"]) {
|
|
944
|
+
headers["Content-Type"] = "application/octet-stream";
|
|
945
|
+
}
|
|
946
|
+
return body;
|
|
947
|
+
}
|
|
948
|
+
if (body !== undefined && body !== null) {
|
|
949
|
+
headers["Content-Type"] = "application/json";
|
|
950
|
+
return JSON.stringify(body);
|
|
951
|
+
}
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
938
954
|
async function request({
|
|
939
955
|
path,
|
|
940
956
|
baseUrl,
|
|
941
957
|
method = "GET",
|
|
942
958
|
body,
|
|
943
|
-
extraHeaders = {}
|
|
959
|
+
extraHeaders = {},
|
|
960
|
+
raw = false
|
|
944
961
|
}) {
|
|
945
962
|
const url = baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : `/${path}`);
|
|
946
963
|
const headers = { ...extraHeaders };
|
|
947
|
-
|
|
948
|
-
if (body instanceof FormData) {
|
|
949
|
-
payload = body;
|
|
950
|
-
} else if (body !== undefined && body !== null) {
|
|
951
|
-
payload = JSON.stringify(body);
|
|
952
|
-
headers["Content-Type"] = "application/json";
|
|
953
|
-
}
|
|
964
|
+
const payload = prepareRequestBody(body, headers);
|
|
954
965
|
const res = await fetch(url, {
|
|
955
966
|
method,
|
|
956
967
|
headers,
|
|
957
968
|
body: payload,
|
|
958
969
|
credentials: "omit"
|
|
959
970
|
});
|
|
971
|
+
if (raw) {
|
|
972
|
+
return res;
|
|
973
|
+
}
|
|
960
974
|
if (!res.ok) {
|
|
961
975
|
const clonedRes = res.clone();
|
|
962
976
|
const errorBody = await clonedRes.json().catch(() => clonedRes.text().catch(() => {
|
|
@@ -978,8 +992,8 @@ async function request({
|
|
|
978
992
|
throw err;
|
|
979
993
|
}
|
|
980
994
|
}
|
|
981
|
-
const
|
|
982
|
-
return
|
|
995
|
+
const rawText = await res.text().catch(() => "");
|
|
996
|
+
return rawText && rawText.length > 0 ? rawText : undefined;
|
|
983
997
|
}
|
|
984
998
|
async function fetchManifest(assetBundleBase) {
|
|
985
999
|
const manifestUrl = `${assetBundleBase.replace(/\/$/, "")}/playcademy.manifest.json`;
|
|
@@ -1357,7 +1371,24 @@ function createDevNamespace(client) {
|
|
|
1357
1371
|
upsert: async (slug, metadata) => {
|
|
1358
1372
|
return client.dev.games.deploy.frontend(slug, metadata, null);
|
|
1359
1373
|
},
|
|
1360
|
-
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
|
|
1374
|
+
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE"),
|
|
1375
|
+
secrets: {
|
|
1376
|
+
set: async (slug, secrets) => {
|
|
1377
|
+
const result = await client["request"](`/games/${slug}/secrets`, "POST", secrets);
|
|
1378
|
+
return result.keys;
|
|
1379
|
+
},
|
|
1380
|
+
list: async (slug) => {
|
|
1381
|
+
const result = await client["request"](`/games/${slug}/secrets`, "GET");
|
|
1382
|
+
return result.keys;
|
|
1383
|
+
},
|
|
1384
|
+
get: async (slug) => {
|
|
1385
|
+
const result = await client["request"](`/games/${slug}/secrets/values`, "GET");
|
|
1386
|
+
return result.secrets;
|
|
1387
|
+
},
|
|
1388
|
+
delete: async (slug, key) => {
|
|
1389
|
+
await client["request"](`/games/${slug}/secrets/${key}`, "DELETE");
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1361
1392
|
},
|
|
1362
1393
|
items: {
|
|
1363
1394
|
create: (gameId, slug, itemData) => client["request"](`/games/${gameId}/items`, "POST", {
|
|
@@ -2276,6 +2307,9 @@ function createBackendNamespace(client) {
|
|
|
2276
2307
|
},
|
|
2277
2308
|
async request(path, method, body, headers) {
|
|
2278
2309
|
return client["requestGameBackend"](normalizePath(path), method, body, headers);
|
|
2310
|
+
},
|
|
2311
|
+
async download(path, method = "GET", body, headers) {
|
|
2312
|
+
return client["requestGameBackend"](normalizePath(path), method, body, headers, true);
|
|
2279
2313
|
}
|
|
2280
2314
|
};
|
|
2281
2315
|
}
|
|
@@ -2542,7 +2576,7 @@ var init_client = __esm(() => {
|
|
|
2542
2576
|
extraHeaders: effectiveHeaders
|
|
2543
2577
|
});
|
|
2544
2578
|
}
|
|
2545
|
-
async requestGameBackend(path, method, body, headers) {
|
|
2579
|
+
async requestGameBackend(path, method, body, headers, raw) {
|
|
2546
2580
|
const effectiveHeaders = {
|
|
2547
2581
|
...headers,
|
|
2548
2582
|
...this.authStrategy.getHeaders()
|
|
@@ -2552,7 +2586,8 @@ var init_client = __esm(() => {
|
|
|
2552
2586
|
method,
|
|
2553
2587
|
body,
|
|
2554
2588
|
baseUrl: this.getGameBackendUrl(),
|
|
2555
|
-
extraHeaders: effectiveHeaders
|
|
2589
|
+
extraHeaders: effectiveHeaders,
|
|
2590
|
+
raw
|
|
2556
2591
|
});
|
|
2557
2592
|
}
|
|
2558
2593
|
_ensureGameId() {
|
package/dist/server.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ interface IntegrationsConfig {
|
|
|
52
52
|
database?: DatabaseIntegration | boolean;
|
|
53
53
|
/** Key-Value storage (optional) */
|
|
54
54
|
kv?: boolean;
|
|
55
|
+
/** Bucket storage (optional) */
|
|
56
|
+
bucket?: boolean;
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
57
59
|
* Unified Playcademy configuration
|
|
@@ -171,6 +173,8 @@ interface BackendDeploymentBundle {
|
|
|
171
173
|
bindings?: BackendResourceBindings;
|
|
172
174
|
/** Optional schema information for database setup */
|
|
173
175
|
schema?: SchemaInfo;
|
|
176
|
+
/** Optional game secrets */
|
|
177
|
+
secrets?: Record<string, string>;
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
/**
|
package/dist/server.js
CHANGED
|
@@ -122,7 +122,8 @@ async function loadFile(filename, options = {}) {
|
|
|
122
122
|
required = false,
|
|
123
123
|
searchUp = false,
|
|
124
124
|
maxLevels = 3,
|
|
125
|
-
parseJson = false
|
|
125
|
+
parseJson = false,
|
|
126
|
+
stripComments = false
|
|
126
127
|
} = options;
|
|
127
128
|
let fileResult;
|
|
128
129
|
if (searchUp) {
|
|
@@ -151,8 +152,11 @@ async function loadFile(filename, options = {}) {
|
|
|
151
152
|
return null;
|
|
152
153
|
}
|
|
153
154
|
try {
|
|
154
|
-
|
|
155
|
+
let content = await readFile(fileResult.path, "utf-8");
|
|
155
156
|
if (parseJson) {
|
|
157
|
+
if (stripComments) {
|
|
158
|
+
content = stripJsonComments(content);
|
|
159
|
+
}
|
|
156
160
|
return JSON.parse(content);
|
|
157
161
|
}
|
|
158
162
|
return content;
|
|
@@ -178,6 +182,11 @@ async function findFile(filename, options = {}) {
|
|
|
178
182
|
}
|
|
179
183
|
return null;
|
|
180
184
|
}
|
|
185
|
+
function stripJsonComments(jsonc) {
|
|
186
|
+
let result = jsonc.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
187
|
+
result = result.replace(/\/\/.*/g, "");
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
181
190
|
|
|
182
191
|
// src/server/utils/config-loader.ts
|
|
183
192
|
async function findConfigPath(configPath) {
|
package/dist/types.d.ts
CHANGED
|
@@ -3931,6 +3931,8 @@ interface IntegrationsConfig {
|
|
|
3931
3931
|
database?: DatabaseIntegration | boolean;
|
|
3932
3932
|
/** Key-Value storage (optional) */
|
|
3933
3933
|
kv?: boolean;
|
|
3934
|
+
/** Bucket storage (optional) */
|
|
3935
|
+
bucket?: boolean;
|
|
3934
3936
|
}
|
|
3935
3937
|
/**
|
|
3936
3938
|
* Unified Playcademy configuration
|
|
@@ -4050,6 +4052,8 @@ interface BackendDeploymentBundle {
|
|
|
4050
4052
|
bindings?: BackendResourceBindings;
|
|
4051
4053
|
/** Optional schema information for database setup */
|
|
4052
4054
|
schema?: SchemaInfo;
|
|
4055
|
+
/** Optional game secrets */
|
|
4056
|
+
secrets?: Record<string, string>;
|
|
4053
4057
|
}
|
|
4054
4058
|
|
|
4055
4059
|
interface UserScore {
|
|
@@ -4403,9 +4407,10 @@ declare class PlaycademyClient {
|
|
|
4403
4407
|
* @param method - HTTP method
|
|
4404
4408
|
* @param body - Request body (optional)
|
|
4405
4409
|
* @param headers - Additional headers (optional)
|
|
4406
|
-
* @returns
|
|
4410
|
+
* @param raw - If true, returns raw Response instead of parsing (optional)
|
|
4411
|
+
* @returns Promise resolving to the response data or raw Response
|
|
4407
4412
|
*/
|
|
4408
|
-
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string
|
|
4413
|
+
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, raw?: boolean): Promise<T>;
|
|
4409
4414
|
/**
|
|
4410
4415
|
* Ensures a gameId is available, throwing an error if not.
|
|
4411
4416
|
*
|
|
@@ -4539,6 +4544,12 @@ declare class PlaycademyClient {
|
|
|
4539
4544
|
};
|
|
4540
4545
|
upsert: (slug: string, metadata: UpsertGameMetadataInput) => Promise<Game>;
|
|
4541
4546
|
delete: (gameId: string) => Promise<void>;
|
|
4547
|
+
secrets: {
|
|
4548
|
+
set: (slug: string, secrets: Record<string, string>) => Promise<string[]>;
|
|
4549
|
+
list: (slug: string) => Promise<string[]>;
|
|
4550
|
+
get: (slug: string) => Promise<Record<string, string>>;
|
|
4551
|
+
delete: (slug: string, key: string) => Promise<void>;
|
|
4552
|
+
};
|
|
4542
4553
|
};
|
|
4543
4554
|
items: {
|
|
4544
4555
|
create: (gameId: string, slug: string, itemData: Omit<InsertItemInput, "slug" | "gameId">) => Promise<Item>;
|
|
@@ -4575,49 +4586,49 @@ declare class PlaycademyClient {
|
|
|
4575
4586
|
};
|
|
4576
4587
|
items: {
|
|
4577
4588
|
create: (props: InsertItemInput) => Promise<{
|
|
4589
|
+
metadata: unknown;
|
|
4578
4590
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4579
4591
|
slug: string;
|
|
4580
4592
|
id: string;
|
|
4581
4593
|
createdAt: Date;
|
|
4582
4594
|
gameId: string | null;
|
|
4583
4595
|
displayName: string;
|
|
4584
|
-
metadata: unknown;
|
|
4585
4596
|
description: string | null;
|
|
4586
4597
|
isPlaceable: boolean;
|
|
4587
4598
|
imageUrl: string | null;
|
|
4588
4599
|
}>;
|
|
4589
4600
|
get: (itemId: string) => Promise<{
|
|
4601
|
+
metadata: unknown;
|
|
4590
4602
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4591
4603
|
slug: string;
|
|
4592
4604
|
id: string;
|
|
4593
4605
|
createdAt: Date;
|
|
4594
4606
|
gameId: string | null;
|
|
4595
4607
|
displayName: string;
|
|
4596
|
-
metadata: unknown;
|
|
4597
4608
|
description: string | null;
|
|
4598
4609
|
isPlaceable: boolean;
|
|
4599
4610
|
imageUrl: string | null;
|
|
4600
4611
|
}>;
|
|
4601
4612
|
list: () => Promise<{
|
|
4613
|
+
metadata: unknown;
|
|
4602
4614
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4603
4615
|
slug: string;
|
|
4604
4616
|
id: string;
|
|
4605
4617
|
createdAt: Date;
|
|
4606
4618
|
gameId: string | null;
|
|
4607
4619
|
displayName: string;
|
|
4608
|
-
metadata: unknown;
|
|
4609
4620
|
description: string | null;
|
|
4610
4621
|
isPlaceable: boolean;
|
|
4611
4622
|
imageUrl: string | null;
|
|
4612
4623
|
}[]>;
|
|
4613
4624
|
update: (itemId: string, props: UpdateItemInput) => Promise<{
|
|
4625
|
+
metadata: unknown;
|
|
4614
4626
|
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4615
4627
|
slug: string;
|
|
4616
4628
|
id: string;
|
|
4617
4629
|
createdAt: Date;
|
|
4618
4630
|
gameId: string | null;
|
|
4619
4631
|
displayName: string;
|
|
4620
|
-
metadata: unknown;
|
|
4621
4632
|
description: string | null;
|
|
4622
4633
|
isPlaceable: boolean;
|
|
4623
4634
|
imageUrl: string | null;
|
|
@@ -4853,6 +4864,7 @@ declare class PlaycademyClient {
|
|
|
4853
4864
|
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
4854
4865
|
delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
4855
4866
|
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
4867
|
+
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string>): Promise<Response>;
|
|
4856
4868
|
};
|
|
4857
4869
|
/** Auto-initializes a PlaycademyClient with context from the environment */
|
|
4858
4870
|
static init: typeof init;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcademy/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"@playcademy/constants": "0.0.1",
|
|
38
38
|
"@playcademy/data": "0.0.1",
|
|
39
39
|
"@playcademy/logger": "0.0.1",
|
|
40
|
-
"@playcademy/sandbox": "0.1.
|
|
40
|
+
"@playcademy/sandbox": "0.1.7",
|
|
41
41
|
"@playcademy/test": "0.0.1",
|
|
42
42
|
"@playcademy/timeback": "0.0.1",
|
|
43
43
|
"@playcademy/utils": "0.0.1",
|
|
44
44
|
"@types/bun": "latest",
|
|
45
|
-
"playcademy": "0.
|
|
45
|
+
"playcademy": "0.13.19",
|
|
46
46
|
"rollup": "^4.50.2",
|
|
47
47
|
"rollup-plugin-dts": "^6.2.3",
|
|
48
48
|
"typescript": "^5.7.2",
|