@studiometa/forge-sdk 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -185,6 +185,25 @@ forge.server(id).daemons.restart(daemonId);
185
185
  forge.server(id).daemons.delete(daemonId);
186
186
  ```
187
187
 
188
+ ### PHP
189
+
190
+ Version methods take the PHP version ID from `php.list()`.
191
+
192
+ ```typescript
193
+ forge.server(id).php.list(); // Installed PHP versions
194
+ forge.server(id).php.get(versionId);
195
+ forge.server(id).php.config(versionId, "fpm"); // "cli", "fpm" or "pool"
196
+ forge.server(id).php.config(versionId, "pool", { user: "forge" });
197
+ forge.server(id).php.updateConfig(versionId, "fpm", "memory_limit = 512M\n...");
198
+ forge.server(id).php.maxUploadSize(); // Megabytes
199
+ forge.server(id).php.setMaxUploadSize(128);
200
+ forge.server(id).php.maxExecutionTime(); // Seconds
201
+ forge.server(id).php.setMaxExecutionTime(120);
202
+ forge.server(id).php.opcache(); // true or false
203
+ forge.server(id).php.enableOpcache();
204
+ forge.server(id).php.disableOpcache();
205
+ ```
206
+
188
207
  ### User
189
208
 
190
209
  ```typescript
package/dist/index.d.ts CHANGED
@@ -21,6 +21,8 @@ export { MonitorsCollection } from "./resources/monitors.ts";
21
21
  export type { MonitorListOptions } from "./resources/monitors.ts";
22
22
  export { NginxTemplatesCollection } from "./resources/nginx-templates.ts";
23
23
  export type { NginxTemplateListOptions } from "./resources/nginx-templates.ts";
24
+ export { PhpResource, PHP_CONFIG_TYPES } from "./resources/php.ts";
25
+ export type { PhpConfigOptions, PhpConfigType, PhpVersionListOptions } from "./resources/php.ts";
24
26
  export { RecipesCollection } from "./resources/recipes.ts";
25
27
  export type { RecipeListOptions, RunRecipeOptions } from "./resources/recipes.ts";
26
28
  export { RedirectRulesCollection } from "./resources/redirect-rules.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,YAAY,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACnF,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG3F,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,0BAA0B,EAC1B,0BAA0B,EAC1B,kBAAkB,EAClB,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,YAAY,GACb,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -791,7 +791,7 @@ var SiteEnvResource = class extends BaseCollection {
791
791
  * @param content The full .env file content.
792
792
  */
793
793
  async update(content) {
794
- await this.client.put(this.basePath, { content });
794
+ await this.client.put(this.basePath, { environment: content });
795
795
  }
796
796
  };
797
797
  /**
@@ -829,7 +829,7 @@ var SiteNginxResource = class extends BaseCollection {
829
829
  * @param content The full Nginx config content.
830
830
  */
831
831
  async update(content) {
832
- await this.client.put(this.basePath, { content });
832
+ await this.client.put(this.basePath, { config: content });
833
833
  }
834
834
  };
835
835
  //#endregion
@@ -1861,6 +1861,182 @@ var ServicesCollection = class extends BaseCollection {
1861
1861
  }
1862
1862
  };
1863
1863
  //#endregion
