@studiometa/forge-sdk 0.4.4 → 0.4.5
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.js +69 -0
- package/dist/index.js.map +1 -1
- package/dist/test-utils.js +2 -0
- package/dist/test-utils.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HttpClient, unwrapDocument, unwrapDocument as unwrapDocument$1, unwrapListDocument, unwrapListDocument as unwrapListDocument$1, unwrapResource } from "@studiometa/forge-api";
|
|
2
|
+
//#region src/pagination.ts
|
|
2
3
|
/**
|
|
3
4
|
* Async paginated iterator that auto-fetches all pages using cursor-based pagination.
|
|
4
5
|
*
|
|
@@ -42,6 +43,8 @@ var AsyncPaginatedIterator = class {
|
|
|
42
43
|
return items;
|
|
43
44
|
}
|
|
44
45
|
};
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/utils/name-matcher.ts
|
|
45
48
|
/**
|
|
46
49
|
* Match items by name using case-insensitive exact and partial matching.
|
|
47
50
|
*/
|
|
@@ -52,6 +55,8 @@ function matchByName(items, query, getName) {
|
|
|
52
55
|
partial: items.filter((item) => getName(item).toLowerCase().includes(lower))
|
|
53
56
|
};
|
|
54
57
|
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/resources/base.ts
|
|
55
60
|
/**
|
|
56
61
|
* Abstract base class for resource collections.
|
|
57
62
|
* Provides shared `client` and `orgSlug` properties to avoid duplication across all collection classes.
|
|
@@ -64,6 +69,8 @@ var BaseCollection = class {
|
|
|
64
69
|
this.orgSlug = orgSlug;
|
|
65
70
|
}
|
|
66
71
|
};
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/resources/deployments.ts
|
|
67
74
|
/**
|
|
68
75
|
* Collection of deployments for a site.
|
|
69
76
|
*
|
|
@@ -75,6 +82,8 @@ var BaseCollection = class {
|
|
|
75
82
|
* ```
|
|
76
83
|
*/
|
|
77
84
|
var DeploymentsCollection = class extends BaseCollection {
|
|
85
|
+
serverId;
|
|
86
|
+
siteId;
|
|
78
87
|
/** @internal */
|
|
79
88
|
constructor(client, orgSlug, serverId, siteId) {
|
|
80
89
|
super(client, orgSlug);
|
|
@@ -168,6 +177,8 @@ var DeploymentsCollection = class extends BaseCollection {
|
|
|
168
177
|
await this.client.put(`/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments/script`, { content });
|
|
169
178
|
}
|
|
170
179
|
};
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/resources/certificates.ts
|
|
171
182
|
/**
|
|
172
183
|
* SSL certificates for a site, accessed per-domain.
|
|
173
184
|
*
|
|
@@ -182,6 +193,8 @@ var DeploymentsCollection = class extends BaseCollection {
|
|
|
182
193
|
* ```
|
|
183
194
|
*/
|
|
184
195
|
var CertificatesCollection = class extends BaseCollection {
|
|
196
|
+
serverId;
|
|
197
|
+
siteId;
|
|
185
198
|
/** @internal */
|
|
186
199
|
constructor(client, orgSlug, serverId, siteId) {
|
|
187
200
|
super(client, orgSlug);
|
|
@@ -238,6 +251,8 @@ var CertificatesCollection = class extends BaseCollection {
|
|
|
238
251
|
await this.client.post(`${this.domainPath(domainId)}/actions`, { action: "activate" });
|
|
239
252
|
}
|
|
240
253
|
};
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/resources/commands.ts
|
|
241
256
|
/**
|
|
242
257
|
* Collection of commands run on a site.
|
|
243
258
|
*
|
|
@@ -249,6 +264,8 @@ var CertificatesCollection = class extends BaseCollection {
|
|
|
249
264
|
* ```
|
|
250
265
|
*/
|
|
251
266
|
var CommandsCollection = class extends BaseCollection {
|
|
267
|
+
serverId;
|
|
268
|
+
siteId;
|
|
252
269
|
/** @internal */
|
|
253
270
|
constructor(client, orgSlug, serverId, siteId) {
|
|
254
271
|
super(client, orgSlug);
|
|
@@ -321,6 +338,8 @@ var CommandsCollection = class extends BaseCollection {
|
|
|
321
338
|
return unwrapDocument$1(await this.client.post(this.basePath, data));
|
|
322
339
|
}
|
|
323
340
|
};
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/resources/security-rules.ts
|
|
324
343
|
/**
|
|
325
344
|
* Collection of security rules on a site.
|
|
326
345
|
*
|
|
@@ -332,6 +351,8 @@ var CommandsCollection = class extends BaseCollection {
|
|
|
332
351
|
* ```
|
|
333
352
|
*/
|
|
334
353
|
var SecurityRulesCollection = class extends BaseCollection {
|
|
354
|
+
serverId;
|
|
355
|
+
siteId;
|
|
335
356
|
/** @internal */
|
|
336
357
|
constructor(client, orgSlug, serverId, siteId) {
|
|
337
358
|
super(client, orgSlug);
|
|
@@ -417,6 +438,8 @@ var SecurityRulesCollection = class extends BaseCollection {
|
|
|
417
438
|
await this.client.delete(`${this.basePath}/${ruleId}`);
|
|
418
439
|
}
|
|
419
440
|
};
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/resources/redirect-rules.ts
|
|
420
443
|
/**
|
|
421
444
|
* Collection of redirect rules on a site.
|
|
422
445
|
*
|
|
@@ -428,6 +451,8 @@ var SecurityRulesCollection = class extends BaseCollection {
|
|
|
428
451
|
* ```
|
|
429
452
|
*/
|
|
430
453
|
var RedirectRulesCollection = class extends BaseCollection {
|
|
454
|
+
serverId;
|
|
455
|
+
siteId;
|
|
431
456
|
/** @internal */
|
|
432
457
|
constructor(client, orgSlug, serverId, siteId) {
|
|
433
458
|
super(client, orgSlug);
|
|
@@ -513,6 +538,8 @@ var RedirectRulesCollection = class extends BaseCollection {
|
|
|
513
538
|
await this.client.delete(`${this.basePath}/${ruleId}`);
|
|
514
539
|
}
|
|
515
540
|
};
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region src/resources/sites.ts
|
|
516
543
|
/**
|
|
517
544
|
* Collection of sites on a server.
|
|
518
545
|
*
|
|
@@ -524,6 +551,7 @@ var RedirectRulesCollection = class extends BaseCollection {
|
|
|
524
551
|
* ```
|
|
525
552
|
*/
|
|
526
553
|
var SitesCollection = class extends BaseCollection {
|
|
554
|
+
serverId;
|
|
527
555
|
/** @internal */
|
|
528
556
|
constructor(client, orgSlug, serverId) {
|
|
529
557
|
super(client, orgSlug);
|
|
@@ -662,6 +690,8 @@ var SitesCollection = class extends BaseCollection {
|
|
|
662
690
|
* ```
|
|
663
691
|
*/
|
|
664
692
|
var SiteResource = class extends BaseCollection {
|
|
693
|
+
serverId;
|
|
694
|
+
siteId;
|
|
665
695
|
/** Deployments for this site. */
|
|
666
696
|
deployments;
|
|
667
697
|
/** SSL certificates for this site. */
|
|
@@ -736,6 +766,8 @@ var SiteResource = class extends BaseCollection {
|
|
|
736
766
|
* ```
|
|
737
767
|
*/
|
|
738
768
|
var SiteEnvResource = class extends BaseCollection {
|
|
769
|
+
serverId;
|
|
770
|
+
siteId;
|
|
739
771
|
/** @internal */
|
|
740
772
|
constructor(client, orgSlug, serverId, siteId) {
|
|
741
773
|
super(client, orgSlug);
|
|
@@ -772,6 +804,8 @@ var SiteEnvResource = class extends BaseCollection {
|
|
|
772
804
|
* ```
|
|
773
805
|
*/
|
|
774
806
|
var SiteNginxResource = class extends BaseCollection {
|
|
807
|
+
serverId;
|
|
808
|
+
siteId;
|
|
775
809
|
/** @internal */
|
|
776
810
|
constructor(client, orgSlug, serverId, siteId) {
|
|
777
811
|
super(client, orgSlug);
|
|
@@ -798,6 +832,8 @@ var SiteNginxResource = class extends BaseCollection {
|
|
|
798
832
|
await this.client.put(this.basePath, { content });
|
|
799
833
|
}
|
|
800
834
|
};
|
|
835
|
+
//#endregion
|
|
836
|
+
//#region src/resources/databases.ts
|
|
801
837
|
/**
|
|
802
838
|
* Collection of databases on a server.
|
|
803
839
|
*
|
|
@@ -809,6 +845,7 @@ var SiteNginxResource = class extends BaseCollection {
|
|
|
809
845
|
* ```
|
|
810
846
|
*/
|
|
811
847
|
var DatabasesCollection = class extends BaseCollection {
|
|
848
|
+
serverId;
|
|
812
849
|
/** @internal */
|
|
813
850
|
constructor(client, orgSlug, serverId) {
|
|
814
851
|
super(client, orgSlug);
|
|
@@ -893,6 +930,8 @@ var DatabasesCollection = class extends BaseCollection {
|
|
|
893
930
|
await this.client.delete(`${this.basePath}/${databaseId}`);
|
|
894
931
|
}
|
|
895
932
|
};
|
|
933
|
+
//#endregion
|
|
934
|
+
//#region src/resources/database-users.ts
|
|
896
935
|
/**
|
|
897
936
|
* Collection of database users on a server.
|
|
898
937
|
*
|
|
@@ -904,6 +943,7 @@ var DatabasesCollection = class extends BaseCollection {
|
|
|
904
943
|
* ```
|
|
905
944
|
*/
|
|
906
945
|
var DatabaseUsersCollection = class extends BaseCollection {
|
|
946
|
+
serverId;
|
|
907
947
|
/** @internal */
|
|
908
948
|
constructor(client, orgSlug, serverId) {
|
|
909
949
|
super(client, orgSlug);
|
|
@@ -988,6 +1028,8 @@ var DatabaseUsersCollection = class extends BaseCollection {
|
|
|
988
1028
|
await this.client.delete(`${this.basePath}/${userId}`);
|
|
989
1029
|
}
|
|
990
1030
|
};
|
|
1031
|
+
//#endregion
|
|
1032
|
+
//#region src/resources/daemons.ts
|
|
991
1033
|
/**
|
|
992
1034
|
* Collection of daemons (background processes) on a server.
|
|
993
1035
|
*
|
|
@@ -999,6 +1041,7 @@ var DatabaseUsersCollection = class extends BaseCollection {
|
|
|
999
1041
|
* ```
|
|
1000
1042
|
*/
|
|
1001
1043
|
var DaemonsCollection = class extends BaseCollection {
|
|
1044
|
+
serverId;
|
|
1002
1045
|
/** @internal */
|
|
1003
1046
|
constructor(client, orgSlug, serverId) {
|
|
1004
1047
|
super(client, orgSlug);
|
|
@@ -1093,6 +1136,8 @@ var DaemonsCollection = class extends BaseCollection {
|
|
|
1093
1136
|
await this.client.post(`${this.basePath}/${daemonId}/restart`);
|
|
1094
1137
|
}
|
|
1095
1138
|
};
|
|
1139
|
+
//#endregion
|
|
1140
|
+
//#region src/resources/backups.ts
|
|
1096
1141
|
/**
|
|
1097
1142
|
* Collection of backup configurations on a server.
|
|
1098
1143
|
*
|
|
@@ -1104,6 +1149,7 @@ var DaemonsCollection = class extends BaseCollection {
|
|
|
1104
1149
|
* ```
|
|
1105
1150
|
*/
|
|
1106
1151
|
var BackupsCollection = class extends BaseCollection {
|
|
1152
|
+
serverId;
|
|
1107
1153
|
/** @internal */
|
|
1108
1154
|
constructor(client, orgSlug, serverId) {
|
|
1109
1155
|
super(client, orgSlug);
|
|
@@ -1190,6 +1236,8 @@ var BackupsCollection = class extends BaseCollection {
|
|
|
1190
1236
|
await this.client.delete(`${this.basePath}/${backupId}`);
|
|
1191
1237
|
}
|
|
1192
1238
|
};
|
|
1239
|
+
//#endregion
|
|
1240
|
+
//#region src/resources/scheduled-jobs.ts
|
|
1193
1241
|
/**
|
|
1194
1242
|
* Collection of scheduled jobs (cron jobs) on a server.
|
|
1195
1243
|
*
|
|
@@ -1201,6 +1249,7 @@ var BackupsCollection = class extends BaseCollection {
|
|
|
1201
1249
|
* ```
|
|
1202
1250
|
*/
|
|
1203
1251
|
var ScheduledJobsCollection = class extends BaseCollection {
|
|
1252
|
+
serverId;
|
|
1204
1253
|
/** @internal */
|
|
1205
1254
|
constructor(client, orgSlug, serverId) {
|
|
1206
1255
|
super(client, orgSlug);
|
|
@@ -1285,6 +1334,8 @@ var ScheduledJobsCollection = class extends BaseCollection {
|
|
|
1285
1334
|
await this.client.delete(`${this.basePath}/${jobId}`);
|
|
1286
1335
|
}
|
|
1287
1336
|
};
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region src/resources/monitors.ts
|
|
1288
1339
|
/**
|
|
1289
1340
|
* Collection of server monitors.
|
|
1290
1341
|
*
|
|
@@ -1296,6 +1347,7 @@ var ScheduledJobsCollection = class extends BaseCollection {
|
|
|
1296
1347
|
* ```
|
|
1297
1348
|
*/
|
|
1298
1349
|
var MonitorsCollection = class extends BaseCollection {
|
|
1350
|
+
serverId;
|
|
1299
1351
|
/** @internal */
|
|
1300
1352
|
constructor(client, orgSlug, serverId) {
|
|
1301
1353
|
super(client, orgSlug);
|
|
@@ -1381,6 +1433,8 @@ var MonitorsCollection = class extends BaseCollection {
|
|
|
1381
1433
|
await this.client.delete(`${this.basePath}/${monitorId}`);
|
|
1382
1434
|
}
|
|
1383
1435
|
};
|
|
1436
|
+
//#endregion
|
|
1437
|
+
//#region src/resources/firewall-rules.ts
|
|
1384
1438
|
/**
|
|
1385
1439
|
* Collection of firewall rules on a server.
|
|
1386
1440
|
*
|
|
@@ -1392,6 +1446,7 @@ var MonitorsCollection = class extends BaseCollection {
|
|
|
1392
1446
|
* ```
|
|
1393
1447
|
*/
|
|
1394
1448
|
var FirewallRulesCollection = class extends BaseCollection {
|
|
1449
|
+
serverId;
|
|
1395
1450
|
/** @internal */
|
|
1396
1451
|
constructor(client, orgSlug, serverId) {
|
|
1397
1452
|
super(client, orgSlug);
|
|
@@ -1476,6 +1531,8 @@ var FirewallRulesCollection = class extends BaseCollection {
|
|
|
1476
1531
|
await this.client.delete(`${this.basePath}/${ruleId}`);
|
|
1477
1532
|
}
|
|
1478
1533
|
};
|
|
1534
|
+
//#endregion
|
|
1535
|
+
//#region src/resources/ssh-keys.ts
|
|
1479
1536
|
/**
|
|
1480
1537
|
* Collection of SSH keys on a server.
|
|
1481
1538
|
*
|
|
@@ -1487,6 +1544,7 @@ var FirewallRulesCollection = class extends BaseCollection {
|
|
|
1487
1544
|
* ```
|
|
1488
1545
|
*/
|
|
1489
1546
|
var SshKeysCollection = class extends BaseCollection {
|
|
1547
|
+
serverId;
|
|
1490
1548
|
/** @internal */
|
|
1491
1549
|
constructor(client, orgSlug, serverId) {
|
|
1492
1550
|
super(client, orgSlug);
|
|
@@ -1570,6 +1628,8 @@ var SshKeysCollection = class extends BaseCollection {
|
|
|
1570
1628
|
await this.client.delete(`${this.basePath}/${keyId}`);
|
|
1571
1629
|
}
|
|
1572
1630
|
};
|
|
1631
|
+
//#endregion
|
|
1632
|
+
//#region src/resources/nginx-templates.ts
|
|
1573
1633
|
/**
|
|
1574
1634
|
* Collection of Nginx templates on a server.
|
|
1575
1635
|
*
|
|
@@ -1581,6 +1641,7 @@ var SshKeysCollection = class extends BaseCollection {
|
|
|
1581
1641
|
* ```
|
|
1582
1642
|
*/
|
|
1583
1643
|
var NginxTemplatesCollection = class extends BaseCollection {
|
|
1644
|
+
serverId;
|
|
1584
1645
|
/** @internal */
|
|
1585
1646
|
constructor(client, orgSlug, serverId) {
|
|
1586
1647
|
super(client, orgSlug);
|
|
@@ -1678,6 +1739,8 @@ var NginxTemplatesCollection = class extends BaseCollection {
|
|
|
1678
1739
|
await this.client.delete(`${this.basePath}/${templateId}`);
|
|
1679
1740
|
}
|
|
1680
1741
|
};
|
|
1742
|
+
//#endregion
|
|
1743
|
+
//#region src/resources/servers.ts
|
|
1681
1744
|
/**
|
|
1682
1745
|
* Collection of servers.
|
|
1683
1746
|
*
|
|
@@ -1849,6 +1912,7 @@ var ServersCollection = class extends BaseCollection {
|
|
|
1849
1912
|
* ```
|
|
1850
1913
|
*/
|
|
1851
1914
|
var ServerResource = class extends BaseCollection {
|
|
1915
|
+
serverId;
|
|
1852
1916
|
/** Sites on this server. */
|
|
1853
1917
|
sites;
|
|
1854
1918
|
/** Databases on this server. */
|
|
@@ -1933,6 +1997,8 @@ var ServerResource = class extends BaseCollection {
|
|
|
1933
1997
|
await this.client.delete(`/orgs/${this.orgSlug}/servers/${this.serverId}`);
|
|
1934
1998
|
}
|
|
1935
1999
|
};
|
|
2000
|
+
//#endregion
|
|
2001
|
+
//#region src/resources/recipes.ts
|
|
1936
2002
|
/**
|
|
1937
2003
|
* Collection of recipes.
|
|
1938
2004
|
*
|
|
@@ -2035,6 +2101,8 @@ var RecipesCollection = class extends BaseCollection {
|
|
|
2035
2101
|
await this.client.post(`${this.basePath}/${recipeId}/run`, options);
|
|
2036
2102
|
}
|
|
2037
2103
|
};
|
|
2104
|
+
//#endregion
|
|
2105
|
+
//#region src/forge.ts
|
|
2038
2106
|
/**
|
|
2039
2107
|
* Laravel Forge TypeScript SDK.
|
|
2040
2108
|
*
|
|
@@ -2138,6 +2206,7 @@ var Forge = class {
|
|
|
2138
2206
|
return unwrapDocument$1(await this.client.get("/user"));
|
|
2139
2207
|
}
|
|
2140
2208
|
};
|
|
2209
|
+
//#endregion
|
|
2141
2210
|
export { AsyncPaginatedIterator, BackupsCollection, BaseCollection, CertificatesCollection, CommandsCollection, DaemonsCollection, DatabaseUsersCollection, DatabasesCollection, DeploymentsCollection, FirewallRulesCollection, Forge, MonitorsCollection, NginxTemplatesCollection, RecipesCollection, RedirectRulesCollection, ScheduledJobsCollection, SecurityRulesCollection, ServerResource, ServersCollection, SiteEnvResource, SiteNginxResource, SiteResource, SitesCollection, SshKeysCollection, unwrapDocument, unwrapListDocument, unwrapResource };
|
|
2142
2211
|
|
|
2143
2212
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/pagination.ts","../src/utils/name-matcher.ts","../src/resources/base.ts","../src/resources/deployments.ts","../src/resources/certificates.ts","../src/resources/commands.ts","../src/resources/security-rules.ts","../src/resources/redirect-rules.ts","../src/resources/sites.ts","../src/resources/databases.ts","../src/resources/database-users.ts","../src/resources/daemons.ts","../src/resources/backups.ts","../src/resources/scheduled-jobs.ts","../src/resources/monitors.ts","../src/resources/firewall-rules.ts","../src/resources/ssh-keys.ts","../src/resources/nginx-templates.ts","../src/resources/servers.ts","../src/resources/recipes.ts","../src/forge.ts"],"sourcesContent":["/**\n * Function that fetches a page of results using cursor-based pagination.\n * Pass `null` for the first page, or a cursor string for subsequent pages.\n */\nexport type PageFetcher<T> = (\n cursor: string | null,\n) => Promise<{ items: T[]; nextCursor: string | null }>;\n\n/**\n * Async paginated iterator that auto-fetches all pages using cursor-based pagination.\n *\n * @example\n * ```ts\n * const iter = forge.server(123).site(456).deployments.all();\n * for await (const deployment of iter) {\n * console.log(deployment);\n * }\n *\n * // Or collect all items at once:\n * const deployments = await iter.toArray();\n * ```\n */\nexport class AsyncPaginatedIterator<T> {\n private fetchPage: PageFetcher<T>;\n\n constructor(fetchPage: PageFetcher<T>) {\n this.fetchPage = fetchPage;\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<T, void, undefined> {\n let cursor: string | null = null;\n let hasMore = true;\n\n while (hasMore) {\n const { items, nextCursor } = await this.fetchPage(cursor);\n\n for (const item of items) {\n yield item;\n }\n\n if (nextCursor) {\n cursor = nextCursor;\n } else {\n hasMore = false;\n }\n }\n }\n\n /**\n * Collect all items into an array.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.all().toArray();\n * ```\n */\n async toArray(): Promise<T[]> {\n const items: T[] = [];\n for await (const item of this) {\n items.push(item);\n }\n return items;\n }\n}\n","/**\n * Result of a name matching operation.\n */\nexport interface NameMatch<T> {\n exact: T[];\n partial: T[];\n}\n\n/**\n * Match items by name using case-insensitive exact and partial matching.\n */\nexport function matchByName<T>(\n items: T[],\n query: string,\n getName: (item: T) => string,\n): NameMatch<T> {\n const lower = query.toLowerCase();\n const exact = items.filter((item) => getName(item).toLowerCase() === lower);\n const partial = items.filter((item) => getName(item).toLowerCase().includes(lower));\n return { exact, partial };\n}\n","import type { HttpClient } from \"@studiometa/forge-api\";\n\n/**\n * Abstract base class for resource collections.\n * Provides shared `client` and `orgSlug` properties to avoid duplication across all collection classes.\n */\nexport abstract class BaseCollection {\n protected readonly client: HttpClient;\n protected readonly orgSlug: string;\n\n constructor(client: HttpClient, orgSlug: string) {\n this.client = client;\n this.orgSlug = orgSlug;\n }\n}\n","import type {\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DeploymentAttributes,\n DeploymentOutputAttributes,\n DeploymentScriptAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing deployments.\n */\nexport interface DeploymentListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of deployments for a site.\n *\n * Access via `forge.server(id).site(id).deployments`.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.list();\n * ```\n */\nexport class DeploymentsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments`;\n }\n\n /**\n * List deployments for this site.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).deployments.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DeploymentListOptions = {},\n ): Promise<Array<DeploymentAttributes & { id: number }>> {\n const params = new URLSearchParams({ sort: \"-created_at\" });\n if (options.cursor !== undefined) {\n params.set(\"page[cursor]\", options.cursor);\n }\n const response = await this.client.get<JsonApiListDocument<DeploymentAttributes>>(\n `${this.basePath}?${params.toString()}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all deployments across all pages.\n *\n * @example\n * ```ts\n * for await (const deployment of forge.server(123).site(456).deployments.all()) {\n * console.log(deployment);\n * }\n *\n * // Or collect all at once:\n * const deployments = await forge.server(123).site(456).deployments.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DeploymentAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DeploymentAttributes & { id: number }>(async (cursor) => {\n const params = \"?sort=-created_at\" + (cursor !== null ? `&page[cursor]=${cursor}` : \"\");\n const response = await this.client.get<JsonApiListDocument<DeploymentAttributes>>(\n `${this.basePath}${params}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific deployment.\n *\n * @example\n * ```ts\n * const deployment = await forge.server(123).site(456).deployments.get(789);\n * ```\n */\n async get(deploymentId: number): Promise<DeploymentAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DeploymentAttributes>>(\n `${this.basePath}/${deploymentId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Get the output of a deployment.\n *\n * @example\n * ```ts\n * const output = await forge.server(123).site(456).deployments.output(789);\n * ```\n */\n async output(deploymentId: number): Promise<string> {\n const response = await this.client.get<JsonApiDocument<DeploymentOutputAttributes>>(\n `${this.basePath}/${deploymentId}/output`,\n );\n return unwrapDocument(response).output;\n }\n\n /**\n * Get the deployment script.\n *\n * @example\n * ```ts\n * const script = await forge.server(123).site(456).deployments.script();\n * ```\n */\n async script(): Promise<string> {\n const response = await this.client.get<JsonApiDocument<DeploymentScriptAttributes>>(\n `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments/script`,\n );\n return unwrapDocument(response).content;\n }\n\n /**\n * Update the deployment script.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).deployments.updateScript('npm run build && ...');\n * ```\n */\n async updateScript(content: string): Promise<void> {\n await this.client.put(\n `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments/script`,\n { content },\n );\n }\n}\n","import type {\n CreateCertificateData,\n HttpClient,\n JsonApiDocument,\n CertificateAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * SSL certificates for a site, accessed per-domain.\n *\n * In v2, certificates are a singular sub-resource of a domain:\n * `/orgs/{org}/servers/{server}/sites/{site}/domains/{domain}/certificate`\n *\n * Access via `forge.server(id).site(id).certificates`.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.get(789);\n * ```\n */\nexport class CertificatesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private domainPath(domainId: number): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/domains/${domainId}/certificate`;\n }\n\n /**\n * Get the certificate for a domain.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.get(789);\n * ```\n */\n async get(domainId: number): Promise<CertificateAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<CertificateAttributes>>(\n this.domainPath(domainId),\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a certificate for a domain.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.create(789, {\n * type: 'letsencrypt',\n * });\n * ```\n */\n async create(\n domainId: number,\n data: CreateCertificateData,\n ): Promise<CertificateAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<CertificateAttributes>>(\n this.domainPath(domainId),\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete the certificate for a domain.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).certificates.delete(789);\n * ```\n */\n async delete(domainId: number): Promise<void> {\n await this.client.delete(this.domainPath(domainId));\n }\n\n /**\n * Activate the certificate for a domain.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).certificates.activate(789);\n * ```\n */\n async activate(domainId: number): Promise<void> {\n await this.client.post(`${this.domainPath(domainId)}/actions`, { action: \"activate\" });\n }\n}\n","import type {\n CreateCommandData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n CommandAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing site commands.\n */\nexport interface CommandListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of commands run on a site.\n *\n * Access via `forge.server(id).site(id).commands`.\n *\n * @example\n * ```ts\n * const commands = await forge.server(123).site(456).commands.list();\n * ```\n */\nexport class CommandsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/commands`;\n }\n\n /**\n * List commands run on this site.\n *\n * @example\n * ```ts\n * const commands = await forge.server(123).site(456).commands.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).commands.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: CommandListOptions = {}): Promise<Array<CommandAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<CommandAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all commands across all pages.\n *\n * @example\n * ```ts\n * for await (const command of forge.server(123).site(456).commands.all()) {\n * console.log(command);\n * }\n *\n * // Or collect all at once:\n * const commands = await forge.server(123).site(456).commands.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<CommandAttributes & { id: number }> {\n return new AsyncPaginatedIterator<CommandAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<CommandAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific command.\n *\n * @example\n * ```ts\n * const command = await forge.server(123).site(456).commands.get(789);\n * ```\n */\n async get(commandId: number): Promise<CommandAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<CommandAttributes>>(\n `${this.basePath}/${commandId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Run a command on this site.\n *\n * @example\n * ```ts\n * const command = await forge.server(123).site(456).commands.create({\n * command: 'php artisan migrate',\n * });\n * ```\n */\n async create(data: CreateCommandData): Promise<CommandAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<CommandAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n}\n","import type {\n CreateSecurityRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SecurityRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing security rules.\n */\nexport interface SecurityRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of security rules on a site.\n *\n * Access via `forge.server(id).site(id).securityRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).securityRules.list();\n * ```\n */\nexport class SecurityRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/security-rules`;\n }\n\n /**\n * List security rules on this site.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).securityRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).securityRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: SecurityRuleListOptions = {},\n ): Promise<Array<SecurityRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SecurityRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all security rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).site(456).securityRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).site(456).securityRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SecurityRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SecurityRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SecurityRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific security rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).securityRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<SecurityRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SecurityRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new security rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).securityRules.create({\n * name: 'Admin Area',\n * path: '/admin',\n * credentials: [{ username: 'admin', password: 'secret' }],\n * });\n * ```\n */\n async create(data: CreateSecurityRuleData): Promise<SecurityRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SecurityRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a security rule.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).securityRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateRedirectRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n RedirectRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing redirect rules.\n */\nexport interface RedirectRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of redirect rules on a site.\n *\n * Access via `forge.server(id).site(id).redirectRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).redirectRules.list();\n * ```\n */\nexport class RedirectRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/redirect-rules`;\n }\n\n /**\n * List redirect rules on this site.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).redirectRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).redirectRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: RedirectRuleListOptions = {},\n ): Promise<Array<RedirectRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RedirectRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all redirect rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).site(456).redirectRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).site(456).redirectRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<RedirectRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<RedirectRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RedirectRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific redirect rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).redirectRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<RedirectRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<RedirectRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new redirect rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).redirectRules.create({\n * from: '/old-path',\n * to: '/new-path',\n * type: 'redirect',\n * });\n * ```\n */\n async create(data: CreateRedirectRuleData): Promise<RedirectRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<RedirectRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a redirect rule.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).redirectRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateSiteData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SiteAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\nimport { matchByName } from \"../utils/name-matcher.ts\";\nimport type { ResolveResult } from \"./servers.ts\";\nimport { DeploymentsCollection } from \"./deployments.ts\";\nimport { CertificatesCollection } from \"./certificates.ts\";\nimport { CommandsCollection } from \"./commands.ts\";\nimport { SecurityRulesCollection } from \"./security-rules.ts\";\nimport { RedirectRulesCollection } from \"./redirect-rules.ts\";\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * Options for listing sites.\n */\nexport interface SiteListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of sites on a server.\n *\n * Access via `forge.server(id).sites`.\n *\n * @example\n * ```ts\n * const sites = await forge.server(123).sites.list();\n * ```\n */\nexport class SitesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites`;\n }\n\n /**\n * List sites on this server.\n *\n * @example\n * ```ts\n * const sites = await forge.server(123).sites.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).sites.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: SiteListOptions = {}): Promise<Array<SiteAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SiteAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all sites across all pages.\n *\n * @example\n * ```ts\n * for await (const site of forge.server(123).sites.all()) {\n * console.log(site);\n * }\n *\n * // Or collect all at once:\n * const sites = await forge.server(123).sites.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SiteAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SiteAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SiteAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific site by ID.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).sites.get(456);\n * ```\n */\n async get(siteId: number): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SiteAttributes>>(\n `/orgs/${this.orgSlug}/sites/${siteId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new site on this server.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).sites.create({\n * type: 'php',\n * name: 'example.com',\n * directory: '/public',\n * });\n * ```\n */\n async create(data: CreateSiteData): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SiteAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Update a site.\n *\n * @example\n * ```ts\n * await forge.server(123).sites.update(456, { directory: '/public' });\n * ```\n */\n async update(\n siteId: number,\n data: Partial<CreateSiteData>,\n ): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<SiteAttributes>>(\n `${this.basePath}/${siteId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a site.\n *\n * @example\n * ```ts\n * await forge.server(123).sites.delete(456);\n * ```\n */\n async delete(siteId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${siteId}`);\n }\n\n /**\n * Find sites by domain name using case-insensitive partial matching.\n *\n * If exactly one site matches the query exactly, only that site is returned.\n * Otherwise all partial matches are returned.\n *\n * @param query - The search query to match against site domain names.\n * @returns Resolve result with matching sites.\n *\n * @example\n * ```ts\n * // Find sites matching \"example\"\n * const result = await forge.server(123).sites.resolve('example');\n * // → { query: 'example', matches: [{ id: 456, name: 'example.com' }], total: 1 }\n * ```\n */\n async resolve(query: string): Promise<ResolveResult> {\n const sites = await this.list();\n const { exact, partial } = matchByName(sites, query, (s) => s.name);\n const matches = exact.length === 1 ? exact : partial;\n return {\n query,\n matches: matches.map((s) => ({ id: s.id, name: s.name })),\n total: matches.length,\n };\n }\n}\n\n/**\n * A specific site with nested resources and actions.\n *\n * Access via `forge.server(id).site(id)`.\n *\n * @example\n * ```ts\n * // Deploy\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment\n * const env = await forge.server(123).site(456).env.get();\n * ```\n */\nexport class SiteResource extends BaseCollection {\n /** Deployments for this site. */\n readonly deployments: DeploymentsCollection;\n\n /** SSL certificates for this site. */\n readonly certificates: CertificatesCollection;\n\n /** Environment variables for this site. */\n readonly env: SiteEnvResource;\n\n /** Nginx configuration for this site. */\n readonly nginx: SiteNginxResource;\n\n /** Commands run on this site. */\n readonly commands: CommandsCollection;\n\n /** Security rules for this site. */\n readonly securityRules: SecurityRulesCollection;\n\n /** Redirect rules for this site. */\n readonly redirectRules: RedirectRulesCollection;\n\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n this.deployments = new DeploymentsCollection(client, orgSlug, serverId, siteId);\n this.certificates = new CertificatesCollection(client, orgSlug, serverId, siteId);\n this.env = new SiteEnvResource(client, orgSlug, serverId, siteId);\n this.nginx = new SiteNginxResource(client, orgSlug, serverId, siteId);\n this.commands = new CommandsCollection(client, orgSlug, serverId, siteId);\n this.securityRules = new SecurityRulesCollection(client, orgSlug, serverId, siteId);\n this.redirectRules = new RedirectRulesCollection(client, orgSlug, serverId, siteId);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}`;\n }\n\n /**\n * Get this site's details.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).site(456).get();\n * ```\n */\n async get(): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SiteAttributes>>(\n `/orgs/${this.orgSlug}/sites/${this.siteId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Deploy this site.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).deploy();\n * ```\n */\n async deploy(): Promise<void> {\n await this.client.post(`${this.basePath}/deployments/deploy`);\n }\n\n /**\n * Delete this site.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).delete();\n * ```\n */\n async delete(): Promise<void> {\n await this.client.delete(this.basePath);\n }\n}\n\n/**\n * Environment variables for a site.\n *\n * @example\n * ```ts\n * const env = await forge.server(123).site(456).env.get();\n * await forge.server(123).site(456).env.update('APP_ENV=production\\n...');\n * ```\n */\nexport class SiteEnvResource extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/environment`;\n }\n\n /**\n * Get the environment file content.\n *\n * @returns The .env file content as a string.\n */\n async get(): Promise<string> {\n return this.client.get<string>(this.basePath);\n }\n\n /**\n * Update the environment file content.\n *\n * @param content The full .env file content.\n */\n async update(content: string): Promise<void> {\n await this.client.put(this.basePath, { content });\n }\n}\n\n/**\n * Nginx configuration for a site.\n *\n * @example\n * ```ts\n * const config = await forge.server(123).site(456).nginx.get();\n * await forge.server(123).site(456).nginx.update('server { ... }');\n * ```\n */\nexport class SiteNginxResource extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/nginx`;\n }\n\n /**\n * Get the Nginx configuration.\n *\n * @returns The Nginx config content as a string.\n */\n async get(): Promise<string> {\n return this.client.get<string>(this.basePath);\n }\n\n /**\n * Update the Nginx configuration.\n *\n * @param content The full Nginx config content.\n */\n async update(content: string): Promise<void> {\n await this.client.put(this.basePath, { content });\n }\n}\n","import type {\n CreateDatabaseData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DatabaseAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing databases.\n */\nexport interface DatabaseListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of databases on a server.\n *\n * Access via `forge.server(id).databases`.\n *\n * @example\n * ```ts\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class DatabasesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/schemas`;\n }\n\n /**\n * List databases on this server.\n *\n * @example\n * ```ts\n * const dbs = await forge.server(123).databases.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).databases.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DatabaseListOptions = {},\n ): Promise<Array<DatabaseAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all databases across all pages.\n *\n * @example\n * ```ts\n * for await (const db of forge.server(123).databases.all()) {\n * console.log(db);\n * }\n *\n * // Or collect all at once:\n * const dbs = await forge.server(123).databases.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DatabaseAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DatabaseAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific database.\n *\n * @example\n * ```ts\n * const db = await forge.server(123).databases.get(789);\n * ```\n */\n async get(databaseId: number): Promise<DatabaseAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DatabaseAttributes>>(\n `${this.basePath}/${databaseId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new database.\n *\n * @example\n * ```ts\n * const db = await forge.server(123).databases.create({\n * name: 'myapp',\n * user: 'admin',\n * password: 'secret',\n * });\n * ```\n */\n async create(data: CreateDatabaseData): Promise<DatabaseAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<DatabaseAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a database.\n *\n * @example\n * ```ts\n * await forge.server(123).databases.delete(789);\n * ```\n */\n async delete(databaseId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${databaseId}`);\n }\n}\n","import type {\n CreateDatabaseUserData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DatabaseUserAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing database users.\n */\nexport interface DatabaseUserListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of database users on a server.\n *\n * Access via `forge.server(id).databaseUsers`.\n *\n * @example\n * ```ts\n * const users = await forge.server(123).databaseUsers.list();\n * ```\n */\nexport class DatabaseUsersCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/users`;\n }\n\n /**\n * List database users on this server.\n *\n * @example\n * ```ts\n * const users = await forge.server(123).databaseUsers.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).databaseUsers.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DatabaseUserListOptions = {},\n ): Promise<Array<DatabaseUserAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseUserAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all database users across all pages.\n *\n * @example\n * ```ts\n * for await (const user of forge.server(123).databaseUsers.all()) {\n * console.log(user);\n * }\n *\n * // Or collect all at once:\n * const users = await forge.server(123).databaseUsers.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DatabaseUserAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DatabaseUserAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseUserAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific database user.\n *\n * @example\n * ```ts\n * const user = await forge.server(123).databaseUsers.get(789);\n * ```\n */\n async get(userId: number): Promise<DatabaseUserAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DatabaseUserAttributes>>(\n `${this.basePath}/${userId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new database user.\n *\n * @example\n * ```ts\n * const user = await forge.server(123).databaseUsers.create({\n * name: 'forge',\n * password: 'secret',\n * databases: [1, 2],\n * });\n * ```\n */\n async create(data: CreateDatabaseUserData): Promise<DatabaseUserAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<DatabaseUserAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a database user.\n *\n * @example\n * ```ts\n * await forge.server(123).databaseUsers.delete(789);\n * ```\n */\n async delete(userId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${userId}`);\n }\n}\n","import type {\n CreateDaemonData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n BackgroundProcessAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing daemons.\n */\nexport interface DaemonListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of daemons (background processes) on a server.\n *\n * Access via `forge.server(id).daemons`.\n *\n * @example\n * ```ts\n * const daemons = await forge.server(123).daemons.list();\n * ```\n */\nexport class DaemonsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/background-processes`;\n }\n\n /**\n * List daemons on this server.\n *\n * @example\n * ```ts\n * const daemons = await forge.server(123).daemons.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).daemons.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DaemonListOptions = {},\n ): Promise<Array<BackgroundProcessAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackgroundProcessAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all daemons across all pages.\n *\n * @example\n * ```ts\n * for await (const daemon of forge.server(123).daemons.all()) {\n * console.log(daemon);\n * }\n *\n * // Or collect all at once:\n * const daemons = await forge.server(123).daemons.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<BackgroundProcessAttributes & { id: number }> {\n return new AsyncPaginatedIterator<BackgroundProcessAttributes & { id: number }>(\n async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackgroundProcessAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n },\n );\n }\n\n /**\n * Get a specific daemon.\n *\n * @example\n * ```ts\n * const daemon = await forge.server(123).daemons.get(789);\n * ```\n */\n async get(daemonId: number): Promise<BackgroundProcessAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<BackgroundProcessAttributes>>(\n `${this.basePath}/${daemonId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new daemon.\n *\n * @example\n * ```ts\n * const daemon = await forge.server(123).daemons.create({\n * command: 'php artisan queue:work',\n * user: 'forge',\n * });\n * ```\n */\n async create(data: CreateDaemonData): Promise<BackgroundProcessAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<BackgroundProcessAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a daemon.\n *\n * @example\n * ```ts\n * await forge.server(123).daemons.delete(789);\n * ```\n */\n async delete(daemonId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${daemonId}`);\n }\n\n /**\n * Restart a daemon.\n *\n * @example\n * ```ts\n * await forge.server(123).daemons.restart(789);\n * ```\n */\n async restart(daemonId: number): Promise<void> {\n await this.client.post(`${this.basePath}/${daemonId}/restart`);\n }\n}\n","import type {\n CreateBackupConfigData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n BackupConfigAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing backup configurations.\n */\nexport interface BackupConfigListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of backup configurations on a server.\n *\n * Access via `forge.server(id).backups`.\n *\n * @example\n * ```ts\n * const backups = await forge.server(123).backups.list();\n * ```\n */\nexport class BackupsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/backups`;\n }\n\n /**\n * List backup configurations on this server.\n *\n * @example\n * ```ts\n * const backups = await forge.server(123).backups.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).backups.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: BackupConfigListOptions = {},\n ): Promise<Array<BackupConfigAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackupConfigAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all backup configurations across all pages.\n *\n * @example\n * ```ts\n * for await (const backup of forge.server(123).backups.all()) {\n * console.log(backup);\n * }\n *\n * // Or collect all at once:\n * const backups = await forge.server(123).backups.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<BackupConfigAttributes & { id: number }> {\n return new AsyncPaginatedIterator<BackupConfigAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackupConfigAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific backup configuration.\n *\n * @example\n * ```ts\n * const backup = await forge.server(123).backups.get(789);\n * ```\n */\n async get(backupId: number): Promise<BackupConfigAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<BackupConfigAttributes>>(\n `${this.basePath}/${backupId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new backup configuration.\n *\n * @example\n * ```ts\n * const backup = await forge.server(123).backups.create({\n * provider: 's3',\n * credentials: { key: 'ACCESS_KEY', secret: 'SECRET_KEY', region: 'us-east-1', bucket: 'my-bucket' },\n * frequency: 'weekly',\n * retention: 7,\n * databases: [1, 2],\n * });\n * ```\n */\n async create(data: CreateBackupConfigData): Promise<BackupConfigAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<BackupConfigAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a backup configuration.\n *\n * @example\n * ```ts\n * await forge.server(123).backups.delete(789);\n * ```\n */\n async delete(backupId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${backupId}`);\n }\n}\n","import type {\n CreateScheduledJobData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n ScheduledJobAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing scheduled jobs.\n */\nexport interface ScheduledJobListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of scheduled jobs (cron jobs) on a server.\n *\n * Access via `forge.server(id).scheduledJobs`.\n *\n * @example\n * ```ts\n * const jobs = await forge.server(123).scheduledJobs.list();\n * ```\n */\nexport class ScheduledJobsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/scheduled-jobs`;\n }\n\n /**\n * List scheduled jobs on this server.\n *\n * @example\n * ```ts\n * const jobs = await forge.server(123).scheduledJobs.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).scheduledJobs.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: ScheduledJobListOptions = {},\n ): Promise<Array<ScheduledJobAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ScheduledJobAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all scheduled jobs across all pages.\n *\n * @example\n * ```ts\n * for await (const job of forge.server(123).scheduledJobs.all()) {\n * console.log(job);\n * }\n *\n * // Or collect all at once:\n * const jobs = await forge.server(123).scheduledJobs.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<ScheduledJobAttributes & { id: number }> {\n return new AsyncPaginatedIterator<ScheduledJobAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ScheduledJobAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific scheduled job.\n *\n * @example\n * ```ts\n * const job = await forge.server(123).scheduledJobs.get(789);\n * ```\n */\n async get(jobId: number): Promise<ScheduledJobAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ScheduledJobAttributes>>(\n `${this.basePath}/${jobId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new scheduled job.\n *\n * @example\n * ```ts\n * const job = await forge.server(123).scheduledJobs.create({\n * command: 'php /home/forge/artisan schedule:run',\n * user: 'forge',\n * frequency: 'minutely',\n * });\n * ```\n */\n async create(data: CreateScheduledJobData): Promise<ScheduledJobAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<ScheduledJobAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a scheduled job.\n *\n * @example\n * ```ts\n * await forge.server(123).scheduledJobs.delete(789);\n * ```\n */\n async delete(jobId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${jobId}`);\n }\n}\n","import type {\n CreateMonitorData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n MonitorAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing monitors.\n */\nexport interface MonitorListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of server monitors.\n *\n * Access via `forge.server(id).monitors`.\n *\n * @example\n * ```ts\n * const monitors = await forge.server(123).monitors.list();\n * ```\n */\nexport class MonitorsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/monitors`;\n }\n\n /**\n * List monitors on this server.\n *\n * @example\n * ```ts\n * const monitors = await forge.server(123).monitors.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).monitors.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: MonitorListOptions = {}): Promise<Array<MonitorAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<MonitorAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all monitors across all pages.\n *\n * @example\n * ```ts\n * for await (const monitor of forge.server(123).monitors.all()) {\n * console.log(monitor);\n * }\n *\n * // Or collect all at once:\n * const monitors = await forge.server(123).monitors.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<MonitorAttributes & { id: number }> {\n return new AsyncPaginatedIterator<MonitorAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<MonitorAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific monitor.\n *\n * @example\n * ```ts\n * const monitor = await forge.server(123).monitors.get(789);\n * ```\n */\n async get(monitorId: number): Promise<MonitorAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<MonitorAttributes>>(\n `${this.basePath}/${monitorId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new monitor.\n *\n * @example\n * ```ts\n * const monitor = await forge.server(123).monitors.create({\n * type: 'cpu_load',\n * operator: 'gte',\n * threshold: 80,\n * minutes: 5,\n * });\n * ```\n */\n async create(data: CreateMonitorData): Promise<MonitorAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<MonitorAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a monitor.\n *\n * @example\n * ```ts\n * await forge.server(123).monitors.delete(789);\n * ```\n */\n async delete(monitorId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${monitorId}`);\n }\n}\n","import type {\n CreateFirewallRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n FirewallRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing firewall rules.\n */\nexport interface FirewallRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of firewall rules on a server.\n *\n * Access via `forge.server(id).firewallRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).firewallRules.list();\n * ```\n */\nexport class FirewallRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/firewall-rules`;\n }\n\n /**\n * List firewall rules on this server.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).firewallRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).firewallRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: FirewallRuleListOptions = {},\n ): Promise<Array<FirewallRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<FirewallRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all firewall rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).firewallRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).firewallRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<FirewallRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<FirewallRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<FirewallRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific firewall rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).firewallRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<FirewallRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<FirewallRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new firewall rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).firewallRules.create({\n * name: 'Allow HTTP',\n * port: 80,\n * type: 'allow',\n * });\n * ```\n */\n async create(data: CreateFirewallRuleData): Promise<FirewallRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<FirewallRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a firewall rule.\n *\n * @example\n * ```ts\n * await forge.server(123).firewallRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateSshKeyData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SshKeyAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing SSH keys.\n */\nexport interface SshKeyListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of SSH keys on a server.\n *\n * Access via `forge.server(id).sshKeys`.\n *\n * @example\n * ```ts\n * const keys = await forge.server(123).sshKeys.list();\n * ```\n */\nexport class SshKeysCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/ssh-keys`;\n }\n\n /**\n * List SSH keys on this server.\n *\n * @example\n * ```ts\n * const keys = await forge.server(123).sshKeys.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).sshKeys.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: SshKeyListOptions = {}): Promise<Array<SshKeyAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SshKeyAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all SSH keys across all pages.\n *\n * @example\n * ```ts\n * for await (const key of forge.server(123).sshKeys.all()) {\n * console.log(key);\n * }\n *\n * // Or collect all at once:\n * const keys = await forge.server(123).sshKeys.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SshKeyAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SshKeyAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SshKeyAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific SSH key.\n *\n * @example\n * ```ts\n * const key = await forge.server(123).sshKeys.get(789);\n * ```\n */\n async get(keyId: number): Promise<SshKeyAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SshKeyAttributes>>(\n `${this.basePath}/${keyId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new SSH key.\n *\n * @example\n * ```ts\n * const key = await forge.server(123).sshKeys.create({\n * name: 'deploy-key',\n * key: 'ssh-rsa AAAA...',\n * });\n * ```\n */\n async create(data: CreateSshKeyData): Promise<SshKeyAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SshKeyAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Delete an SSH key.\n *\n * @example\n * ```ts\n * await forge.server(123).sshKeys.delete(789);\n * ```\n */\n async delete(keyId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${keyId}`);\n }\n}\n","import type {\n CreateNginxTemplateData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n NginxTemplateAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing Nginx templates.\n */\nexport interface NginxTemplateListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of Nginx templates on a server.\n *\n * Access via `forge.server(id).nginxTemplates`.\n *\n * @example\n * ```ts\n * const templates = await forge.server(123).nginxTemplates.list();\n * ```\n */\nexport class NginxTemplatesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/nginx/templates`;\n }\n\n /**\n * List Nginx templates on this server.\n *\n * @example\n * ```ts\n * const templates = await forge.server(123).nginxTemplates.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).nginxTemplates.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: NginxTemplateListOptions = {},\n ): Promise<Array<NginxTemplateAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<NginxTemplateAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all Nginx templates across all pages.\n *\n * @example\n * ```ts\n * for await (const template of forge.server(123).nginxTemplates.all()) {\n * console.log(template);\n * }\n *\n * // Or collect all at once:\n * const templates = await forge.server(123).nginxTemplates.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<NginxTemplateAttributes & { id: number }> {\n return new AsyncPaginatedIterator<NginxTemplateAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<NginxTemplateAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.get(789);\n * ```\n */\n async get(templateId: number): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<NginxTemplateAttributes>>(\n `${this.basePath}/${templateId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.create({\n * name: 'Laravel Template',\n * content: 'server { ... }',\n * });\n * ```\n */\n async create(data: CreateNginxTemplateData): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<NginxTemplateAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Update an existing Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.update(789, {\n * name: 'Updated Template',\n * content: 'server { ... }',\n * });\n * ```\n */\n async update(\n templateId: number,\n data: Partial<CreateNginxTemplateData>,\n ): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<NginxTemplateAttributes>>(\n `${this.basePath}/${templateId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a Nginx template.\n *\n * @example\n * ```ts\n * await forge.server(123).nginxTemplates.delete(789);\n * ```\n */\n async delete(templateId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${templateId}`);\n }\n}\n","import type {\n CreateServerData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n ServerAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\nimport { matchByName } from \"../utils/name-matcher.ts\";\nimport { SitesCollection, SiteResource } from \"./sites.ts\";\nimport { DatabasesCollection } from \"./databases.ts\";\nimport { DatabaseUsersCollection } from \"./database-users.ts\";\nimport { DaemonsCollection } from \"./daemons.ts\";\nimport { BackupsCollection } from \"./backups.ts\";\nimport { ScheduledJobsCollection } from \"./scheduled-jobs.ts\";\nimport { MonitorsCollection } from \"./monitors.ts\";\nimport { FirewallRulesCollection } from \"./firewall-rules.ts\";\nimport { SshKeysCollection } from \"./ssh-keys.ts\";\nimport { NginxTemplatesCollection } from \"./nginx-templates.ts\";\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * A matched resource item with ID and name.\n */\nexport interface ResolveMatch {\n id: number;\n name: string;\n}\n\n/**\n * Result of a resolve operation.\n */\nexport interface ResolveResult {\n query: string;\n matches: ResolveMatch[];\n total: number;\n}\n\n/**\n * Options for listing servers.\n */\nexport interface ServerListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of servers.\n *\n * Access via `forge.servers`.\n *\n * @example\n * ```ts\n * // List all servers\n * const servers = await forge.servers.list();\n *\n * // Get a specific server\n * const server = await forge.servers.get(123);\n *\n * // Create a new server\n * const server = await forge.servers.create({ ... });\n * ```\n */\nexport class ServersCollection extends BaseCollection {\n /** @internal */\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers`;\n }\n\n /**\n * List servers.\n *\n * @example\n * ```ts\n * const servers = await forge.servers.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.servers.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: ServerListOptions = {}): Promise<Array<ServerAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ServerAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all servers across all pages.\n *\n * @example\n * ```ts\n * for await (const server of forge.servers.all()) {\n * console.log(server);\n * }\n *\n * // Or collect all at once:\n * const servers = await forge.servers.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<ServerAttributes & { id: number }> {\n return new AsyncPaginatedIterator<ServerAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ServerAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific server by ID.\n *\n * @example\n * ```ts\n * const server = await forge.servers.get(123);\n * ```\n */\n async get(serverId: number): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(\n `${this.basePath}/${serverId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new server.\n *\n * @example\n * ```ts\n * const server = await forge.servers.create({\n * provider: 'ocean2',\n * credential_id: 1,\n * name: 'web-1',\n * type: 'app',\n * size: '01',\n * region: 'ams3',\n * });\n * ```\n */\n async create(data: CreateServerData): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<ServerAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Update a server.\n *\n * @example\n * ```ts\n * await forge.servers.update(123, { name: 'web-1-renamed' });\n * ```\n */\n async update(\n serverId: number,\n data: Partial<CreateServerData>,\n ): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<ServerAttributes>>(\n `${this.basePath}/${serverId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a server.\n *\n * @example\n * ```ts\n * await forge.servers.delete(123);\n * ```\n */\n async delete(serverId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${serverId}`);\n }\n\n /**\n * Reboot a server.\n *\n * @example\n * ```ts\n * await forge.servers.reboot(123);\n * ```\n */\n async reboot(serverId: number): Promise<void> {\n await this.client.post(`${this.basePath}/${serverId}/reboot`);\n }\n\n /**\n * Find servers by name using case-insensitive partial matching.\n *\n * If exactly one server matches the query exactly, only that server is returned.\n * Otherwise all partial matches are returned.\n *\n * @param query - The search query to match against server names.\n * @returns Resolve result with matching servers.\n *\n * @example\n * ```ts\n * // Find servers matching \"prod\"\n * const result = await forge.servers.resolve('prod');\n * // → { query: 'prod', matches: [{ id: 725393, name: 'wilo-grove-prod' }], total: 1 }\n *\n * // Use the result to access a server\n * if (result.total === 1) {\n * const sites = await forge.server(result.matches[0].id).sites.list();\n * }\n * ```\n */\n async resolve(query: string): Promise<ResolveResult> {\n const servers = await this.list();\n const { exact, partial } = matchByName(servers, query, (s) => s.name);\n const matches = exact.length === 1 ? exact : partial;\n return {\n query,\n matches: matches.map((s) => ({ id: s.id, name: s.name })),\n total: matches.length,\n };\n }\n}\n\n/**\n * A specific server with nested resources.\n *\n * Access via `forge.server(id)`.\n *\n * @example\n * ```ts\n * // Access sites on a server\n * const sites = await forge.server(123).sites.list();\n *\n * // Access databases on a server\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class ServerResource extends BaseCollection {\n /** Sites on this server. */\n readonly sites: SitesCollection;\n\n /** Databases on this server. */\n readonly databases: DatabasesCollection;\n\n /** Database users on this server. */\n readonly databaseUsers: DatabaseUsersCollection;\n\n /** Daemons (background processes) on this server. */\n readonly daemons: DaemonsCollection;\n\n /** Backup configurations on this server. */\n readonly backups: BackupsCollection;\n\n /** Scheduled jobs (cron jobs) on this server. */\n readonly scheduledJobs: ScheduledJobsCollection;\n\n /** Monitors on this server. */\n readonly monitors: MonitorsCollection;\n\n /** Firewall rules on this server. */\n readonly firewallRules: FirewallRulesCollection;\n\n /** SSH keys on this server. */\n readonly sshKeys: SshKeysCollection;\n\n /** Nginx templates on this server. */\n readonly nginxTemplates: NginxTemplatesCollection;\n\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n this.sites = new SitesCollection(client, orgSlug, serverId);\n this.databases = new DatabasesCollection(client, orgSlug, serverId);\n this.databaseUsers = new DatabaseUsersCollection(client, orgSlug, serverId);\n this.daemons = new DaemonsCollection(client, orgSlug, serverId);\n this.backups = new BackupsCollection(client, orgSlug, serverId);\n this.scheduledJobs = new ScheduledJobsCollection(client, orgSlug, serverId);\n this.monitors = new MonitorsCollection(client, orgSlug, serverId);\n this.firewallRules = new FirewallRulesCollection(client, orgSlug, serverId);\n this.sshKeys = new SshKeysCollection(client, orgSlug, serverId);\n this.nginxTemplates = new NginxTemplatesCollection(client, orgSlug, serverId);\n }\n\n /**\n * Access a specific site on this server, with nested resources.\n *\n * @example\n * ```ts\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment variables\n * const env = await forge.server(123).site(456).env.get();\n * ```\n */\n site(siteId: number): SiteResource {\n return new SiteResource(this.client, this.orgSlug, this.serverId, siteId);\n }\n\n /**\n * Get this server's details.\n *\n * @example\n * ```ts\n * const server = await forge.server(123).get();\n * ```\n */\n async get(): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(\n `/orgs/${this.orgSlug}/servers/${this.serverId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Reboot this server.\n *\n * @example\n * ```ts\n * await forge.server(123).reboot();\n * ```\n */\n async reboot(): Promise<void> {\n await this.client.post(`/orgs/${this.orgSlug}/servers/${this.serverId}/reboot`);\n }\n\n /**\n * Delete this server.\n *\n * @example\n * ```ts\n * await forge.server(123).delete();\n * ```\n */\n async delete(): Promise<void> {\n await this.client.delete(`/orgs/${this.orgSlug}/servers/${this.serverId}`);\n }\n}\n","import type {\n CreateRecipeData,\n JsonApiDocument,\n JsonApiListDocument,\n RecipeAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing recipes.\n */\nexport interface RecipeListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Options for running a recipe.\n */\nexport interface RunRecipeOptions {\n /** Server IDs to run the recipe on. */\n servers: number[];\n}\n\n/**\n * Collection of recipes.\n *\n * Access via `forge.recipes`.\n *\n * @example\n * ```ts\n * const recipes = await forge.recipes.list();\n * ```\n */\nexport class RecipesCollection extends BaseCollection {\n /** @internal */\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/recipes`;\n }\n\n /**\n * List all recipes.\n *\n * @example\n * ```ts\n * const recipes = await forge.recipes.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.recipes.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: RecipeListOptions = {}): Promise<Array<RecipeAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RecipeAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all recipes across all pages.\n *\n * @example\n * ```ts\n * for await (const recipe of forge.recipes.all()) {\n * console.log(recipe);\n * }\n *\n * // Or collect all at once:\n * const recipes = await forge.recipes.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<RecipeAttributes & { id: number }> {\n return new AsyncPaginatedIterator<RecipeAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RecipeAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific recipe.\n *\n * @example\n * ```ts\n * const recipe = await forge.recipes.get(789);\n * ```\n */\n async get(recipeId: number): Promise<RecipeAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<RecipeAttributes>>(\n `${this.basePath}/${recipeId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new recipe.\n *\n * @example\n * ```ts\n * const recipe = await forge.recipes.create({\n * name: 'Install Node',\n * user: 'root',\n * script: 'curl -fsSL https://deb.nodesource.com/setup_20.x | bash -',\n * });\n * ```\n */\n async create(data: CreateRecipeData): Promise<RecipeAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<RecipeAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Delete a recipe.\n *\n * @example\n * ```ts\n * await forge.recipes.delete(789);\n * ```\n */\n async delete(recipeId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${recipeId}`);\n }\n\n /**\n * Run a recipe on one or more servers.\n *\n * @example\n * ```ts\n * await forge.recipes.run(789, { servers: [123, 456] });\n * ```\n */\n async run(recipeId: number, options: RunRecipeOptions): Promise<void> {\n await this.client.post(`${this.basePath}/${recipeId}/run`, options);\n }\n}\n","import type { ForgeOptions, JsonApiDocument, UserAttributes } from \"@studiometa/forge-api\";\n\nimport { HttpClient, unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { ServersCollection, ServerResource } from \"./resources/servers.ts\";\nimport { RecipesCollection } from \"./resources/recipes.ts\";\n\n/**\n * Laravel Forge TypeScript SDK.\n *\n * Provides a fluent, chainable API for managing Laravel Forge servers,\n * sites, deployments, and more.\n *\n * @example\n * ```ts\n * import { Forge } from '@studiometa/forge-sdk';\n *\n * const forge = new Forge('your-api-token', 'my-org');\n *\n * // List all servers\n * const servers = await forge.servers.list();\n *\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment variables\n * const env = await forge.server(123).site(456).env.get();\n *\n * // Manage databases\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class Forge {\n /** @internal */\n readonly client: HttpClient;\n\n /** The organization slug used for v2 API URL prefixing. */\n readonly organizationSlug: string;\n\n /** Server operations (list, get, create, update, delete, reboot). */\n readonly servers: ServersCollection;\n\n /** Recipe operations (list, get, create, delete, run). */\n readonly recipes: RecipesCollection;\n\n /**\n * Create a new Forge SDK instance.\n *\n * @param token Your Laravel Forge API token.\n * @param organizationSlug Your organization slug (used for v2 API URLs).\n * @param options Optional configuration (custom fetch, base URL, rate limiting).\n *\n * @example\n * ```ts\n * // Basic usage\n * const forge = new Forge('your-api-token', 'my-org');\n *\n * // With custom options\n * const forge = new Forge('your-api-token', 'my-org', {\n * baseUrl: 'https://forge.laravel.com/api/v2',\n * });\n *\n * // With mock fetch for testing\n * const forge = new Forge('test-token', 'test-org', { fetch: mockFetch });\n * ```\n */\n constructor(token: string, organizationSlug: string, options?: ForgeOptions) {\n this.client = new HttpClient({ token, ...options });\n this.organizationSlug = organizationSlug;\n this.servers = new ServersCollection(this.client, organizationSlug);\n this.recipes = new RecipesCollection(this.client, organizationSlug);\n }\n\n /**\n * Access a specific server by ID, with nested resources.\n *\n * Returns a `ServerResource` that provides access to sites, databases,\n * daemons, and other server-level resources.\n *\n * @param serverId The server ID.\n *\n * @example\n * ```ts\n * // List sites on a server\n * const sites = await forge.server(123).sites.list();\n *\n * // Access a specific site\n * const site = await forge.server(123).site(456);\n *\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Manage databases\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\n server(serverId: number): ServerResource {\n return new ServerResource(this.client, this.organizationSlug, serverId);\n }\n\n /**\n * Get the currently authenticated user.\n *\n * @example\n * ```ts\n * const user = await forge.user();\n * console.log(user.name, user.email);\n * ```\n */\n async user(): Promise<UserAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<UserAttributes>>(\"/user\");\n return unwrapDocument(response);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/pagination.ts","../src/utils/name-matcher.ts","../src/resources/base.ts","../src/resources/deployments.ts","../src/resources/certificates.ts","../src/resources/commands.ts","../src/resources/security-rules.ts","../src/resources/redirect-rules.ts","../src/resources/sites.ts","../src/resources/databases.ts","../src/resources/database-users.ts","../src/resources/daemons.ts","../src/resources/backups.ts","../src/resources/scheduled-jobs.ts","../src/resources/monitors.ts","../src/resources/firewall-rules.ts","../src/resources/ssh-keys.ts","../src/resources/nginx-templates.ts","../src/resources/servers.ts","../src/resources/recipes.ts","../src/forge.ts"],"sourcesContent":["/**\n * Function that fetches a page of results using cursor-based pagination.\n * Pass `null` for the first page, or a cursor string for subsequent pages.\n */\nexport type PageFetcher<T> = (\n cursor: string | null,\n) => Promise<{ items: T[]; nextCursor: string | null }>;\n\n/**\n * Async paginated iterator that auto-fetches all pages using cursor-based pagination.\n *\n * @example\n * ```ts\n * const iter = forge.server(123).site(456).deployments.all();\n * for await (const deployment of iter) {\n * console.log(deployment);\n * }\n *\n * // Or collect all items at once:\n * const deployments = await iter.toArray();\n * ```\n */\nexport class AsyncPaginatedIterator<T> {\n private fetchPage: PageFetcher<T>;\n\n constructor(fetchPage: PageFetcher<T>) {\n this.fetchPage = fetchPage;\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<T, void, undefined> {\n let cursor: string | null = null;\n let hasMore = true;\n\n while (hasMore) {\n const { items, nextCursor } = await this.fetchPage(cursor);\n\n for (const item of items) {\n yield item;\n }\n\n if (nextCursor) {\n cursor = nextCursor;\n } else {\n hasMore = false;\n }\n }\n }\n\n /**\n * Collect all items into an array.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.all().toArray();\n * ```\n */\n async toArray(): Promise<T[]> {\n const items: T[] = [];\n for await (const item of this) {\n items.push(item);\n }\n return items;\n }\n}\n","/**\n * Result of a name matching operation.\n */\nexport interface NameMatch<T> {\n exact: T[];\n partial: T[];\n}\n\n/**\n * Match items by name using case-insensitive exact and partial matching.\n */\nexport function matchByName<T>(\n items: T[],\n query: string,\n getName: (item: T) => string,\n): NameMatch<T> {\n const lower = query.toLowerCase();\n const exact = items.filter((item) => getName(item).toLowerCase() === lower);\n const partial = items.filter((item) => getName(item).toLowerCase().includes(lower));\n return { exact, partial };\n}\n","import type { HttpClient } from \"@studiometa/forge-api\";\n\n/**\n * Abstract base class for resource collections.\n * Provides shared `client` and `orgSlug` properties to avoid duplication across all collection classes.\n */\nexport abstract class BaseCollection {\n protected readonly client: HttpClient;\n protected readonly orgSlug: string;\n\n constructor(client: HttpClient, orgSlug: string) {\n this.client = client;\n this.orgSlug = orgSlug;\n }\n}\n","import type {\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DeploymentAttributes,\n DeploymentOutputAttributes,\n DeploymentScriptAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing deployments.\n */\nexport interface DeploymentListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of deployments for a site.\n *\n * Access via `forge.server(id).site(id).deployments`.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.list();\n * ```\n */\nexport class DeploymentsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments`;\n }\n\n /**\n * List deployments for this site.\n *\n * @example\n * ```ts\n * const deployments = await forge.server(123).site(456).deployments.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).deployments.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DeploymentListOptions = {},\n ): Promise<Array<DeploymentAttributes & { id: number }>> {\n const params = new URLSearchParams({ sort: \"-created_at\" });\n if (options.cursor !== undefined) {\n params.set(\"page[cursor]\", options.cursor);\n }\n const response = await this.client.get<JsonApiListDocument<DeploymentAttributes>>(\n `${this.basePath}?${params.toString()}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all deployments across all pages.\n *\n * @example\n * ```ts\n * for await (const deployment of forge.server(123).site(456).deployments.all()) {\n * console.log(deployment);\n * }\n *\n * // Or collect all at once:\n * const deployments = await forge.server(123).site(456).deployments.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DeploymentAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DeploymentAttributes & { id: number }>(async (cursor) => {\n const params = \"?sort=-created_at\" + (cursor !== null ? `&page[cursor]=${cursor}` : \"\");\n const response = await this.client.get<JsonApiListDocument<DeploymentAttributes>>(\n `${this.basePath}${params}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific deployment.\n *\n * @example\n * ```ts\n * const deployment = await forge.server(123).site(456).deployments.get(789);\n * ```\n */\n async get(deploymentId: number): Promise<DeploymentAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DeploymentAttributes>>(\n `${this.basePath}/${deploymentId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Get the output of a deployment.\n *\n * @example\n * ```ts\n * const output = await forge.server(123).site(456).deployments.output(789);\n * ```\n */\n async output(deploymentId: number): Promise<string> {\n const response = await this.client.get<JsonApiDocument<DeploymentOutputAttributes>>(\n `${this.basePath}/${deploymentId}/output`,\n );\n return unwrapDocument(response).output;\n }\n\n /**\n * Get the deployment script.\n *\n * @example\n * ```ts\n * const script = await forge.server(123).site(456).deployments.script();\n * ```\n */\n async script(): Promise<string> {\n const response = await this.client.get<JsonApiDocument<DeploymentScriptAttributes>>(\n `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments/script`,\n );\n return unwrapDocument(response).content;\n }\n\n /**\n * Update the deployment script.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).deployments.updateScript('npm run build && ...');\n * ```\n */\n async updateScript(content: string): Promise<void> {\n await this.client.put(\n `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/deployments/script`,\n { content },\n );\n }\n}\n","import type {\n CreateCertificateData,\n HttpClient,\n JsonApiDocument,\n CertificateAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * SSL certificates for a site, accessed per-domain.\n *\n * In v2, certificates are a singular sub-resource of a domain:\n * `/orgs/{org}/servers/{server}/sites/{site}/domains/{domain}/certificate`\n *\n * Access via `forge.server(id).site(id).certificates`.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.get(789);\n * ```\n */\nexport class CertificatesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private domainPath(domainId: number): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/domains/${domainId}/certificate`;\n }\n\n /**\n * Get the certificate for a domain.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.get(789);\n * ```\n */\n async get(domainId: number): Promise<CertificateAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<CertificateAttributes>>(\n this.domainPath(domainId),\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a certificate for a domain.\n *\n * @example\n * ```ts\n * const cert = await forge.server(123).site(456).certificates.create(789, {\n * type: 'letsencrypt',\n * });\n * ```\n */\n async create(\n domainId: number,\n data: CreateCertificateData,\n ): Promise<CertificateAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<CertificateAttributes>>(\n this.domainPath(domainId),\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete the certificate for a domain.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).certificates.delete(789);\n * ```\n */\n async delete(domainId: number): Promise<void> {\n await this.client.delete(this.domainPath(domainId));\n }\n\n /**\n * Activate the certificate for a domain.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).certificates.activate(789);\n * ```\n */\n async activate(domainId: number): Promise<void> {\n await this.client.post(`${this.domainPath(domainId)}/actions`, { action: \"activate\" });\n }\n}\n","import type {\n CreateCommandData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n CommandAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing site commands.\n */\nexport interface CommandListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of commands run on a site.\n *\n * Access via `forge.server(id).site(id).commands`.\n *\n * @example\n * ```ts\n * const commands = await forge.server(123).site(456).commands.list();\n * ```\n */\nexport class CommandsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/commands`;\n }\n\n /**\n * List commands run on this site.\n *\n * @example\n * ```ts\n * const commands = await forge.server(123).site(456).commands.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).commands.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: CommandListOptions = {}): Promise<Array<CommandAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<CommandAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all commands across all pages.\n *\n * @example\n * ```ts\n * for await (const command of forge.server(123).site(456).commands.all()) {\n * console.log(command);\n * }\n *\n * // Or collect all at once:\n * const commands = await forge.server(123).site(456).commands.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<CommandAttributes & { id: number }> {\n return new AsyncPaginatedIterator<CommandAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<CommandAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific command.\n *\n * @example\n * ```ts\n * const command = await forge.server(123).site(456).commands.get(789);\n * ```\n */\n async get(commandId: number): Promise<CommandAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<CommandAttributes>>(\n `${this.basePath}/${commandId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Run a command on this site.\n *\n * @example\n * ```ts\n * const command = await forge.server(123).site(456).commands.create({\n * command: 'php artisan migrate',\n * });\n * ```\n */\n async create(data: CreateCommandData): Promise<CommandAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<CommandAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n}\n","import type {\n CreateSecurityRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SecurityRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing security rules.\n */\nexport interface SecurityRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of security rules on a site.\n *\n * Access via `forge.server(id).site(id).securityRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).securityRules.list();\n * ```\n */\nexport class SecurityRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/security-rules`;\n }\n\n /**\n * List security rules on this site.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).securityRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).securityRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: SecurityRuleListOptions = {},\n ): Promise<Array<SecurityRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SecurityRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all security rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).site(456).securityRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).site(456).securityRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SecurityRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SecurityRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SecurityRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific security rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).securityRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<SecurityRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SecurityRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new security rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).securityRules.create({\n * name: 'Admin Area',\n * path: '/admin',\n * credentials: [{ username: 'admin', password: 'secret' }],\n * });\n * ```\n */\n async create(data: CreateSecurityRuleData): Promise<SecurityRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SecurityRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a security rule.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).securityRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateRedirectRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n RedirectRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing redirect rules.\n */\nexport interface RedirectRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of redirect rules on a site.\n *\n * Access via `forge.server(id).site(id).redirectRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).redirectRules.list();\n * ```\n */\nexport class RedirectRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/redirect-rules`;\n }\n\n /**\n * List redirect rules on this site.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).site(456).redirectRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).site(456).redirectRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: RedirectRuleListOptions = {},\n ): Promise<Array<RedirectRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RedirectRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all redirect rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).site(456).redirectRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).site(456).redirectRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<RedirectRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<RedirectRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RedirectRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific redirect rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).redirectRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<RedirectRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<RedirectRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new redirect rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).site(456).redirectRules.create({\n * from: '/old-path',\n * to: '/new-path',\n * type: 'redirect',\n * });\n * ```\n */\n async create(data: CreateRedirectRuleData): Promise<RedirectRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<RedirectRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a redirect rule.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).redirectRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateSiteData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SiteAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\nimport { matchByName } from \"../utils/name-matcher.ts\";\nimport type { ResolveResult } from \"./servers.ts\";\nimport { DeploymentsCollection } from \"./deployments.ts\";\nimport { CertificatesCollection } from \"./certificates.ts\";\nimport { CommandsCollection } from \"./commands.ts\";\nimport { SecurityRulesCollection } from \"./security-rules.ts\";\nimport { RedirectRulesCollection } from \"./redirect-rules.ts\";\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * Options for listing sites.\n */\nexport interface SiteListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of sites on a server.\n *\n * Access via `forge.server(id).sites`.\n *\n * @example\n * ```ts\n * const sites = await forge.server(123).sites.list();\n * ```\n */\nexport class SitesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites`;\n }\n\n /**\n * List sites on this server.\n *\n * @example\n * ```ts\n * const sites = await forge.server(123).sites.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).sites.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: SiteListOptions = {}): Promise<Array<SiteAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SiteAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all sites across all pages.\n *\n * @example\n * ```ts\n * for await (const site of forge.server(123).sites.all()) {\n * console.log(site);\n * }\n *\n * // Or collect all at once:\n * const sites = await forge.server(123).sites.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SiteAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SiteAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SiteAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific site by ID.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).sites.get(456);\n * ```\n */\n async get(siteId: number): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SiteAttributes>>(\n `/orgs/${this.orgSlug}/sites/${siteId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new site on this server.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).sites.create({\n * type: 'php',\n * name: 'example.com',\n * directory: '/public',\n * });\n * ```\n */\n async create(data: CreateSiteData): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SiteAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Update a site.\n *\n * @example\n * ```ts\n * await forge.server(123).sites.update(456, { directory: '/public' });\n * ```\n */\n async update(\n siteId: number,\n data: Partial<CreateSiteData>,\n ): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<SiteAttributes>>(\n `${this.basePath}/${siteId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a site.\n *\n * @example\n * ```ts\n * await forge.server(123).sites.delete(456);\n * ```\n */\n async delete(siteId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${siteId}`);\n }\n\n /**\n * Find sites by domain name using case-insensitive partial matching.\n *\n * If exactly one site matches the query exactly, only that site is returned.\n * Otherwise all partial matches are returned.\n *\n * @param query - The search query to match against site domain names.\n * @returns Resolve result with matching sites.\n *\n * @example\n * ```ts\n * // Find sites matching \"example\"\n * const result = await forge.server(123).sites.resolve('example');\n * // → { query: 'example', matches: [{ id: 456, name: 'example.com' }], total: 1 }\n * ```\n */\n async resolve(query: string): Promise<ResolveResult> {\n const sites = await this.list();\n const { exact, partial } = matchByName(sites, query, (s) => s.name);\n const matches = exact.length === 1 ? exact : partial;\n return {\n query,\n matches: matches.map((s) => ({ id: s.id, name: s.name })),\n total: matches.length,\n };\n }\n}\n\n/**\n * A specific site with nested resources and actions.\n *\n * Access via `forge.server(id).site(id)`.\n *\n * @example\n * ```ts\n * // Deploy\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment\n * const env = await forge.server(123).site(456).env.get();\n * ```\n */\nexport class SiteResource extends BaseCollection {\n /** Deployments for this site. */\n readonly deployments: DeploymentsCollection;\n\n /** SSL certificates for this site. */\n readonly certificates: CertificatesCollection;\n\n /** Environment variables for this site. */\n readonly env: SiteEnvResource;\n\n /** Nginx configuration for this site. */\n readonly nginx: SiteNginxResource;\n\n /** Commands run on this site. */\n readonly commands: CommandsCollection;\n\n /** Security rules for this site. */\n readonly securityRules: SecurityRulesCollection;\n\n /** Redirect rules for this site. */\n readonly redirectRules: RedirectRulesCollection;\n\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n this.deployments = new DeploymentsCollection(client, orgSlug, serverId, siteId);\n this.certificates = new CertificatesCollection(client, orgSlug, serverId, siteId);\n this.env = new SiteEnvResource(client, orgSlug, serverId, siteId);\n this.nginx = new SiteNginxResource(client, orgSlug, serverId, siteId);\n this.commands = new CommandsCollection(client, orgSlug, serverId, siteId);\n this.securityRules = new SecurityRulesCollection(client, orgSlug, serverId, siteId);\n this.redirectRules = new RedirectRulesCollection(client, orgSlug, serverId, siteId);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}`;\n }\n\n /**\n * Get this site's details.\n *\n * @example\n * ```ts\n * const site = await forge.server(123).site(456).get();\n * ```\n */\n async get(): Promise<SiteAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SiteAttributes>>(\n `/orgs/${this.orgSlug}/sites/${this.siteId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Deploy this site.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).deploy();\n * ```\n */\n async deploy(): Promise<void> {\n await this.client.post(`${this.basePath}/deployments/deploy`);\n }\n\n /**\n * Delete this site.\n *\n * @example\n * ```ts\n * await forge.server(123).site(456).delete();\n * ```\n */\n async delete(): Promise<void> {\n await this.client.delete(this.basePath);\n }\n}\n\n/**\n * Environment variables for a site.\n *\n * @example\n * ```ts\n * const env = await forge.server(123).site(456).env.get();\n * await forge.server(123).site(456).env.update('APP_ENV=production\\n...');\n * ```\n */\nexport class SiteEnvResource extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/environment`;\n }\n\n /**\n * Get the environment file content.\n *\n * @returns The .env file content as a string.\n */\n async get(): Promise<string> {\n return this.client.get<string>(this.basePath);\n }\n\n /**\n * Update the environment file content.\n *\n * @param content The full .env file content.\n */\n async update(content: string): Promise<void> {\n await this.client.put(this.basePath, { content });\n }\n}\n\n/**\n * Nginx configuration for a site.\n *\n * @example\n * ```ts\n * const config = await forge.server(123).site(456).nginx.get();\n * await forge.server(123).site(456).nginx.update('server { ... }');\n * ```\n */\nexport class SiteNginxResource extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n private readonly siteId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/sites/${this.siteId}/nginx`;\n }\n\n /**\n * Get the Nginx configuration.\n *\n * @returns The Nginx config content as a string.\n */\n async get(): Promise<string> {\n return this.client.get<string>(this.basePath);\n }\n\n /**\n * Update the Nginx configuration.\n *\n * @param content The full Nginx config content.\n */\n async update(content: string): Promise<void> {\n await this.client.put(this.basePath, { content });\n }\n}\n","import type {\n CreateDatabaseData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DatabaseAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing databases.\n */\nexport interface DatabaseListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of databases on a server.\n *\n * Access via `forge.server(id).databases`.\n *\n * @example\n * ```ts\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class DatabasesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/schemas`;\n }\n\n /**\n * List databases on this server.\n *\n * @example\n * ```ts\n * const dbs = await forge.server(123).databases.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).databases.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DatabaseListOptions = {},\n ): Promise<Array<DatabaseAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all databases across all pages.\n *\n * @example\n * ```ts\n * for await (const db of forge.server(123).databases.all()) {\n * console.log(db);\n * }\n *\n * // Or collect all at once:\n * const dbs = await forge.server(123).databases.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DatabaseAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DatabaseAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific database.\n *\n * @example\n * ```ts\n * const db = await forge.server(123).databases.get(789);\n * ```\n */\n async get(databaseId: number): Promise<DatabaseAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DatabaseAttributes>>(\n `${this.basePath}/${databaseId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new database.\n *\n * @example\n * ```ts\n * const db = await forge.server(123).databases.create({\n * name: 'myapp',\n * user: 'admin',\n * password: 'secret',\n * });\n * ```\n */\n async create(data: CreateDatabaseData): Promise<DatabaseAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<DatabaseAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a database.\n *\n * @example\n * ```ts\n * await forge.server(123).databases.delete(789);\n * ```\n */\n async delete(databaseId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${databaseId}`);\n }\n}\n","import type {\n CreateDatabaseUserData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n DatabaseUserAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing database users.\n */\nexport interface DatabaseUserListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of database users on a server.\n *\n * Access via `forge.server(id).databaseUsers`.\n *\n * @example\n * ```ts\n * const users = await forge.server(123).databaseUsers.list();\n * ```\n */\nexport class DatabaseUsersCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/users`;\n }\n\n /**\n * List database users on this server.\n *\n * @example\n * ```ts\n * const users = await forge.server(123).databaseUsers.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).databaseUsers.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DatabaseUserListOptions = {},\n ): Promise<Array<DatabaseUserAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseUserAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all database users across all pages.\n *\n * @example\n * ```ts\n * for await (const user of forge.server(123).databaseUsers.all()) {\n * console.log(user);\n * }\n *\n * // Or collect all at once:\n * const users = await forge.server(123).databaseUsers.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<DatabaseUserAttributes & { id: number }> {\n return new AsyncPaginatedIterator<DatabaseUserAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<DatabaseUserAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific database user.\n *\n * @example\n * ```ts\n * const user = await forge.server(123).databaseUsers.get(789);\n * ```\n */\n async get(userId: number): Promise<DatabaseUserAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<DatabaseUserAttributes>>(\n `${this.basePath}/${userId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new database user.\n *\n * @example\n * ```ts\n * const user = await forge.server(123).databaseUsers.create({\n * name: 'forge',\n * password: 'secret',\n * databases: [1, 2],\n * });\n * ```\n */\n async create(data: CreateDatabaseUserData): Promise<DatabaseUserAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<DatabaseUserAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a database user.\n *\n * @example\n * ```ts\n * await forge.server(123).databaseUsers.delete(789);\n * ```\n */\n async delete(userId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${userId}`);\n }\n}\n","import type {\n CreateDaemonData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n BackgroundProcessAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing daemons.\n */\nexport interface DaemonListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of daemons (background processes) on a server.\n *\n * Access via `forge.server(id).daemons`.\n *\n * @example\n * ```ts\n * const daemons = await forge.server(123).daemons.list();\n * ```\n */\nexport class DaemonsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/background-processes`;\n }\n\n /**\n * List daemons on this server.\n *\n * @example\n * ```ts\n * const daemons = await forge.server(123).daemons.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).daemons.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: DaemonListOptions = {},\n ): Promise<Array<BackgroundProcessAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackgroundProcessAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all daemons across all pages.\n *\n * @example\n * ```ts\n * for await (const daemon of forge.server(123).daemons.all()) {\n * console.log(daemon);\n * }\n *\n * // Or collect all at once:\n * const daemons = await forge.server(123).daemons.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<BackgroundProcessAttributes & { id: number }> {\n return new AsyncPaginatedIterator<BackgroundProcessAttributes & { id: number }>(\n async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackgroundProcessAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n },\n );\n }\n\n /**\n * Get a specific daemon.\n *\n * @example\n * ```ts\n * const daemon = await forge.server(123).daemons.get(789);\n * ```\n */\n async get(daemonId: number): Promise<BackgroundProcessAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<BackgroundProcessAttributes>>(\n `${this.basePath}/${daemonId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new daemon.\n *\n * @example\n * ```ts\n * const daemon = await forge.server(123).daemons.create({\n * command: 'php artisan queue:work',\n * user: 'forge',\n * });\n * ```\n */\n async create(data: CreateDaemonData): Promise<BackgroundProcessAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<BackgroundProcessAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a daemon.\n *\n * @example\n * ```ts\n * await forge.server(123).daemons.delete(789);\n * ```\n */\n async delete(daemonId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${daemonId}`);\n }\n\n /**\n * Restart a daemon.\n *\n * @example\n * ```ts\n * await forge.server(123).daemons.restart(789);\n * ```\n */\n async restart(daemonId: number): Promise<void> {\n await this.client.post(`${this.basePath}/${daemonId}/restart`);\n }\n}\n","import type {\n CreateBackupConfigData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n BackupConfigAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing backup configurations.\n */\nexport interface BackupConfigListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of backup configurations on a server.\n *\n * Access via `forge.server(id).backups`.\n *\n * @example\n * ```ts\n * const backups = await forge.server(123).backups.list();\n * ```\n */\nexport class BackupsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/database/backups`;\n }\n\n /**\n * List backup configurations on this server.\n *\n * @example\n * ```ts\n * const backups = await forge.server(123).backups.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).backups.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: BackupConfigListOptions = {},\n ): Promise<Array<BackupConfigAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackupConfigAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all backup configurations across all pages.\n *\n * @example\n * ```ts\n * for await (const backup of forge.server(123).backups.all()) {\n * console.log(backup);\n * }\n *\n * // Or collect all at once:\n * const backups = await forge.server(123).backups.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<BackupConfigAttributes & { id: number }> {\n return new AsyncPaginatedIterator<BackupConfigAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<BackupConfigAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific backup configuration.\n *\n * @example\n * ```ts\n * const backup = await forge.server(123).backups.get(789);\n * ```\n */\n async get(backupId: number): Promise<BackupConfigAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<BackupConfigAttributes>>(\n `${this.basePath}/${backupId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new backup configuration.\n *\n * @example\n * ```ts\n * const backup = await forge.server(123).backups.create({\n * provider: 's3',\n * credentials: { key: 'ACCESS_KEY', secret: 'SECRET_KEY', region: 'us-east-1', bucket: 'my-bucket' },\n * frequency: 'weekly',\n * retention: 7,\n * databases: [1, 2],\n * });\n * ```\n */\n async create(data: CreateBackupConfigData): Promise<BackupConfigAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<BackupConfigAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a backup configuration.\n *\n * @example\n * ```ts\n * await forge.server(123).backups.delete(789);\n * ```\n */\n async delete(backupId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${backupId}`);\n }\n}\n","import type {\n CreateScheduledJobData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n ScheduledJobAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing scheduled jobs.\n */\nexport interface ScheduledJobListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of scheduled jobs (cron jobs) on a server.\n *\n * Access via `forge.server(id).scheduledJobs`.\n *\n * @example\n * ```ts\n * const jobs = await forge.server(123).scheduledJobs.list();\n * ```\n */\nexport class ScheduledJobsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/scheduled-jobs`;\n }\n\n /**\n * List scheduled jobs on this server.\n *\n * @example\n * ```ts\n * const jobs = await forge.server(123).scheduledJobs.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).scheduledJobs.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: ScheduledJobListOptions = {},\n ): Promise<Array<ScheduledJobAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ScheduledJobAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all scheduled jobs across all pages.\n *\n * @example\n * ```ts\n * for await (const job of forge.server(123).scheduledJobs.all()) {\n * console.log(job);\n * }\n *\n * // Or collect all at once:\n * const jobs = await forge.server(123).scheduledJobs.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<ScheduledJobAttributes & { id: number }> {\n return new AsyncPaginatedIterator<ScheduledJobAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ScheduledJobAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific scheduled job.\n *\n * @example\n * ```ts\n * const job = await forge.server(123).scheduledJobs.get(789);\n * ```\n */\n async get(jobId: number): Promise<ScheduledJobAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ScheduledJobAttributes>>(\n `${this.basePath}/${jobId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new scheduled job.\n *\n * @example\n * ```ts\n * const job = await forge.server(123).scheduledJobs.create({\n * command: 'php /home/forge/artisan schedule:run',\n * user: 'forge',\n * frequency: 'minutely',\n * });\n * ```\n */\n async create(data: CreateScheduledJobData): Promise<ScheduledJobAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<ScheduledJobAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a scheduled job.\n *\n * @example\n * ```ts\n * await forge.server(123).scheduledJobs.delete(789);\n * ```\n */\n async delete(jobId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${jobId}`);\n }\n}\n","import type {\n CreateMonitorData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n MonitorAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing monitors.\n */\nexport interface MonitorListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of server monitors.\n *\n * Access via `forge.server(id).monitors`.\n *\n * @example\n * ```ts\n * const monitors = await forge.server(123).monitors.list();\n * ```\n */\nexport class MonitorsCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/monitors`;\n }\n\n /**\n * List monitors on this server.\n *\n * @example\n * ```ts\n * const monitors = await forge.server(123).monitors.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).monitors.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: MonitorListOptions = {}): Promise<Array<MonitorAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<MonitorAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all monitors across all pages.\n *\n * @example\n * ```ts\n * for await (const monitor of forge.server(123).monitors.all()) {\n * console.log(monitor);\n * }\n *\n * // Or collect all at once:\n * const monitors = await forge.server(123).monitors.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<MonitorAttributes & { id: number }> {\n return new AsyncPaginatedIterator<MonitorAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<MonitorAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific monitor.\n *\n * @example\n * ```ts\n * const monitor = await forge.server(123).monitors.get(789);\n * ```\n */\n async get(monitorId: number): Promise<MonitorAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<MonitorAttributes>>(\n `${this.basePath}/${monitorId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new monitor.\n *\n * @example\n * ```ts\n * const monitor = await forge.server(123).monitors.create({\n * type: 'cpu_load',\n * operator: 'gte',\n * threshold: 80,\n * minutes: 5,\n * });\n * ```\n */\n async create(data: CreateMonitorData): Promise<MonitorAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<MonitorAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a monitor.\n *\n * @example\n * ```ts\n * await forge.server(123).monitors.delete(789);\n * ```\n */\n async delete(monitorId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${monitorId}`);\n }\n}\n","import type {\n CreateFirewallRuleData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n FirewallRuleAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing firewall rules.\n */\nexport interface FirewallRuleListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of firewall rules on a server.\n *\n * Access via `forge.server(id).firewallRules`.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).firewallRules.list();\n * ```\n */\nexport class FirewallRulesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/firewall-rules`;\n }\n\n /**\n * List firewall rules on this server.\n *\n * @example\n * ```ts\n * const rules = await forge.server(123).firewallRules.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).firewallRules.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: FirewallRuleListOptions = {},\n ): Promise<Array<FirewallRuleAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<FirewallRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all firewall rules across all pages.\n *\n * @example\n * ```ts\n * for await (const rule of forge.server(123).firewallRules.all()) {\n * console.log(rule);\n * }\n *\n * // Or collect all at once:\n * const rules = await forge.server(123).firewallRules.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<FirewallRuleAttributes & { id: number }> {\n return new AsyncPaginatedIterator<FirewallRuleAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<FirewallRuleAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific firewall rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).firewallRules.get(789);\n * ```\n */\n async get(ruleId: number): Promise<FirewallRuleAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<FirewallRuleAttributes>>(\n `${this.basePath}/${ruleId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new firewall rule.\n *\n * @example\n * ```ts\n * const rule = await forge.server(123).firewallRules.create({\n * name: 'Allow HTTP',\n * port: 80,\n * type: 'allow',\n * });\n * ```\n */\n async create(data: CreateFirewallRuleData): Promise<FirewallRuleAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<FirewallRuleAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a firewall rule.\n *\n * @example\n * ```ts\n * await forge.server(123).firewallRules.delete(789);\n * ```\n */\n async delete(ruleId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${ruleId}`);\n }\n}\n","import type {\n CreateSshKeyData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n SshKeyAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing SSH keys.\n */\nexport interface SshKeyListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of SSH keys on a server.\n *\n * Access via `forge.server(id).sshKeys`.\n *\n * @example\n * ```ts\n * const keys = await forge.server(123).sshKeys.list();\n * ```\n */\nexport class SshKeysCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/ssh-keys`;\n }\n\n /**\n * List SSH keys on this server.\n *\n * @example\n * ```ts\n * const keys = await forge.server(123).sshKeys.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).sshKeys.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: SshKeyListOptions = {}): Promise<Array<SshKeyAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SshKeyAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all SSH keys across all pages.\n *\n * @example\n * ```ts\n * for await (const key of forge.server(123).sshKeys.all()) {\n * console.log(key);\n * }\n *\n * // Or collect all at once:\n * const keys = await forge.server(123).sshKeys.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<SshKeyAttributes & { id: number }> {\n return new AsyncPaginatedIterator<SshKeyAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<SshKeyAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific SSH key.\n *\n * @example\n * ```ts\n * const key = await forge.server(123).sshKeys.get(789);\n * ```\n */\n async get(keyId: number): Promise<SshKeyAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<SshKeyAttributes>>(\n `${this.basePath}/${keyId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new SSH key.\n *\n * @example\n * ```ts\n * const key = await forge.server(123).sshKeys.create({\n * name: 'deploy-key',\n * key: 'ssh-rsa AAAA...',\n * });\n * ```\n */\n async create(data: CreateSshKeyData): Promise<SshKeyAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<SshKeyAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Delete an SSH key.\n *\n * @example\n * ```ts\n * await forge.server(123).sshKeys.delete(789);\n * ```\n */\n async delete(keyId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${keyId}`);\n }\n}\n","import type {\n CreateNginxTemplateData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n NginxTemplateAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing Nginx templates.\n */\nexport interface NginxTemplateListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of Nginx templates on a server.\n *\n * Access via `forge.server(id).nginxTemplates`.\n *\n * @example\n * ```ts\n * const templates = await forge.server(123).nginxTemplates.list();\n * ```\n */\nexport class NginxTemplatesCollection extends BaseCollection {\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n }\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers/${this.serverId}/nginx/templates`;\n }\n\n /**\n * List Nginx templates on this server.\n *\n * @example\n * ```ts\n * const templates = await forge.server(123).nginxTemplates.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.server(123).nginxTemplates.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(\n options: NginxTemplateListOptions = {},\n ): Promise<Array<NginxTemplateAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<NginxTemplateAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all Nginx templates across all pages.\n *\n * @example\n * ```ts\n * for await (const template of forge.server(123).nginxTemplates.all()) {\n * console.log(template);\n * }\n *\n * // Or collect all at once:\n * const templates = await forge.server(123).nginxTemplates.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<NginxTemplateAttributes & { id: number }> {\n return new AsyncPaginatedIterator<NginxTemplateAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<NginxTemplateAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.get(789);\n * ```\n */\n async get(templateId: number): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<NginxTemplateAttributes>>(\n `${this.basePath}/${templateId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.create({\n * name: 'Laravel Template',\n * content: 'server { ... }',\n * });\n * ```\n */\n async create(data: CreateNginxTemplateData): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<NginxTemplateAttributes>>(\n this.basePath,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Update an existing Nginx template.\n *\n * @example\n * ```ts\n * const template = await forge.server(123).nginxTemplates.update(789, {\n * name: 'Updated Template',\n * content: 'server { ... }',\n * });\n * ```\n */\n async update(\n templateId: number,\n data: Partial<CreateNginxTemplateData>,\n ): Promise<NginxTemplateAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<NginxTemplateAttributes>>(\n `${this.basePath}/${templateId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a Nginx template.\n *\n * @example\n * ```ts\n * await forge.server(123).nginxTemplates.delete(789);\n * ```\n */\n async delete(templateId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${templateId}`);\n }\n}\n","import type {\n CreateServerData,\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n ServerAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\nimport { matchByName } from \"../utils/name-matcher.ts\";\nimport { SitesCollection, SiteResource } from \"./sites.ts\";\nimport { DatabasesCollection } from \"./databases.ts\";\nimport { DatabaseUsersCollection } from \"./database-users.ts\";\nimport { DaemonsCollection } from \"./daemons.ts\";\nimport { BackupsCollection } from \"./backups.ts\";\nimport { ScheduledJobsCollection } from \"./scheduled-jobs.ts\";\nimport { MonitorsCollection } from \"./monitors.ts\";\nimport { FirewallRulesCollection } from \"./firewall-rules.ts\";\nimport { SshKeysCollection } from \"./ssh-keys.ts\";\nimport { NginxTemplatesCollection } from \"./nginx-templates.ts\";\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * A matched resource item with ID and name.\n */\nexport interface ResolveMatch {\n id: number;\n name: string;\n}\n\n/**\n * Result of a resolve operation.\n */\nexport interface ResolveResult {\n query: string;\n matches: ResolveMatch[];\n total: number;\n}\n\n/**\n * Options for listing servers.\n */\nexport interface ServerListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Collection of servers.\n *\n * Access via `forge.servers`.\n *\n * @example\n * ```ts\n * // List all servers\n * const servers = await forge.servers.list();\n *\n * // Get a specific server\n * const server = await forge.servers.get(123);\n *\n * // Create a new server\n * const server = await forge.servers.create({ ... });\n * ```\n */\nexport class ServersCollection extends BaseCollection {\n /** @internal */\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/servers`;\n }\n\n /**\n * List servers.\n *\n * @example\n * ```ts\n * const servers = await forge.servers.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.servers.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: ServerListOptions = {}): Promise<Array<ServerAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ServerAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all servers across all pages.\n *\n * @example\n * ```ts\n * for await (const server of forge.servers.all()) {\n * console.log(server);\n * }\n *\n * // Or collect all at once:\n * const servers = await forge.servers.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<ServerAttributes & { id: number }> {\n return new AsyncPaginatedIterator<ServerAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<ServerAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific server by ID.\n *\n * @example\n * ```ts\n * const server = await forge.servers.get(123);\n * ```\n */\n async get(serverId: number): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(\n `${this.basePath}/${serverId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new server.\n *\n * @example\n * ```ts\n * const server = await forge.servers.create({\n * provider: 'ocean2',\n * credential_id: 1,\n * name: 'web-1',\n * type: 'app',\n * size: '01',\n * region: 'ams3',\n * });\n * ```\n */\n async create(data: CreateServerData): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<ServerAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Update a server.\n *\n * @example\n * ```ts\n * await forge.servers.update(123, { name: 'web-1-renamed' });\n * ```\n */\n async update(\n serverId: number,\n data: Partial<CreateServerData>,\n ): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.put<JsonApiDocument<ServerAttributes>>(\n `${this.basePath}/${serverId}`,\n data,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Delete a server.\n *\n * @example\n * ```ts\n * await forge.servers.delete(123);\n * ```\n */\n async delete(serverId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${serverId}`);\n }\n\n /**\n * Reboot a server.\n *\n * @example\n * ```ts\n * await forge.servers.reboot(123);\n * ```\n */\n async reboot(serverId: number): Promise<void> {\n await this.client.post(`${this.basePath}/${serverId}/reboot`);\n }\n\n /**\n * Find servers by name using case-insensitive partial matching.\n *\n * If exactly one server matches the query exactly, only that server is returned.\n * Otherwise all partial matches are returned.\n *\n * @param query - The search query to match against server names.\n * @returns Resolve result with matching servers.\n *\n * @example\n * ```ts\n * // Find servers matching \"prod\"\n * const result = await forge.servers.resolve('prod');\n * // → { query: 'prod', matches: [{ id: 725393, name: 'wilo-grove-prod' }], total: 1 }\n *\n * // Use the result to access a server\n * if (result.total === 1) {\n * const sites = await forge.server(result.matches[0].id).sites.list();\n * }\n * ```\n */\n async resolve(query: string): Promise<ResolveResult> {\n const servers = await this.list();\n const { exact, partial } = matchByName(servers, query, (s) => s.name);\n const matches = exact.length === 1 ? exact : partial;\n return {\n query,\n matches: matches.map((s) => ({ id: s.id, name: s.name })),\n total: matches.length,\n };\n }\n}\n\n/**\n * A specific server with nested resources.\n *\n * Access via `forge.server(id)`.\n *\n * @example\n * ```ts\n * // Access sites on a server\n * const sites = await forge.server(123).sites.list();\n *\n * // Access databases on a server\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class ServerResource extends BaseCollection {\n /** Sites on this server. */\n readonly sites: SitesCollection;\n\n /** Databases on this server. */\n readonly databases: DatabasesCollection;\n\n /** Database users on this server. */\n readonly databaseUsers: DatabaseUsersCollection;\n\n /** Daemons (background processes) on this server. */\n readonly daemons: DaemonsCollection;\n\n /** Backup configurations on this server. */\n readonly backups: BackupsCollection;\n\n /** Scheduled jobs (cron jobs) on this server. */\n readonly scheduledJobs: ScheduledJobsCollection;\n\n /** Monitors on this server. */\n readonly monitors: MonitorsCollection;\n\n /** Firewall rules on this server. */\n readonly firewallRules: FirewallRulesCollection;\n\n /** SSH keys on this server. */\n readonly sshKeys: SshKeysCollection;\n\n /** Nginx templates on this server. */\n readonly nginxTemplates: NginxTemplatesCollection;\n\n /** @internal */\n constructor(\n client: HttpClient,\n orgSlug: string,\n private readonly serverId: number,\n ) {\n super(client, orgSlug);\n this.sites = new SitesCollection(client, orgSlug, serverId);\n this.databases = new DatabasesCollection(client, orgSlug, serverId);\n this.databaseUsers = new DatabaseUsersCollection(client, orgSlug, serverId);\n this.daemons = new DaemonsCollection(client, orgSlug, serverId);\n this.backups = new BackupsCollection(client, orgSlug, serverId);\n this.scheduledJobs = new ScheduledJobsCollection(client, orgSlug, serverId);\n this.monitors = new MonitorsCollection(client, orgSlug, serverId);\n this.firewallRules = new FirewallRulesCollection(client, orgSlug, serverId);\n this.sshKeys = new SshKeysCollection(client, orgSlug, serverId);\n this.nginxTemplates = new NginxTemplatesCollection(client, orgSlug, serverId);\n }\n\n /**\n * Access a specific site on this server, with nested resources.\n *\n * @example\n * ```ts\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment variables\n * const env = await forge.server(123).site(456).env.get();\n * ```\n */\n site(siteId: number): SiteResource {\n return new SiteResource(this.client, this.orgSlug, this.serverId, siteId);\n }\n\n /**\n * Get this server's details.\n *\n * @example\n * ```ts\n * const server = await forge.server(123).get();\n * ```\n */\n async get(): Promise<ServerAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(\n `/orgs/${this.orgSlug}/servers/${this.serverId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Reboot this server.\n *\n * @example\n * ```ts\n * await forge.server(123).reboot();\n * ```\n */\n async reboot(): Promise<void> {\n await this.client.post(`/orgs/${this.orgSlug}/servers/${this.serverId}/reboot`);\n }\n\n /**\n * Delete this server.\n *\n * @example\n * ```ts\n * await forge.server(123).delete();\n * ```\n */\n async delete(): Promise<void> {\n await this.client.delete(`/orgs/${this.orgSlug}/servers/${this.serverId}`);\n }\n}\n","import type {\n CreateRecipeData,\n JsonApiDocument,\n JsonApiListDocument,\n RecipeAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\nimport { AsyncPaginatedIterator } from \"../pagination.ts\";\n\n/**\n * Options for listing recipes.\n */\nexport interface RecipeListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Options for running a recipe.\n */\nexport interface RunRecipeOptions {\n /** Server IDs to run the recipe on. */\n servers: number[];\n}\n\n/**\n * Collection of recipes.\n *\n * Access via `forge.recipes`.\n *\n * @example\n * ```ts\n * const recipes = await forge.recipes.list();\n * ```\n */\nexport class RecipesCollection extends BaseCollection {\n /** @internal */\n\n private get basePath(): string {\n return `/orgs/${this.orgSlug}/recipes`;\n }\n\n /**\n * List all recipes.\n *\n * @example\n * ```ts\n * const recipes = await forge.recipes.list();\n *\n * // Fetch a specific cursor page:\n * const page2 = await forge.recipes.list({ cursor: 'next-cursor-value' });\n * ```\n */\n async list(options: RecipeListOptions = {}): Promise<Array<RecipeAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RecipeAttributes>>(\n `${this.basePath}${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Iterate over all recipes across all pages.\n *\n * @example\n * ```ts\n * for await (const recipe of forge.recipes.all()) {\n * console.log(recipe);\n * }\n *\n * // Or collect all at once:\n * const recipes = await forge.recipes.all().toArray();\n * ```\n */\n all(): AsyncPaginatedIterator<RecipeAttributes & { id: number }> {\n return new AsyncPaginatedIterator<RecipeAttributes & { id: number }>(async (cursor) => {\n const query = cursor !== null ? `?page[cursor]=${cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<RecipeAttributes>>(\n `${this.basePath}${query}`,\n );\n return {\n items: unwrapListDocument(response),\n nextCursor: response.meta.next_cursor ?? null,\n };\n });\n }\n\n /**\n * Get a specific recipe.\n *\n * @example\n * ```ts\n * const recipe = await forge.recipes.get(789);\n * ```\n */\n async get(recipeId: number): Promise<RecipeAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<RecipeAttributes>>(\n `${this.basePath}/${recipeId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Create a new recipe.\n *\n * @example\n * ```ts\n * const recipe = await forge.recipes.create({\n * name: 'Install Node',\n * user: 'root',\n * script: 'curl -fsSL https://deb.nodesource.com/setup_20.x | bash -',\n * });\n * ```\n */\n async create(data: CreateRecipeData): Promise<RecipeAttributes & { id: number }> {\n const response = await this.client.post<JsonApiDocument<RecipeAttributes>>(this.basePath, data);\n return unwrapDocument(response);\n }\n\n /**\n * Delete a recipe.\n *\n * @example\n * ```ts\n * await forge.recipes.delete(789);\n * ```\n */\n async delete(recipeId: number): Promise<void> {\n await this.client.delete(`${this.basePath}/${recipeId}`);\n }\n\n /**\n * Run a recipe on one or more servers.\n *\n * @example\n * ```ts\n * await forge.recipes.run(789, { servers: [123, 456] });\n * ```\n */\n async run(recipeId: number, options: RunRecipeOptions): Promise<void> {\n await this.client.post(`${this.basePath}/${recipeId}/run`, options);\n }\n}\n","import type { ForgeOptions, JsonApiDocument, UserAttributes } from \"@studiometa/forge-api\";\n\nimport { HttpClient, unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { ServersCollection, ServerResource } from \"./resources/servers.ts\";\nimport { RecipesCollection } from \"./resources/recipes.ts\";\n\n/**\n * Laravel Forge TypeScript SDK.\n *\n * Provides a fluent, chainable API for managing Laravel Forge servers,\n * sites, deployments, and more.\n *\n * @example\n * ```ts\n * import { Forge } from '@studiometa/forge-sdk';\n *\n * const forge = new Forge('your-api-token', 'my-org');\n *\n * // List all servers\n * const servers = await forge.servers.list();\n *\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Get environment variables\n * const env = await forge.server(123).site(456).env.get();\n *\n * // Manage databases\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\nexport class Forge {\n /** @internal */\n readonly client: HttpClient;\n\n /** The organization slug used for v2 API URL prefixing. */\n readonly organizationSlug: string;\n\n /** Server operations (list, get, create, update, delete, reboot). */\n readonly servers: ServersCollection;\n\n /** Recipe operations (list, get, create, delete, run). */\n readonly recipes: RecipesCollection;\n\n /**\n * Create a new Forge SDK instance.\n *\n * @param token Your Laravel Forge API token.\n * @param organizationSlug Your organization slug (used for v2 API URLs).\n * @param options Optional configuration (custom fetch, base URL, rate limiting).\n *\n * @example\n * ```ts\n * // Basic usage\n * const forge = new Forge('your-api-token', 'my-org');\n *\n * // With custom options\n * const forge = new Forge('your-api-token', 'my-org', {\n * baseUrl: 'https://forge.laravel.com/api/v2',\n * });\n *\n * // With mock fetch for testing\n * const forge = new Forge('test-token', 'test-org', { fetch: mockFetch });\n * ```\n */\n constructor(token: string, organizationSlug: string, options?: ForgeOptions) {\n this.client = new HttpClient({ token, ...options });\n this.organizationSlug = organizationSlug;\n this.servers = new ServersCollection(this.client, organizationSlug);\n this.recipes = new RecipesCollection(this.client, organizationSlug);\n }\n\n /**\n * Access a specific server by ID, with nested resources.\n *\n * Returns a `ServerResource` that provides access to sites, databases,\n * daemons, and other server-level resources.\n *\n * @param serverId The server ID.\n *\n * @example\n * ```ts\n * // List sites on a server\n * const sites = await forge.server(123).sites.list();\n *\n * // Access a specific site\n * const site = await forge.server(123).site(456);\n *\n * // Deploy a site\n * await forge.server(123).site(456).deploy();\n *\n * // Manage databases\n * const dbs = await forge.server(123).databases.list();\n * ```\n */\n server(serverId: number): ServerResource {\n return new ServerResource(this.client, this.organizationSlug, serverId);\n }\n\n /**\n * Get the currently authenticated user.\n *\n * @example\n * ```ts\n * const user = await forge.user();\n * console.log(user.name, user.email);\n * ```\n */\n async user(): Promise<UserAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<UserAttributes>>(\"/user\");\n return unwrapDocument(response);\n }\n}\n"],"mappings":"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"}
|
package/dist/test-utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { vi } from "vitest";
|
|
2
|
+
//#region src/test-utils.ts
|
|
2
3
|
/**
|
|
3
4
|
* Convert a fetch URL argument to a string.
|
|
4
5
|
* Handles string, URL, and Request objects safely.
|
|
@@ -44,6 +45,7 @@ function createMockFetch(handler) {
|
|
|
44
45
|
});
|
|
45
46
|
});
|
|
46
47
|
}
|
|
48
|
+
//#endregion
|
|
47
49
|
export { createMockFetch, toUrlString };
|
|
48
50
|
|
|
49
51
|
//# sourceMappingURL=test-utils.js.map
|
package/dist/test-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.js","names":[],"sources":["../src/test-utils.ts"],"sourcesContent":["import { vi } from \"vitest\";\n\n/**\n * Convert a fetch URL argument to a string.\n * Handles string, URL, and Request objects safely.\n */\n// eslint-disable-next-line typescript-eslint/no-redundant-type-constituents -- matches fetch() signature\nexport function toUrlString(url: string | URL | Request): string {\n return typeof url === \"string\" ? url : url instanceof URL ? url.toString() : url.url;\n}\n\n/**\n * Create a mock `fetch` function for use in SDK tests.\n *\n * The handler receives the request URL and init options, and should return\n * the data to be serialised as JSON in the response body.\n *\n * @param handler A function that receives `(url, init)` and returns response data.\n * @returns A vitest mock function compatible with the `fetch` signature.\n *\n * @example\n * ```ts\n * import { describe, it, expect } from 'vitest';\n * import { Forge } from '@studiometa/forge-sdk';\n * import { createMockFetch } from '@studiometa/forge-sdk/test-utils';\n *\n * describe('my feature', () => {\n * it('lists servers', async () => {\n * const mockFetch = createMockFetch(() => ({\n * data: [{ id: '1', type: 'server', attributes: { name: 'web-1' } }],\n * links: {},\n * meta: { per_page: 200, next_cursor: null },\n * }));\n * const forge = new Forge('test-token', 'test-org', { fetch: mockFetch });\n * const servers = await forge.servers.list();\n * expect(servers).toHaveLength(1);\n * });\n * });\n * ```\n */\nexport function createMockFetch(\n handler: (url: string, init?: RequestInit) => unknown,\n): typeof fetch {\n // eslint-disable-next-line typescript-eslint/no-redundant-type-constituents -- matches fetch() signature\n return vi.fn(async (url: string | URL | Request, init?: RequestInit) => {\n const urlStr = toUrlString(url);\n const data = handler(urlStr, init);\n return new Response(JSON.stringify(data), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }) as unknown as typeof fetch;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"test-utils.js","names":[],"sources":["../src/test-utils.ts"],"sourcesContent":["import { vi } from \"vitest\";\n\n/**\n * Convert a fetch URL argument to a string.\n * Handles string, URL, and Request objects safely.\n */\n// eslint-disable-next-line typescript-eslint/no-redundant-type-constituents -- matches fetch() signature\nexport function toUrlString(url: string | URL | Request): string {\n return typeof url === \"string\" ? url : url instanceof URL ? url.toString() : url.url;\n}\n\n/**\n * Create a mock `fetch` function for use in SDK tests.\n *\n * The handler receives the request URL and init options, and should return\n * the data to be serialised as JSON in the response body.\n *\n * @param handler A function that receives `(url, init)` and returns response data.\n * @returns A vitest mock function compatible with the `fetch` signature.\n *\n * @example\n * ```ts\n * import { describe, it, expect } from 'vitest';\n * import { Forge } from '@studiometa/forge-sdk';\n * import { createMockFetch } from '@studiometa/forge-sdk/test-utils';\n *\n * describe('my feature', () => {\n * it('lists servers', async () => {\n * const mockFetch = createMockFetch(() => ({\n * data: [{ id: '1', type: 'server', attributes: { name: 'web-1' } }],\n * links: {},\n * meta: { per_page: 200, next_cursor: null },\n * }));\n * const forge = new Forge('test-token', 'test-org', { fetch: mockFetch });\n * const servers = await forge.servers.list();\n * expect(servers).toHaveLength(1);\n * });\n * });\n * ```\n */\nexport function createMockFetch(\n handler: (url: string, init?: RequestInit) => unknown,\n): typeof fetch {\n // eslint-disable-next-line typescript-eslint/no-redundant-type-constituents -- matches fetch() signature\n return vi.fn(async (url: string | URL | Request, init?: RequestInit) => {\n const urlStr = toUrlString(url);\n const data = handler(urlStr, init);\n return new Response(JSON.stringify(data), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }) as unknown as typeof fetch;\n}\n"],"mappings":";;;;;;AAOA,SAAgB,YAAY,KAAqC;CAC/D,OAAO,OAAO,QAAQ,WAAW,MAAM,eAAe,MAAM,IAAI,SAAS,IAAI,IAAI;AACnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,gBACd,SACc;CAEd,OAAO,GAAG,GAAG,OAAO,KAA6B,SAAuB;EAEtE,MAAM,OAAO,QADE,YAAY,GACN,GAAQ,IAAI;EACjC,OAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;GACxC,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;EAChD,CAAC;CACH,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/forge-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Laravel Forge TypeScript SDK — fluent, chainable, fully-typed API client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"typecheck": "tsgo -p tsconfig.typecheck.json --noEmit"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@studiometa/forge-api": "0.4.
|
|
47
|
+
"@studiometa/forge-api": "0.4.5"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@typescript/native-preview": "^7.0.0-dev.20260409.1",
|