deploynest 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # DeployNest API Client
2
+
3
+ Programmatic, type-safe client for the DeployNest HTTP API. Built on [Hono's typed client](https://hono.dev/docs/guides/rpc) so requests stay in sync with the server route definitions.
4
+
5
+ ## Installation
6
+
7
+ Inside the DeployNest monorepo, the package is available as a workspace dependency:
8
+
9
+ ```bash
10
+ bun add deploynest
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```ts
16
+ import { DeployNestClient } from "deploynest"
17
+
18
+ const api = new DeployNestClient("https://deploynest.app")
19
+
20
+ const result = await api.servers.getServers("org_abc123")
21
+
22
+ if (result.success) {
23
+ console.log(result.servers)
24
+ } else {
25
+ console.error(result.message)
26
+ }
27
+ ```
28
+
29
+ When used from the DeployNest web app, pass the current origin so requests stay same-origin and session cookies are sent automatically:
30
+
31
+ ```ts
32
+ const api = new DeployNestClient(window.location.origin, {
33
+ userAgent: "DeployNest/1.0.0",
34
+ })
35
+ ```
36
+
37
+ ## Configuration
38
+
39
+ ```ts
40
+ import { DeployNestClient, type ClientOptions } from "deploynest"
41
+
42
+ const opts: ClientOptions = {
43
+ bearerToken: "your-token", // optional Authorization: Bearer header
44
+ userAgent: "MyApp/1.0.0", // optional User-Agent header
45
+ }
46
+
47
+ const api = new DeployNestClient("https://deploynest.app", opts)
48
+ ```
49
+
50
+ | Option | Description |
51
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
52
+ | `baseURL` | Deployment origin (e.g. `https://deploynest.app` or `http://localhost:3000`). Do not include `/api` — resource paths are appended automatically. |
53
+ | `bearerToken` | Sets an `Authorization: Bearer …` header on every request. |
54
+ | `userAgent` | Sets a custom `User-Agent` header on every request. |
55
+
56
+ ## Response shape
57
+
58
+ Every method returns a discriminated result. Check `success` before reading the payload:
59
+
60
+ ```ts
61
+ // Success
62
+ { success: true, servers: [...] }
63
+ { success: true, credential: {...} }
64
+
65
+ // Failure
66
+ { success: false, message: "Forbidden." }
67
+ ```
68
+
69
+ ## Authentication
70
+
71
+ All endpoints require authentication. When the client runs in the browser against the same origin as the app, session cookies are included automatically.
72
+
73
+ For server-side or external scripts, pass a bearer token via `ClientOptions.bearerToken`.
74
+
75
+ Every organization-scoped method requires an `organizationId`. The API validates that the authenticated user has the appropriate organization permission before returning data.
@@ -0,0 +1,12 @@
1
+ import type { Hono } from "hono";
2
+ import { hc } from "hono/client";
3
+ export type HonoClient<App extends Hono> = ReturnType<typeof hc<App>>;
4
+ export interface BaseClientOptions {
5
+ bearerToken?: string;
6
+ userAgent?: string;
7
+ }
8
+ export declare class BaseClient<HonoApp extends Hono> {
9
+ readonly baseURL: string;
10
+ readonly client: HonoClient<HonoApp>;
11
+ constructor(baseURL: string, basePath: string, opts: BaseClientOptions);
12
+ }
@@ -0,0 +1,35 @@
1
+ // src/utils.ts
2
+ function path(baseURL, path2) {
3
+ const normalizedBase = baseURL.replace(/\/+$/, "");
4
+ const normalizedPath = path2.replace(/^\/+/, "");
5
+ if (!normalizedPath) {
6
+ return normalizedBase || "/";
7
+ }
8
+ return `${normalizedBase}/${normalizedPath}`;
9
+ }
10
+
11
+ // src/clients/base.ts
12
+ import { hc } from "hono/client";
13
+ class BaseClient {
14
+ baseURL;
15
+ client;
16
+ constructor(baseURL, basePath, opts) {
17
+ let headers = {};
18
+ if (opts.bearerToken) {
19
+ headers.Authorization = `Bearer ${opts.bearerToken}`;
20
+ }
21
+ if (opts.userAgent) {
22
+ headers["User-Agent"] = opts.userAgent;
23
+ }
24
+ if (Object.keys(headers).length === 0) {
25
+ headers = undefined;
26
+ }
27
+ this.baseURL = path(baseURL, basePath);
28
+ this.client = hc(this.baseURL, {
29
+ headers
30
+ });
31
+ }
32
+ }
33
+ export {
34
+ BaseClient
35
+ };
@@ -0,0 +1,54 @@
1
+ import { type BaseClientOptions } from "./base";
2
+ export declare class CredentialsClient {
3
+ private readonly base;
4
+ constructor(baseURL: string, opts: BaseClientOptions);
5
+ private get client();
6
+ getCredentials(organizationId: string): Promise<{
7
+ success: boolean;
8
+ credentials: {
9
+ id: string;
10
+ name: string;
11
+ type: "private_key";
12
+ publicKey: string | null;
13
+ fingerprint: string | null;
14
+ createdAt: string;
15
+ }[];
16
+ message?: undefined;
17
+ } | {
18
+ success: boolean;
19
+ message: string;
20
+ credentials?: undefined;
21
+ }>;
22
+ createCredential(organizationId: string, name: string, privateKey: string): Promise<{
23
+ success: boolean;
24
+ credential: {
25
+ id: `${string}-${string}-${string}-${string}-${string}`;
26
+ name: string;
27
+ type: string;
28
+ publicKey: string;
29
+ fingerprint: string;
30
+ createdAt: string;
31
+ };
32
+ message?: undefined;
33
+ } | {
34
+ success: boolean;
35
+ message: string;
36
+ credential?: undefined;
37
+ }>;
38
+ generatePrivateKey(): Promise<{
39
+ success: boolean;
40
+ privateKey: string;
41
+ message?: undefined;
42
+ } | {
43
+ success: boolean;
44
+ message: string;
45
+ privateKey?: undefined;
46
+ }>;
47
+ deleteCredential(credentialId: string, organizationId: string): Promise<{
48
+ success: boolean;
49
+ message?: undefined;
50
+ } | {
51
+ success: boolean;
52
+ message: string;
53
+ }>;
54
+ }
@@ -0,0 +1,115 @@
1
+ // src/utils.ts
2
+ function path(baseURL, path2) {
3
+ const normalizedBase = baseURL.replace(/\/+$/, "");
4
+ const normalizedPath = path2.replace(/^\/+/, "");
5
+ if (!normalizedPath) {
6
+ return normalizedBase || "/";
7
+ }
8
+ return `${normalizedBase}/${normalizedPath}`;
9
+ }
10
+
11
+ // src/clients/base.ts
12
+ import { hc } from "hono/client";
13
+ class BaseClient {
14
+ baseURL;
15
+ client;
16
+ constructor(baseURL, basePath, opts) {
17
+ let headers = {};
18
+ if (opts.bearerToken) {
19
+ headers.Authorization = `Bearer ${opts.bearerToken}`;
20
+ }
21
+ if (opts.userAgent) {
22
+ headers["User-Agent"] = opts.userAgent;
23
+ }
24
+ if (Object.keys(headers).length === 0) {
25
+ headers = undefined;
26
+ }
27
+ this.baseURL = path(baseURL, basePath);
28
+ this.client = hc(this.baseURL, {
29
+ headers
30
+ });
31
+ }
32
+ }
33
+
34
+ // src/clients/credentials.ts
35
+ class CredentialsClient {
36
+ base;
37
+ constructor(baseURL, opts) {
38
+ this.base = new BaseClient(baseURL, "/api/credentials", opts);
39
+ }
40
+ get client() {
41
+ return this.base.client;
42
+ }
43
+ async getCredentials(organizationId) {
44
+ const response = await this.client.index.$get({
45
+ query: {
46
+ organizationId
47
+ }
48
+ });
49
+ if (response.ok) {
50
+ const data2 = await response.json();
51
+ return {
52
+ success: true,
53
+ credentials: data2.credentials
54
+ };
55
+ }
56
+ const data = await response.json();
57
+ return {
58
+ success: false,
59
+ message: data.message
60
+ };
61
+ }
62
+ async createCredential(organizationId, name, privateKey) {
63
+ const response = await this.client.index.$post({
64
+ json: {
65
+ organizationId,
66
+ name,
67
+ privateKey
68
+ }
69
+ });
70
+ if (response.ok) {
71
+ const data2 = await response.json();
72
+ return {
73
+ success: true,
74
+ credential: data2.credential
75
+ };
76
+ }
77
+ const data = await response.json();
78
+ return {
79
+ success: false,
80
+ message: data.message
81
+ };
82
+ }
83
+ async generatePrivateKey() {
84
+ const response = await this.client["generate-private-key"].$post();
85
+ if (response.ok) {
86
+ const data2 = await response.json();
87
+ return {
88
+ success: true,
89
+ privateKey: data2.privateKey
90
+ };
91
+ }
92
+ const data = await response.json();
93
+ return {
94
+ success: false,
95
+ message: data.message
96
+ };
97
+ }
98
+ async deleteCredential(credentialId, organizationId) {
99
+ const response = await this.client[":credentialId"].$delete({
100
+ param: { credentialId },
101
+ query: { organizationId }
102
+ });
103
+ if (response.ok) {
104
+ return { success: true };
105
+ }
106
+ const data = await response.json();
107
+ return {
108
+ success: false,
109
+ message: data.message
110
+ };
111
+ }
112
+ }
113
+ export {
114
+ CredentialsClient
115
+ };
@@ -0,0 +1,60 @@
1
+ import { type BaseClientOptions } from "./base";
2
+ export declare class ServersClient {
3
+ private readonly base;
4
+ constructor(baseURL: string, opts: BaseClientOptions);
5
+ private get client();
6
+ getServers(organizationId: string): Promise<{
7
+ success: boolean;
8
+ servers: {
9
+ id: string;
10
+ ip: string;
11
+ port: number;
12
+ username: string;
13
+ setup: boolean;
14
+ privateKeyCredentialId: string;
15
+ privateKeyCredentialName: string;
16
+ createdAt: string;
17
+ }[];
18
+ message?: undefined;
19
+ } | {
20
+ success: boolean;
21
+ message: string;
22
+ servers?: undefined;
23
+ }>;
24
+ createServer(organizationId: string, ip: string, port: number, username: string, privateKeyCredentialId: string): Promise<{
25
+ success: boolean;
26
+ server: {
27
+ id: string;
28
+ ip: string;
29
+ port: number;
30
+ username: string;
31
+ setup: boolean;
32
+ privateKeyCredentialId: string;
33
+ privateKeyCredentialName: string;
34
+ createdAt: string;
35
+ };
36
+ message?: undefined;
37
+ } | {
38
+ success: boolean;
39
+ message: string;
40
+ server?: undefined;
41
+ }>;
42
+ setupServer(serverId: string, organizationId: string): Promise<{
43
+ alreadyInstalled: boolean;
44
+ dockerVersion: string;
45
+ log: string[];
46
+ ok: true;
47
+ success: boolean;
48
+ message?: undefined;
49
+ } | {
50
+ success: boolean;
51
+ message: string;
52
+ }>;
53
+ deleteServer(serverId: string, organizationId: string): Promise<{
54
+ success: boolean;
55
+ message?: undefined;
56
+ } | {
57
+ success: boolean;
58
+ message: string;
59
+ }>;
60
+ }
@@ -0,0 +1,120 @@
1
+ // src/utils.ts
2
+ function path(baseURL, path2) {
3
+ const normalizedBase = baseURL.replace(/\/+$/, "");
4
+ const normalizedPath = path2.replace(/^\/+/, "");
5
+ if (!normalizedPath) {
6
+ return normalizedBase || "/";
7
+ }
8
+ return `${normalizedBase}/${normalizedPath}`;
9
+ }
10
+
11
+ // src/clients/base.ts
12
+ import { hc } from "hono/client";
13
+ class BaseClient {
14
+ baseURL;
15
+ client;
16
+ constructor(baseURL, basePath, opts) {
17
+ let headers = {};
18
+ if (opts.bearerToken) {
19
+ headers.Authorization = `Bearer ${opts.bearerToken}`;
20
+ }
21
+ if (opts.userAgent) {
22
+ headers["User-Agent"] = opts.userAgent;
23
+ }
24
+ if (Object.keys(headers).length === 0) {
25
+ headers = undefined;
26
+ }
27
+ this.baseURL = path(baseURL, basePath);
28
+ this.client = hc(this.baseURL, {
29
+ headers
30
+ });
31
+ }
32
+ }
33
+
34
+ // src/clients/servers.ts
35
+ class ServersClient {
36
+ base;
37
+ constructor(baseURL, opts) {
38
+ this.base = new BaseClient(baseURL, "/api/servers", opts);
39
+ }
40
+ get client() {
41
+ return this.base.client;
42
+ }
43
+ async getServers(organizationId) {
44
+ const response = await this.client.index.$get({
45
+ query: {
46
+ organizationId
47
+ }
48
+ });
49
+ if (response.ok) {
50
+ const data2 = await response.json();
51
+ return {
52
+ success: true,
53
+ servers: data2.servers
54
+ };
55
+ }
56
+ const data = await response.json();
57
+ return {
58
+ success: false,
59
+ message: data.message
60
+ };
61
+ }
62
+ async createServer(organizationId, ip, port, username, privateKeyCredentialId) {
63
+ const response = await this.client.index.$post({
64
+ json: {
65
+ organizationId,
66
+ ip,
67
+ port,
68
+ username,
69
+ privateKeyCredentialId
70
+ }
71
+ });
72
+ if (response.ok) {
73
+ const data2 = await response.json();
74
+ return {
75
+ success: true,
76
+ server: data2.server
77
+ };
78
+ }
79
+ const data = await response.json();
80
+ return {
81
+ success: false,
82
+ message: data.message
83
+ };
84
+ }
85
+ async setupServer(serverId, organizationId) {
86
+ const response = await this.client[":serverId"].setup.$post({
87
+ param: { serverId },
88
+ query: { organizationId }
89
+ });
90
+ if (response.ok) {
91
+ const data2 = await response.json();
92
+ return {
93
+ success: true,
94
+ ...data2
95
+ };
96
+ }
97
+ const data = await response.json();
98
+ return {
99
+ success: false,
100
+ message: data.message
101
+ };
102
+ }
103
+ async deleteServer(serverId, organizationId) {
104
+ const response = await this.client[":serverId"].$delete({
105
+ param: { serverId },
106
+ query: { organizationId }
107
+ });
108
+ if (response.ok) {
109
+ return { success: true };
110
+ }
111
+ const data = await response.json();
112
+ return {
113
+ success: false,
114
+ message: data.message
115
+ };
116
+ }
117
+ }
118
+ export {
119
+ ServersClient
120
+ };
@@ -0,0 +1,10 @@
1
+ import { type BaseClientOptions } from "~/clients/base";
2
+ import { CredentialsClient } from "~/clients/credentials";
3
+ import { ServersClient } from "~/clients/servers";
4
+ export type ClientOptions = BaseClientOptions;
5
+ export declare class DeployNestClient {
6
+ readonly baseURL: string;
7
+ readonly credentials: CredentialsClient;
8
+ readonly servers: ServersClient;
9
+ constructor(baseURL?: string, opts?: ClientOptions);
10
+ }
package/dist/index.js ADDED
@@ -0,0 +1,212 @@
1
+ // src/utils.ts
2
+ function path(baseURL, path2) {
3
+ const normalizedBase = baseURL.replace(/\/+$/, "");
4
+ const normalizedPath = path2.replace(/^\/+/, "");
5
+ if (!normalizedPath) {
6
+ return normalizedBase || "/";
7
+ }
8
+ return `${normalizedBase}/${normalizedPath}`;
9
+ }
10
+
11
+ // src/clients/base.ts
12
+ import { hc } from "hono/client";
13
+ class BaseClient {
14
+ baseURL;
15
+ client;
16
+ constructor(baseURL, basePath, opts) {
17
+ let headers = {};
18
+ if (opts.bearerToken) {
19
+ headers.Authorization = `Bearer ${opts.bearerToken}`;
20
+ }
21
+ if (opts.userAgent) {
22
+ headers["User-Agent"] = opts.userAgent;
23
+ }
24
+ if (Object.keys(headers).length === 0) {
25
+ headers = undefined;
26
+ }
27
+ this.baseURL = path(baseURL, basePath);
28
+ this.client = hc(this.baseURL, {
29
+ headers
30
+ });
31
+ }
32
+ }
33
+
34
+ // src/clients/credentials.ts
35
+ class CredentialsClient {
36
+ base;
37
+ constructor(baseURL, opts) {
38
+ this.base = new BaseClient(baseURL, "/api/credentials", opts);
39
+ }
40
+ get client() {
41
+ return this.base.client;
42
+ }
43
+ async getCredentials(organizationId) {
44
+ const response = await this.client.index.$get({
45
+ query: {
46
+ organizationId
47
+ }
48
+ });
49
+ if (response.ok) {
50
+ const data2 = await response.json();
51
+ return {
52
+ success: true,
53
+ credentials: data2.credentials
54
+ };
55
+ }
56
+ const data = await response.json();
57
+ return {
58
+ success: false,
59
+ message: data.message
60
+ };
61
+ }
62
+ async createCredential(organizationId, name, privateKey) {
63
+ const response = await this.client.index.$post({
64
+ json: {
65
+ organizationId,
66
+ name,
67
+ privateKey
68
+ }
69
+ });
70
+ if (response.ok) {
71
+ const data2 = await response.json();
72
+ return {
73
+ success: true,
74
+ credential: data2.credential
75
+ };
76
+ }
77
+ const data = await response.json();
78
+ return {
79
+ success: false,
80
+ message: data.message
81
+ };
82
+ }
83
+ async generatePrivateKey() {
84
+ const response = await this.client["generate-private-key"].$post();
85
+ if (response.ok) {
86
+ const data2 = await response.json();
87
+ return {
88
+ success: true,
89
+ privateKey: data2.privateKey
90
+ };
91
+ }
92
+ const data = await response.json();
93
+ return {
94
+ success: false,
95
+ message: data.message
96
+ };
97
+ }
98
+ async deleteCredential(credentialId, organizationId) {
99
+ const response = await this.client[":credentialId"].$delete({
100
+ param: { credentialId },
101
+ query: { organizationId }
102
+ });
103
+ if (response.ok) {
104
+ return { success: true };
105
+ }
106
+ const data = await response.json();
107
+ return {
108
+ success: false,
109
+ message: data.message
110
+ };
111
+ }
112
+ }
113
+
114
+ // src/clients/servers.ts
115
+ class ServersClient {
116
+ base;
117
+ constructor(baseURL, opts) {
118
+ this.base = new BaseClient(baseURL, "/api/servers", opts);
119
+ }
120
+ get client() {
121
+ return this.base.client;
122
+ }
123
+ async getServers(organizationId) {
124
+ const response = await this.client.index.$get({
125
+ query: {
126
+ organizationId
127
+ }
128
+ });
129
+ if (response.ok) {
130
+ const data2 = await response.json();
131
+ return {
132
+ success: true,
133
+ servers: data2.servers
134
+ };
135
+ }
136
+ const data = await response.json();
137
+ return {
138
+ success: false,
139
+ message: data.message
140
+ };
141
+ }
142
+ async createServer(organizationId, ip, port, username, privateKeyCredentialId) {
143
+ const response = await this.client.index.$post({
144
+ json: {
145
+ organizationId,
146
+ ip,
147
+ port,
148
+ username,
149
+ privateKeyCredentialId
150
+ }
151
+ });
152
+ if (response.ok) {
153
+ const data2 = await response.json();
154
+ return {
155
+ success: true,
156
+ server: data2.server
157
+ };
158
+ }
159
+ const data = await response.json();
160
+ return {
161
+ success: false,
162
+ message: data.message
163
+ };
164
+ }
165
+ async setupServer(serverId, organizationId) {
166
+ const response = await this.client[":serverId"].setup.$post({
167
+ param: { serverId },
168
+ query: { organizationId }
169
+ });
170
+ if (response.ok) {
171
+ const data2 = await response.json();
172
+ return {
173
+ success: true,
174
+ ...data2
175
+ };
176
+ }
177
+ const data = await response.json();
178
+ return {
179
+ success: false,
180
+ message: data.message
181
+ };
182
+ }
183
+ async deleteServer(serverId, organizationId) {
184
+ const response = await this.client[":serverId"].$delete({
185
+ param: { serverId },
186
+ query: { organizationId }
187
+ });
188
+ if (response.ok) {
189
+ return { success: true };
190
+ }
191
+ const data = await response.json();
192
+ return {
193
+ success: false,
194
+ message: data.message
195
+ };
196
+ }
197
+ }
198
+
199
+ // src/index.ts
200
+ class DeployNestClient {
201
+ baseURL;
202
+ credentials;
203
+ servers;
204
+ constructor(baseURL = "https://deploynest.app/api", opts = {}) {
205
+ this.baseURL = baseURL;
206
+ this.credentials = new CredentialsClient(baseURL, opts);
207
+ this.servers = new ServersClient(baseURL, opts);
208
+ }
209
+ }
210
+ export {
211
+ DeployNestClient
212
+ };
@@ -0,0 +1 @@
1
+ export declare function path(baseURL: string, path: string): string;
package/dist/utils.js ADDED
@@ -0,0 +1,12 @@
1
+ // src/utils.ts
2
+ function path(baseURL, path2) {
3
+ const normalizedBase = baseURL.replace(/\/+$/, "");
4
+ const normalizedPath = path2.replace(/^\/+/, "");
5
+ if (!normalizedPath) {
6
+ return normalizedBase || "/";
7
+ }
8
+ return `${normalizedBase}/${normalizedPath}`;
9
+ }
10
+ export {
11
+ path
12
+ };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "deploynest",
3
+ "version": "0.0.1",
4
+ "main": "./dist/index.js",
5
+ "devDependencies": {
6
+ "@types/bun": "1.3.14",
7
+ "typescript": "6.0.3"
8
+ },
9
+ "dependencies": {
10
+ "hono": "4.12.23"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "description": "Programmatic API client for DeployNest.",
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "rm -rf dist && bun run build.ts",
24
+ "prepack": "bun run build",
25
+ "typecheck": "tsc -p tsconfig.json --noEmit"
26
+ },
27
+ "sideEffects": false,
28
+ "type": "module",
29
+ "types": "./dist/index.d.ts"
30
+ }