1864
+ //#region src/resources/php.ts
1865
+ /**
1866
+ * The PHP configuration files that Forge can read and write.
1867
+ */
1868
+ var PHP_CONFIG_TYPES = [
1869
+ "cli",
1870
+ "fpm",
1871
+ "pool"
1872
+ ];
1873
+ /**
1874
+ * Throw when the configuration type is not one of cli, fpm or pool,
1875
+ * or when a user is given for a type other than pool.
1876
+ */
1877
+ function assertConfigTarget(type, options) {
1878
+ if (!PHP_CONFIG_TYPES.includes(type)) throw new Error(`Invalid PHP config type "${type}". Valid types: ${PHP_CONFIG_TYPES.join(", ")}.`);
1879
+ if (options.user && type !== "pool") throw new Error(`The user option applies to the pool config only, not "${type}".`);
1880
+ }
1881
+ /**
1882
+ * PHP on a server — installed versions, configuration files, limits and OPcache.
1883
+ *
1884
+ * Access via `forge.server(id).php`.
1885
+ *
1886
+ * Version methods take the PHP version ID from `list()`.
1887
+ *
1888
+ * @example
1889
+ * ```ts
1890
+ * const versions = await forge.server(123).php.list();
1891
+ * const fpm = await forge.server(123).php.config(versions[0].id, 'fpm');
1892
+ * await forge.server(123).php.setMaxUploadSize(64);
1893
+ * await forge.server(123).php.enableOpcache();
1894
+ * ```
1895
+ */
1896
+ var PhpResource = class extends BaseCollection {
1897
+ serverId;
1898
+ /** @internal */
1899
+ constructor(client, orgSlug, serverId) {
1900
+ super(client, orgSlug);
1901
+ this.serverId = serverId;
1902
+ }
1903
+ get basePath() {
1904
+ return `/orgs/${this.orgSlug}/servers/${this.serverId}/php`;
1905
+ }
1906
+ /**
1907
+ * List the PHP versions installed on this server.
1908
+ *
1909
+ * @example
1910
+ * ```ts
1911
+ * const versions = await forge.server(123).php.list();
1912
+ * // → [{ id: 12, version: '8.3', binary_name: 'php8.3', status: 'installed', ... }]
1913
+ * ```
1914
+ */
1915
+ async list(options = {}) {
1916
+ const query = options.cursor !== void 0 ? `?page[cursor]=${options.cursor}` : "";
1917
+ return unwrapListDocument$1(await this.client.get(`${this.basePath}/versions${query}`));
1918
+ }
1919
+ /**
1920
+ * Get one installed PHP version.
1921
+ *
1922
+ * @example
1923
+ * ```ts
1924
+ * const version = await forge.server(123).php.get(12);
1925
+ * ```
1926
+ */
1927
+ async get(versionId) {
1928
+ return unwrapDocument$1(await this.client.get(`${this.basePath}/versions/${versionId}`));
1929
+ }
1930
+ /**
1931
+ * Get a PHP configuration file (cli, fpm or pool) of a version.
1932
+ *
1933
+ * @example
1934
+ * ```ts
1935
+ * const ini = await forge.server(123).php.config(12, 'fpm');
1936
+ * const pool = await forge.server(123).php.config(12, 'pool', { user: 'forge' });
1937
+ * ```
1938
+ */
1939
+ async config(versionId, type, options = {}) {
1940
+ assertConfigTarget(type, options);
1941
+ const query = options.user ? `?user=${encodeURIComponent(options.user)}` : "";
1942
+ return unwrapDocument$1(await this.client.get(`${this.basePath}/versions/${versionId}/configs/${type}${query}`)).configuration;
1943
+ }
1944
+ /**
1945
+ * Replace a PHP configuration file (cli, fpm or pool) of a version.
1946
+ *
1947
+ * @example
1948
+ * ```ts
1949
+ * await forge.server(123).php.updateConfig(12, 'fpm', 'memory_limit = 512M\n...');
1950
+ * ```
1951
+ */
1952
+ async updateConfig(versionId, type, content, options = {}) {
1953
+ assertConfigTarget(type, options);
1954
+ await this.client.put(`${this.basePath}/versions/${versionId}/configs/${type}`, {
1955
+ config: content,
1956
+ ...options.user ? { user: options.user } : {}
1957
+ });
1958
+ }
1959
+ /**
1960
+ * Get the PHP max upload size, in megabytes.
1961
+ *
1962
+ * @example
1963
+ * ```ts
1964
+ * const size = await forge.server(123).php.maxUploadSize(); // → "64"
1965
+ * ```
1966
+ */
1967
+ async maxUploadSize() {
1968
+ const response = await this.client.get(`${this.basePath}/max-upload-size`);
1969
+ return String(unwrapDocument$1(response).max_upload_size);
1970
+ }
1971
+ /**
1972
+ * Set the PHP max upload size, in megabytes.
1973
+ *
1974
+ * @example
1975
+ * ```ts
1976
+ * await forge.server(123).php.setMaxUploadSize(128);
1977
+ * ```
1978
+ */
1979
+ async setMaxUploadSize(size) {
1980
+ await this.client.put(`${this.basePath}/max-upload-size`, { max_upload_size: size });
1981
+ }
1982
+ /**
1983
+ * Get the PHP max execution time, in seconds.
1984
+ *
1985
+ * @example
1986
+ * ```ts
1987
+ * const seconds = await forge.server(123).php.maxExecutionTime(); // → "60"
1988
+ * ```
1989
+ */
1990
+ async maxExecutionTime() {
1991
+ const response = await this.client.get(`${this.basePath}/max-execution-time`);
1992
+ return String(unwrapDocument$1(response).max_execution_time);
1993
+ }
1994
+ /**
1995
+ * Set the PHP max execution time, in seconds.
1996
+ *
1997
+ * @example
1998
+ * ```ts
1999
+ * await forge.server(123).php.setMaxExecutionTime(120);
2000
+ * ```
2001
+ */
2002
+ async setMaxExecutionTime(seconds) {
2003
+ await this.client.put(`${this.basePath}/max-execution-time`, { max_execution_time: seconds });
2004
+ }
2005
+ /**
2006
+ * Get whether OPcache is enabled.
2007
+ *
2008
+ * @example
2009
+ * ```ts
2010
+ * const enabled = await forge.server(123).php.opcache(); // → true
2011
+ * ```
2012
+ */
2013
+ async opcache() {
2014
+ return unwrapDocument$1(await this.client.get(`${this.basePath}/opcache`)).opcache_enabled;
2015
+ }
2016
+ /**
2017
+ * Enable OPcache.
2018
+ *
2019
+ * @example
2020
+ * ```ts
2021
+ * await forge.server(123).php.enableOpcache();
2022
+ * ```
2023
+ */
2024
+ async enableOpcache() {
2025
+ await this.client.post(`${this.basePath}/opcache`);
2026
+ }
2027
+ /**
2028
+ * Disable OPcache.
2029
+ *
2030
+ * @example
2031
+ * ```ts
2032
+ * await forge.server(123).php.disableOpcache();
2033
+ * ```
2034
+ */
2035
+ async disableOpcache() {
2036
+ await this.client.delete(`${this.basePath}/opcache`);
2037
+ }
2038
+ };
2039
+ //#endregion
1864
2040
  //#region src/resources/servers.ts
1865
2041
  /**
1866
2042
  * Collection of servers.
@@ -2056,6 +2232,8 @@ var ServerResource = class extends BaseCollection {
2056
2232
  nginxTemplates;
2057
2233
  /** Services (nginx, php, mysql, etc.) on this server. */
2058
2234
  services;
2235
+ /** PHP versions, configuration files, limits and OPcache on this server. */
2236
+ php;
2059
2237
  /** @internal */
2060
2238
  constructor(client, orgSlug, serverId) {
2061
2239
  super(client, orgSlug);
@@ -2071,6 +2249,7 @@ var ServerResource = class extends BaseCollection {
2071
2249
  this.sshKeys = new SshKeysCollection(client, orgSlug, serverId);
2072
2250
  this.nginxTemplates = new NginxTemplatesCollection(client, orgSlug, serverId);
2073
2251
  this.services = new ServicesCollection(client, orgSlug, serverId);
2252
+ this.php = new PhpResource(client, orgSlug, serverId);
2074
2253
  }
2075
2254
  /**
2076
2255
  * Access a specific site on this server, with nested resources.
@@ -2331,6 +2510,6 @@ var Forge = class {
2331
2510
  }
2332
2511
  };
2333
2512
  //#endregion
2334
- export { AsyncPaginatedIterator, BackupsCollection, BaseCollection, CertificatesCollection, CommandsCollection, DaemonsCollection, DatabaseUsersCollection, DatabasesCollection, DeploymentsCollection, FirewallRulesCollection, Forge, MonitorsCollection, NginxTemplatesCollection, RESTARTABLE_SERVICES, RecipesCollection, RedirectRulesCollection, ScheduledJobsCollection, SecurityRulesCollection, ServerResource, ServersCollection, ServicesCollection, SiteEnvResource, SiteNginxResource, SiteResource, SitesCollection, SshKeysCollection, unwrapDocument, unwrapListDocument, unwrapResource };
2513
+ export { AsyncPaginatedIterator, BackupsCollection, BaseCollection, CertificatesCollection, CommandsCollection, DaemonsCollection, DatabaseUsersCollection, DatabasesCollection, DeploymentsCollection, FirewallRulesCollection, Forge, MonitorsCollection, NginxTemplatesCollection, PHP_CONFIG_TYPES, PhpResource, RESTARTABLE_SERVICES, RecipesCollection, RedirectRulesCollection, ScheduledJobsCollection, SecurityRulesCollection, ServerResource, ServersCollection, ServicesCollection, SiteEnvResource, SiteNginxResource, SiteResource, SitesCollection, SshKeysCollection, unwrapDocument, unwrapListDocument, unwrapResource };
2335
2514
 
2336
2515
  //# 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/services.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 BackgroundProcessLogAttributes,\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 * Get the log output of a daemon.\n *\n * @example\n * ```ts\n * const log = await forge.server(123).daemons.log(789);\n * ```\n */\n async log(daemonId: number): Promise<string> {\n const response = await this.client.get<JsonApiDocument<BackgroundProcessLogAttributes>>(\n `${this.basePath}/${daemonId}/log`,\n );\n return unwrapDocument(response).content;\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 { HttpClient, JsonApiDocument, ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * The six restartable services exposed by the Forge v2 API.\n */\nexport const RESTARTABLE_SERVICES = [\n \"nginx\",\n \"php\",\n \"mysql\",\n \"postgres\",\n \"redis\",\n \"supervisor\",\n] as const;\n\nexport type RestartableService = (typeof RESTARTABLE_SERVICES)[number];\n\n/**\n * A single service availability row.\n *\n * `available` is a documented heuristic derived from the server object, since\n * the API has no services GET endpoint.\n */\nexport interface ServiceStatus {\n service: string;\n available: boolean;\n detail: string | null;\n}\n\n/**\n * Options for restarting a service.\n */\nexport interface RestartServiceOptions {\n /** PHP version (e.g. \"php83\") — required when restarting the php service. */\n version?: string;\n}\n\n/**\n * Services on a server — list availability and restart individual services.\n *\n * Access via `forge.server(id).services`.\n *\n * The v2 API has no GET endpoint for services, so `list()` derives availability\n * from the server object. Restarting maps to the API action `reboot`.\n *\n * @example\n * ```ts\n * // List services and their availability\n * const services = await forge.server(123).services.list();\n *\n * // Restart nginx\n * await forge.server(123).services.restart('nginx');\n *\n * // Restart php (version required)\n * await forge.server(123).services.restart('php', { version: 'php83' });\n * ```\n */\nexport class ServicesCollection 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}`;\n }\n\n /**\n * List services on this server with a derived availability flag.\n *\n * @example\n * ```ts\n * const services = await forge.server(123).services.list();\n * // → [{ service: 'nginx', available: true, detail: null }, ...]\n * ```\n */\n async list(): Promise<ServiceStatus[]> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(this.basePath);\n const server = unwrapDocument(response);\n\n const databaseType = server.database_type ?? \"\";\n const isMysql = databaseType.startsWith(\"mysql\") || databaseType.startsWith(\"mariadb\");\n const isPostgres = databaseType.startsWith(\"postgres\");\n\n return [\n { service: \"nginx\", available: true, detail: null },\n { service: \"php\", available: server.php_version !== null, detail: server.php_version },\n { service: \"mysql\", available: isMysql, detail: isMysql ? server.database_type : null },\n {\n service: \"postgres\",\n available: isPostgres,\n detail: isPostgres ? server.database_type : null,\n },\n { service: \"redis\", available: server.redis_status !== null, detail: server.redis_status },\n { service: \"supervisor\", available: true, detail: null },\n ];\n }\n\n /**\n * Restart a service on this server.\n *\n * Maps to the API action `reboot`. The php service requires a `version`.\n *\n * @example\n * ```ts\n * await forge.server(123).services.restart('nginx');\n * await forge.server(123).services.restart('php', { version: 'php83' });\n * ```\n */\n async restart(service: string, options: RestartServiceOptions = {}): Promise<void> {\n if (!(RESTARTABLE_SERVICES as readonly string[]).includes(service)) {\n throw new Error(\n `Invalid service \"${service}\". Valid services: ${RESTARTABLE_SERVICES.join(\", \")}.`,\n );\n }\n\n if (service === \"php\" && !options.version) {\n throw new Error('The \"php\" service requires a version (e.g. \"php83\") to restart.');\n }\n\n await this.client.post(`${this.basePath}/services/${service}/actions`, {\n action: \"reboot\",\n ...(options.version ? { version: options.version } : {}),\n });\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 { ServicesCollection } from \"./services.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 /** Services (nginx, php, mysql, etc.) on this server. */\n readonly services: ServicesCollection;\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 this.services = new ServicesCollection(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/services.ts","../src/resources/php.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, { environment: 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, { config: 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 BackgroundProcessLogAttributes,\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 * Get the log output of a daemon.\n *\n * @example\n * ```ts\n * const log = await forge.server(123).daemons.log(789);\n * ```\n */\n async log(daemonId: number): Promise<string> {\n const response = await this.client.get<JsonApiDocument<BackgroundProcessLogAttributes>>(\n `${this.basePath}/${daemonId}/log`,\n );\n return unwrapDocument(response).content;\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 { HttpClient, JsonApiDocument, ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { unwrapDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * The six restartable services exposed by the Forge v2 API.\n */\nexport const RESTARTABLE_SERVICES = [\n \"nginx\",\n \"php\",\n \"mysql\",\n \"postgres\",\n \"redis\",\n \"supervisor\",\n] as const;\n\nexport type RestartableService = (typeof RESTARTABLE_SERVICES)[number];\n\n/**\n * A single service availability row.\n *\n * `available` is a documented heuristic derived from the server object, since\n * the API has no services GET endpoint.\n */\nexport interface ServiceStatus {\n service: string;\n available: boolean;\n detail: string | null;\n}\n\n/**\n * Options for restarting a service.\n */\nexport interface RestartServiceOptions {\n /** PHP version (e.g. \"php83\") — required when restarting the php service. */\n version?: string;\n}\n\n/**\n * Services on a server — list availability and restart individual services.\n *\n * Access via `forge.server(id).services`.\n *\n * The v2 API has no GET endpoint for services, so `list()` derives availability\n * from the server object. Restarting maps to the API action `reboot`.\n *\n * @example\n * ```ts\n * // List services and their availability\n * const services = await forge.server(123).services.list();\n *\n * // Restart nginx\n * await forge.server(123).services.restart('nginx');\n *\n * // Restart php (version required)\n * await forge.server(123).services.restart('php', { version: 'php83' });\n * ```\n */\nexport class ServicesCollection 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}`;\n }\n\n /**\n * List services on this server with a derived availability flag.\n *\n * @example\n * ```ts\n * const services = await forge.server(123).services.list();\n * // → [{ service: 'nginx', available: true, detail: null }, ...]\n * ```\n */\n async list(): Promise<ServiceStatus[]> {\n const response = await this.client.get<JsonApiDocument<ServerAttributes>>(this.basePath);\n const server = unwrapDocument(response);\n\n const databaseType = server.database_type ?? \"\";\n const isMysql = databaseType.startsWith(\"mysql\") || databaseType.startsWith(\"mariadb\");\n const isPostgres = databaseType.startsWith(\"postgres\");\n\n return [\n { service: \"nginx\", available: true, detail: null },\n { service: \"php\", available: server.php_version !== null, detail: server.php_version },\n { service: \"mysql\", available: isMysql, detail: isMysql ? server.database_type : null },\n {\n service: \"postgres\",\n available: isPostgres,\n detail: isPostgres ? server.database_type : null,\n },\n { service: \"redis\", available: server.redis_status !== null, detail: server.redis_status },\n { service: \"supervisor\", available: true, detail: null },\n ];\n }\n\n /**\n * Restart a service on this server.\n *\n * Maps to the API action `reboot`. The php service requires a `version`.\n *\n * @example\n * ```ts\n * await forge.server(123).services.restart('nginx');\n * await forge.server(123).services.restart('php', { version: 'php83' });\n * ```\n */\n async restart(service: string, options: RestartServiceOptions = {}): Promise<void> {\n if (!(RESTARTABLE_SERVICES as readonly string[]).includes(service)) {\n throw new Error(\n `Invalid service \"${service}\". Valid services: ${RESTARTABLE_SERVICES.join(\", \")}.`,\n );\n }\n\n if (service === \"php\" && !options.version) {\n throw new Error('The \"php\" service requires a version (e.g. \"php83\") to restart.');\n }\n\n await this.client.post(`${this.basePath}/services/${service}/actions`, {\n action: \"reboot\",\n ...(options.version ? { version: options.version } : {}),\n });\n }\n}\n","import type {\n HttpClient,\n JsonApiDocument,\n JsonApiListDocument,\n PhpConfigAttributes,\n PhpMaxExecutionTimeAttributes,\n PhpMaxUploadSizeAttributes,\n PhpOpcacheAttributes,\n PhpVersionAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unwrapDocument, unwrapListDocument } from \"@studiometa/forge-api\";\n\nimport { BaseCollection } from \"./base.ts\";\n\n/**\n * The PHP configuration files that Forge can read and write.\n */\nexport const PHP_CONFIG_TYPES = [\"cli\", \"fpm\", \"pool\"] as const;\n\n/**\n * A PHP configuration file that Forge can read and write.\n */\nexport type PhpConfigType = (typeof PHP_CONFIG_TYPES)[number];\n\n/**\n * Options for listing PHP versions.\n */\nexport interface PhpVersionListOptions {\n /** Cursor for pagination (from previous response's next_cursor). */\n cursor?: string;\n}\n\n/**\n * Options for reading or writing a PHP configuration file.\n */\nexport interface PhpConfigOptions {\n /** Unix user of the FPM pool (pool only). */\n user?: string;\n}\n\n/**\n * Throw when the configuration type is not one of cli, fpm or pool,\n * or when a user is given for a type other than pool.\n */\nfunction assertConfigTarget(type: string, options: PhpConfigOptions): void {\n if (!(PHP_CONFIG_TYPES as readonly string[]).includes(type)) {\n throw new Error(\n `Invalid PHP config type \"${type}\". Valid types: ${PHP_CONFIG_TYPES.join(\", \")}.`,\n );\n }\n\n if (options.user && type !== \"pool\") {\n throw new Error(`The user option applies to the pool config only, not \"${type}\".`);\n }\n}\n\n/**\n * PHP on a server — installed versions, configuration files, limits and OPcache.\n *\n * Access via `forge.server(id).php`.\n *\n * Version methods take the PHP version ID from `list()`.\n *\n * @example\n * ```ts\n * const versions = await forge.server(123).php.list();\n * const fpm = await forge.server(123).php.config(versions[0].id, 'fpm');\n * await forge.server(123).php.setMaxUploadSize(64);\n * await forge.server(123).php.enableOpcache();\n * ```\n */\nexport class PhpResource 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}/php`;\n }\n\n /**\n * List the PHP versions installed on this server.\n *\n * @example\n * ```ts\n * const versions = await forge.server(123).php.list();\n * // → [{ id: 12, version: '8.3', binary_name: 'php8.3', status: 'installed', ... }]\n * ```\n */\n async list(\n options: PhpVersionListOptions = {},\n ): Promise<Array<PhpVersionAttributes & { id: number }>> {\n const query = options.cursor !== undefined ? `?page[cursor]=${options.cursor}` : \"\";\n const response = await this.client.get<JsonApiListDocument<PhpVersionAttributes>>(\n `${this.basePath}/versions${query}`,\n );\n return unwrapListDocument(response);\n }\n\n /**\n * Get one installed PHP version.\n *\n * @example\n * ```ts\n * const version = await forge.server(123).php.get(12);\n * ```\n */\n async get(versionId: number): Promise<PhpVersionAttributes & { id: number }> {\n const response = await this.client.get<JsonApiDocument<PhpVersionAttributes>>(\n `${this.basePath}/versions/${versionId}`,\n );\n return unwrapDocument(response);\n }\n\n /**\n * Get a PHP configuration file (cli, fpm or pool) of a version.\n *\n * @example\n * ```ts\n * const ini = await forge.server(123).php.config(12, 'fpm');\n * const pool = await forge.server(123).php.config(12, 'pool', { user: 'forge' });\n * ```\n */\n async config(\n versionId: number,\n type: PhpConfigType,\n options: PhpConfigOptions = {},\n ): Promise<string> {\n assertConfigTarget(type, options);\n const query = options.user ? `?user=${encodeURIComponent(options.user)}` : \"\";\n const response = await this.client.get<JsonApiDocument<PhpConfigAttributes>>(\n `${this.basePath}/versions/${versionId}/configs/${type}${query}`,\n );\n return unwrapDocument(response).configuration;\n }\n\n /**\n * Replace a PHP configuration file (cli, fpm or pool) of a version.\n *\n * @example\n * ```ts\n * await forge.server(123).php.updateConfig(12, 'fpm', 'memory_limit = 512M\\n...');\n * ```\n */\n async updateConfig(\n versionId: number,\n type: PhpConfigType,\n content: string,\n options: PhpConfigOptions = {},\n ): Promise<void> {\n assertConfigTarget(type, options);\n await this.client.put(`${this.basePath}/versions/${versionId}/configs/${type}`, {\n config: content,\n ...(options.user ? { user: options.user } : {}),\n });\n }\n\n /**\n * Get the PHP max upload size, in megabytes.\n *\n * @example\n * ```ts\n * const size = await forge.server(123).php.maxUploadSize(); // → \"64\"\n * ```\n */\n async maxUploadSize(): Promise<string> {\n const response = await this.client.get<JsonApiDocument<PhpMaxUploadSizeAttributes>>(\n `${this.basePath}/max-upload-size`,\n );\n return String(unwrapDocument(response).max_upload_size);\n }\n\n /**\n * Set the PHP max upload size, in megabytes.\n *\n * @example\n * ```ts\n * await forge.server(123).php.setMaxUploadSize(128);\n * ```\n */\n async setMaxUploadSize(size: number): Promise<void> {\n await this.client.put(`${this.basePath}/max-upload-size`, { max_upload_size: size });\n }\n\n /**\n * Get the PHP max execution time, in seconds.\n *\n * @example\n * ```ts\n * const seconds = await forge.server(123).php.maxExecutionTime(); // → \"60\"\n * ```\n */\n async maxExecutionTime(): Promise<string> {\n const response = await this.client.get<JsonApiDocument<PhpMaxExecutionTimeAttributes>>(\n `${this.basePath}/max-execution-time`,\n );\n return String(unwrapDocument(response).max_execution_time);\n }\n\n /**\n * Set the PHP max execution time, in seconds.\n *\n * @example\n * ```ts\n * await forge.server(123).php.setMaxExecutionTime(120);\n * ```\n */\n async setMaxExecutionTime(seconds: number): Promise<void> {\n await this.client.put(`${this.basePath}/max-execution-time`, { max_execution_time: seconds });\n }\n\n /**\n * Get whether OPcache is enabled.\n *\n * @example\n * ```ts\n * const enabled = await forge.server(123).php.opcache(); // → true\n * ```\n */\n async opcache(): Promise<boolean> {\n const response = await this.client.get<JsonApiDocument<PhpOpcacheAttributes>>(\n `${this.basePath}/opcache`,\n );\n return unwrapDocument(response).opcache_enabled;\n }\n\n /**\n * Enable OPcache.\n *\n * @example\n * ```ts\n * await forge.server(123).php.enableOpcache();\n * ```\n */\n async enableOpcache(): Promise<void> {\n await this.client.post(`${this.basePath}/opcache`);\n }\n\n /**\n * Disable OPcache.\n *\n * @example\n * ```ts\n * await forge.server(123).php.disableOpcache();\n * ```\n */\n async disableOpcache(): Promise<void> {\n await this.client.delete(`${this.basePath}/opcache`);\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 { ServicesCollection } from \"./services.ts\";\nimport { PhpResource } from \"./php.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 /** Services (nginx, php, mysql, etc.) on this server. */\n readonly services: ServicesCollection;\n\n /** PHP versions, configuration files, limits and OPcache on this server. */\n readonly php: PhpResource;\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 this.services = new ServicesCollection(client, orgSlug, serverId);\n this.php = new PhpResource(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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"}
@@ -0,0 +1,151 @@
1
+ import type { HttpClient, PhpVersionAttributes } from "@studiometa/forge-api";
2
+ import { BaseCollection } from "./base.ts";
3
+ /**
4
+ * The PHP configuration files that Forge can read and write.
5
+ */
6
+ export declare const PHP_CONFIG_TYPES: readonly ["cli", "fpm", "pool"];
7
+ /**
8
+ * A PHP configuration file that Forge can read and write.
9
+ */
10
+ export type PhpConfigType = (typeof PHP_CONFIG_TYPES)[number];
11
+ /**
12
+ * Options for listing PHP versions.
13
+ */
14
+ export interface PhpVersionListOptions {
15
+ /** Cursor for pagination (from previous response's next_cursor). */
16
+ cursor?: string;
17
+ }
18
+ /**
19
+ * Options for reading or writing a PHP configuration file.
20
+ */
21
+ export interface PhpConfigOptions {
22
+ /** Unix user of the FPM pool (pool only). */
23
+ user?: string;
24
+ }
25
+ /**
26
+ * PHP on a server — installed versions, configuration files, limits and OPcache.
27
+ *
28
+ * Access via `forge.server(id).php`.
29
+ *
30
+ * Version methods take the PHP version ID from `list()`.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const versions = await forge.server(123).php.list();
35
+ * const fpm = await forge.server(123).php.config(versions[0].id, 'fpm');
36
+ * await forge.server(123).php.setMaxUploadSize(64);
37
+ * await forge.server(123).php.enableOpcache();
38
+ * ```
39
+ */
40
+ export declare class PhpResource extends BaseCollection {
41
+ private readonly serverId;
42
+ /** @internal */
43
+ constructor(client: HttpClient, orgSlug: string, serverId: number);
44
+ private get basePath();
45
+ /**
46
+ * List the PHP versions installed on this server.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const versions = await forge.server(123).php.list();
51
+ * // → [{ id: 12, version: '8.3', binary_name: 'php8.3', status: 'installed', ... }]
52
+ * ```
53
+ */
54
+ list(options?: PhpVersionListOptions): Promise<Array<PhpVersionAttributes & {
55
+ id: number;
56
+ }>>;
57
+ /**
58
+ * Get one installed PHP version.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const version = await forge.server(123).php.get(12);
63
+ * ```
64
+ */
65
+ get(versionId: number): Promise<PhpVersionAttributes & {
66
+ id: number;
67
+ }>;
68
+ /**
69
+ * Get a PHP configuration file (cli, fpm or pool) of a version.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const ini = await forge.server(123).php.config(12, 'fpm');
74
+ * const pool = await forge.server(123).php.config(12, 'pool', { user: 'forge' });
75
+ * ```
76
+ */
77
+ config(versionId: number, type: PhpConfigType, options?: PhpConfigOptions): Promise<string>;
78
+ /**
79
+ * Replace a PHP configuration file (cli, fpm or pool) of a version.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * await forge.server(123).php.updateConfig(12, 'fpm', 'memory_limit = 512M\n...');
84
+ * ```
85
+ */
86
+ updateConfig(versionId: number, type: PhpConfigType, content: string, options?: PhpConfigOptions): Promise<void>;
87
+ /**
88
+ * Get the PHP max upload size, in megabytes.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const size = await forge.server(123).php.maxUploadSize(); // → "64"
93
+ * ```
94
+ */
95
+ maxUploadSize(): Promise<string>;
96
+ /**
97
+ * Set the PHP max upload size, in megabytes.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * await forge.server(123).php.setMaxUploadSize(128);
102
+ * ```
103
+ */
104
+ setMaxUploadSize(size: number): Promise<void>;
105
+ /**
106
+ * Get the PHP max execution time, in seconds.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const seconds = await forge.server(123).php.maxExecutionTime(); // → "60"
111
+ * ```
112
+ */
113
+ maxExecutionTime(): Promise<string>;
114
+ /**
115
+ * Set the PHP max execution time, in seconds.
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * await forge.server(123).php.setMaxExecutionTime(120);
120
+ * ```
121
+ */
122
+ setMaxExecutionTime(seconds: number): Promise<void>;
123
+ /**
124
+ * Get whether OPcache is enabled.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const enabled = await forge.server(123).php.opcache(); // → true
129
+ * ```
130
+ */
131
+ opcache(): Promise<boolean>;
132
+ /**
133
+ * Enable OPcache.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * await forge.server(123).php.enableOpcache();
138
+ * ```
139
+ */
140
+ enableOpcache(): Promise<void>;
141
+ /**
142
+ * Disable OPcache.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * await forge.server(123).php.disableOpcache();
147
+ * ```
148
+ */
149
+ disableOpcache(): Promise<void>;
150
+ }
151
+ //# sourceMappingURL=php.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"php.d.ts","sourceRoot":"","sources":["../../src/resources/php.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAOV,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,YAAI,KAAK,EAAE,KAAK,EAAE,MAAM,CAAU,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAY,SAAQ,cAAc;IAK3C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ3B,gBAAgB;IAChB,YACE,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,EACE,QAAQ,EAAE,MAAM,EAGlC;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED;;;;;;;;OAQG;IACG,IAAI,CACR,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAMvD;IAED;;;;;;;OAOG;IACG,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAK3E;IAED;;;;;;;;OAQG;IACG,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAOjB;IAED;;;;;;;OAOG;IACG,YAAY,CAChB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAMf;IAED;;;;;;;OAOG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAKrC;IAED;;;;;;;OAOG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElD;IAED;;;;;;;OAOG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAKxC;IAED;;;;;;;OAOG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;IAED;;;;;;;OAOG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAKhC;IAED;;;;;;;OAOG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAED;;;;;;;OAOG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpC;CACF"}
@@ -11,6 +11,7 @@ import { FirewallRulesCollection } from "./firewall-rules.ts";
11
11
  import { SshKeysCollection } from "./ssh-keys.ts";
12
12
  import { NginxTemplatesCollection } from "./nginx-templates.ts";
13
13
  import { ServicesCollection } from "./services.ts";
14
+ import { PhpResource } from "./php.ts";
14
15
  import { BaseCollection } from "./base.ts";
15
16
  /**
16
17
  * A matched resource item with ID and name.
@@ -203,6 +204,8 @@ export declare class ServerResource extends BaseCollection {
203
204
  readonly nginxTemplates: NginxTemplatesCollection;
204
205
  /** Services (nginx, php, mysql, etc.) on this server. */
205
206
  readonly services: ServicesCollection;
207
+ /** PHP versions, configuration files, limits and OPcache on this server. */
208
+ readonly php: PhpResource;
206
209
  /** @internal */
207
210
  constructor(client: HttpClient, orgSlug: string, serverId: number);
208
211
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/resources/servers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/resources/servers.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiometa/forge-sdk",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
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.6"
47
+ "@studiometa/forge-api": "0.4.8"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@typescript/native-preview": "^7.0.0-dev.20260409.1",