@phpsandbox/sdk 0.0.53 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/phpsandbox-sdk.esm.js +245 -7
- package/dist/browser/phpsandbox-sdk.esm.min.js +3 -2
- package/dist/browser/phpsandbox-sdk.iife.js +245 -7
- package/dist/browser/phpsandbox-sdk.iife.min.js +3 -2
- package/dist/deployments.d.ts +191 -0
- package/dist/deployments.js +182 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +45 -1
- package/package.json +1 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
export class NotebookDeploymentApi {
|
|
2
|
+
constructor(client) {
|
|
3
|
+
this.client = client;
|
|
4
|
+
}
|
|
5
|
+
async create(id, input = {}) {
|
|
6
|
+
const response = await this.client.post(`/notebook/${id}/deployments`, input);
|
|
7
|
+
return new DeploymentInstance(response.data, this.client);
|
|
8
|
+
}
|
|
9
|
+
async list(id) {
|
|
10
|
+
const response = await this.client.get(`/notebook/${id}/deployments`);
|
|
11
|
+
return response.data;
|
|
12
|
+
}
|
|
13
|
+
async slugAvailability(id, slug) {
|
|
14
|
+
const query = new URLSearchParams({ slug }).toString();
|
|
15
|
+
const response = await this.client.get(`/notebook/${id}/deployments/slug-availability?${query}`);
|
|
16
|
+
return response.data;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class DeploymentApi {
|
|
20
|
+
constructor(client) {
|
|
21
|
+
this.client = client;
|
|
22
|
+
}
|
|
23
|
+
async get(id) {
|
|
24
|
+
const response = await this.client.get(`/deployments/${id}`);
|
|
25
|
+
return new DeploymentInstance(response.data, this.client);
|
|
26
|
+
}
|
|
27
|
+
async redeploy(id, input = {}) {
|
|
28
|
+
const response = await this.client.post(`/deployments/${id}/redeploy`, input);
|
|
29
|
+
return new DeploymentInstance(response.data, this.client);
|
|
30
|
+
}
|
|
31
|
+
async delete(id) {
|
|
32
|
+
await this.client.delete(`/deployments/${id}`);
|
|
33
|
+
}
|
|
34
|
+
async setProtection(id, input) {
|
|
35
|
+
const response = await this.client.put(`/deployments/${id}/protection`, input);
|
|
36
|
+
return new DeploymentInstance(response.data, this.client);
|
|
37
|
+
}
|
|
38
|
+
async protection(id) {
|
|
39
|
+
const response = await this.client.get(`/deployments/${id}/protection`);
|
|
40
|
+
return response.data;
|
|
41
|
+
}
|
|
42
|
+
async createProtectionSession(id) {
|
|
43
|
+
const response = await this.client.post(`/deployments/${id}/protection/session`);
|
|
44
|
+
return response.data;
|
|
45
|
+
}
|
|
46
|
+
async disableProtection(id) {
|
|
47
|
+
const response = await this.client.delete(`/deployments/${id}/protection`);
|
|
48
|
+
return new DeploymentInstance(response.data, this.client);
|
|
49
|
+
}
|
|
50
|
+
async setFeedback(id, input) {
|
|
51
|
+
const response = await this.client.put(`/deployments/${id}/feedback`, input);
|
|
52
|
+
return new DeploymentInstance(response.data, this.client);
|
|
53
|
+
}
|
|
54
|
+
async listDomains(id) {
|
|
55
|
+
const response = await this.client.get(`/deployments/${id}/domains`);
|
|
56
|
+
return unwrapDeploymentDomainCollection(response.data);
|
|
57
|
+
}
|
|
58
|
+
async createDomain(id, input) {
|
|
59
|
+
const response = await this.client.post(`/deployments/${id}/domains`, input);
|
|
60
|
+
return response.data;
|
|
61
|
+
}
|
|
62
|
+
async refreshDomain(id, domainId) {
|
|
63
|
+
const response = await this.client.post(`/deployments/${id}/domains/${domainId}/refresh`);
|
|
64
|
+
return response.data;
|
|
65
|
+
}
|
|
66
|
+
async deleteDomain(id, domainId) {
|
|
67
|
+
await this.client.delete(`/deployments/${id}/domains/${domainId}`);
|
|
68
|
+
}
|
|
69
|
+
async events(id) {
|
|
70
|
+
return parseNdjsonStream(await this.client.stream(`/deployments/${id}/events/stream`));
|
|
71
|
+
}
|
|
72
|
+
async buildLogs(id, buildId) {
|
|
73
|
+
return parseNdjsonStream(await this.client.stream(`/deployments/${id}/builds/${buildId}/logs/stream`));
|
|
74
|
+
}
|
|
75
|
+
async logs(id) {
|
|
76
|
+
return parseNdjsonStream(await this.client.stream(`/deployments/${id}/logs/stream`));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export class DeploymentInstance {
|
|
80
|
+
constructor(data, client) {
|
|
81
|
+
this.data = data;
|
|
82
|
+
this.client = client;
|
|
83
|
+
}
|
|
84
|
+
refresh() {
|
|
85
|
+
return this.client.deployments.get(this.data.id);
|
|
86
|
+
}
|
|
87
|
+
redeploy(input = {}) {
|
|
88
|
+
return this.client.deployments.redeploy(this.data.id, input);
|
|
89
|
+
}
|
|
90
|
+
delete() {
|
|
91
|
+
return this.client.deployments.delete(this.data.id);
|
|
92
|
+
}
|
|
93
|
+
async wait(options = {}) {
|
|
94
|
+
const intervalMs = options.intervalMs ?? 1000;
|
|
95
|
+
const timeoutMs = options.timeoutMs ?? 300000;
|
|
96
|
+
const startedAt = Date.now();
|
|
97
|
+
let current = this;
|
|
98
|
+
while (!deploymentStatusIsTerminal(current.data.status)) {
|
|
99
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
100
|
+
throw new Error(`Timed out waiting for deployment ${this.data.id}`);
|
|
101
|
+
}
|
|
102
|
+
await delay(intervalMs);
|
|
103
|
+
current = await current.refresh();
|
|
104
|
+
}
|
|
105
|
+
return current;
|
|
106
|
+
}
|
|
107
|
+
events() {
|
|
108
|
+
return this.client.deployments.events(this.data.id);
|
|
109
|
+
}
|
|
110
|
+
buildLogs(buildId = this.data.latest_build?.id ?? '') {
|
|
111
|
+
if (buildId === '') {
|
|
112
|
+
return Promise.reject(new Error('Deployment has no latest build id'));
|
|
113
|
+
}
|
|
114
|
+
return this.client.deployments.buildLogs(this.data.id, buildId);
|
|
115
|
+
}
|
|
116
|
+
logs() {
|
|
117
|
+
return this.client.deployments.logs(this.data.id);
|
|
118
|
+
}
|
|
119
|
+
setProtection(input) {
|
|
120
|
+
return this.client.deployments.setProtection(this.data.id, input);
|
|
121
|
+
}
|
|
122
|
+
protection() {
|
|
123
|
+
return this.client.deployments.protection(this.data.id);
|
|
124
|
+
}
|
|
125
|
+
createProtectionSession() {
|
|
126
|
+
return this.client.deployments.createProtectionSession(this.data.id);
|
|
127
|
+
}
|
|
128
|
+
disableProtection() {
|
|
129
|
+
return this.client.deployments.disableProtection(this.data.id);
|
|
130
|
+
}
|
|
131
|
+
setFeedback(input) {
|
|
132
|
+
return this.client.deployments.setFeedback(this.data.id, input);
|
|
133
|
+
}
|
|
134
|
+
domains() {
|
|
135
|
+
return this.client.deployments.listDomains(this.data.id);
|
|
136
|
+
}
|
|
137
|
+
addDomain(input) {
|
|
138
|
+
return this.client.deployments.createDomain(this.data.id, input);
|
|
139
|
+
}
|
|
140
|
+
refreshDomain(domainId) {
|
|
141
|
+
return this.client.deployments.refreshDomain(this.data.id, domainId);
|
|
142
|
+
}
|
|
143
|
+
deleteDomain(domainId) {
|
|
144
|
+
return this.client.deployments.deleteDomain(this.data.id, domainId);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function deploymentStatusIsTerminal(status) {
|
|
148
|
+
return ['healthy', 'failed', 'stopped', 'deleted', 'delete_failed'].includes(status);
|
|
149
|
+
}
|
|
150
|
+
function delay(ms) {
|
|
151
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
152
|
+
}
|
|
153
|
+
function unwrapDeploymentDomainCollection(input) {
|
|
154
|
+
if (Array.isArray(input)) {
|
|
155
|
+
return input;
|
|
156
|
+
}
|
|
157
|
+
return Array.isArray(input.data) ? input.data : [];
|
|
158
|
+
}
|
|
159
|
+
function parseNdjsonStream(input) {
|
|
160
|
+
const decoder = new TextDecoder();
|
|
161
|
+
let buffer = '';
|
|
162
|
+
return input.pipeThrough(new TransformStream({
|
|
163
|
+
transform(chunk, controller) {
|
|
164
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
165
|
+
const lines = buffer.split('\n');
|
|
166
|
+
buffer = lines.pop() ?? '';
|
|
167
|
+
for (const line of lines) {
|
|
168
|
+
const trimmed = line.trim();
|
|
169
|
+
if (trimmed !== '') {
|
|
170
|
+
controller.enqueue(JSON.parse(trimmed));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
flush(controller) {
|
|
175
|
+
buffer += decoder.decode();
|
|
176
|
+
const trimmed = buffer.trim();
|
|
177
|
+
if (trimmed !== '') {
|
|
178
|
+
controller.enqueue(JSON.parse(trimmed));
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
}));
|
|
182
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import Git, { GitActions, GitCredentials, GitEvents } from './git.js';
|
|
|
15
15
|
import { Disposable } from './types.js';
|
|
16
16
|
import { Beacon, BeaconOptions } from './beacon/index.js';
|
|
17
17
|
import { NotebookUnavailableError } from './errors/index.js';
|
|
18
|
+
import { DeploymentApi, NotebookDeploymentApi, type DeployInput, type DeploymentInstance } from './deployments.js';
|
|
18
19
|
export * from './types.js';
|
|
19
20
|
export { Transport } from './socket/index.js';
|
|
20
21
|
export * from './lsp.js';
|
|
@@ -28,6 +29,7 @@ export * from './config.js';
|
|
|
28
29
|
export * from './utils/promise.js';
|
|
29
30
|
export * from './beacon/index.js';
|
|
30
31
|
export * from './errors/index.js';
|
|
32
|
+
export * from './deployments.js';
|
|
31
33
|
interface Result<TType extends 'success' | 'error' | 'running', TData extends object> {
|
|
32
34
|
type: TType;
|
|
33
35
|
message: string;
|
|
@@ -203,6 +205,8 @@ export declare class ApiError extends Error {
|
|
|
203
205
|
readonly response: Response;
|
|
204
206
|
readonly body: string;
|
|
205
207
|
readonly status: number;
|
|
208
|
+
readonly data: unknown;
|
|
209
|
+
readonly apiMessage?: string;
|
|
206
210
|
constructor(response: Response, body: string);
|
|
207
211
|
}
|
|
208
212
|
export declare class NotebookApi {
|
|
@@ -210,6 +214,7 @@ export declare class NotebookApi {
|
|
|
210
214
|
readonly secrets: NotebookSecretApi;
|
|
211
215
|
readonly preview: NotebookPreviewApi;
|
|
212
216
|
readonly mail: NotebookMailApi;
|
|
217
|
+
readonly deployments: NotebookDeploymentApi;
|
|
213
218
|
constructor(client: Client);
|
|
214
219
|
create(template: string, input?: Partial<CreateNotebookInput>, init?: boolean): Promise<NotebookInstance>;
|
|
215
220
|
get(id: string): Promise<NotebookInstance>;
|
|
@@ -230,6 +235,7 @@ export interface PHPSandboxClientOptions {
|
|
|
230
235
|
}
|
|
231
236
|
export declare class Client {
|
|
232
237
|
readonly notebook: NotebookApi;
|
|
238
|
+
readonly deployments: DeploymentApi;
|
|
233
239
|
readonly options: PHPSandboxClientOptions;
|
|
234
240
|
private readonly fetch;
|
|
235
241
|
private readonly baseUrl;
|
|
@@ -247,6 +253,7 @@ export declare class Client {
|
|
|
247
253
|
put<T extends unknown>(path: string, body?: unknown): Promise<{
|
|
248
254
|
data: T;
|
|
249
255
|
}>;
|
|
256
|
+
stream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
250
257
|
private makeRequest;
|
|
251
258
|
}
|
|
252
259
|
export declare class PHPSandbox extends Client {
|
|
@@ -315,6 +322,7 @@ export declare class NotebookInstance {
|
|
|
315
322
|
constructor(data: NotebookData, client: Client);
|
|
316
323
|
ready(): Promise<NotebookInitSuccessResult>;
|
|
317
324
|
fork(input?: Partial<ForkNotebookInput>): Promise<NotebookInstance>;
|
|
325
|
+
deploy(input?: DeployInput): Promise<DeploymentInstance>;
|
|
318
326
|
gitCredentials(): Promise<GitCredentials>;
|
|
319
327
|
delete(): Promise<void>;
|
|
320
328
|
stop(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import EventManager from './events/index.js';
|
|
|
27
27
|
import Git from './git.js';
|
|
28
28
|
import { createBeacon } from './beacon/index.js';
|
|
29
29
|
import { NotebookUnavailableError } from './errors/index.js';
|
|
30
|
+
import { DeploymentApi, NotebookDeploymentApi } from './deployments.js';
|
|
30
31
|
export * from './types.js';
|
|
31
32
|
export { Transport } from './socket/index.js';
|
|
32
33
|
export * from './lsp.js';
|
|
@@ -40,6 +41,7 @@ export * from './config.js';
|
|
|
40
41
|
export * from './utils/promise.js';
|
|
41
42
|
export * from './beacon/index.js';
|
|
42
43
|
export * from './errors/index.js';
|
|
44
|
+
export * from './deployments.js';
|
|
43
45
|
function normalizeNotebookSecretInputs(input) {
|
|
44
46
|
if (Array.isArray(input)) {
|
|
45
47
|
return input;
|
|
@@ -59,18 +61,43 @@ export class NotebookInitError extends Error {
|
|
|
59
61
|
}
|
|
60
62
|
export class ApiError extends Error {
|
|
61
63
|
constructor(response, body) {
|
|
62
|
-
|
|
64
|
+
const data = parseApiErrorBody(body);
|
|
65
|
+
const apiMessage = apiErrorMessage(data, body);
|
|
66
|
+
super(`PHPSandbox API Error: ${response.status} ${response.statusText}${apiMessage === '' ? '' : ` - ${apiMessage}`}`);
|
|
63
67
|
this.response = response;
|
|
64
68
|
this.body = body;
|
|
65
69
|
this.status = response.status;
|
|
70
|
+
this.data = data;
|
|
71
|
+
this.apiMessage = apiMessage === '' ? undefined : apiMessage;
|
|
66
72
|
}
|
|
67
73
|
}
|
|
74
|
+
function parseApiErrorBody(body) {
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(body);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function apiErrorMessage(data, fallback) {
|
|
83
|
+
if (data !== null && typeof data === 'object') {
|
|
84
|
+
const record = data;
|
|
85
|
+
if (typeof record.message === 'string' && record.message.trim() !== '') {
|
|
86
|
+
return record.message.trim();
|
|
87
|
+
}
|
|
88
|
+
if (record.error !== undefined) {
|
|
89
|
+
return typeof record.error === 'string' ? record.error.trim() : JSON.stringify(record.error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return fallback.trim();
|
|
93
|
+
}
|
|
68
94
|
export class NotebookApi {
|
|
69
95
|
constructor(client) {
|
|
70
96
|
this.client = client;
|
|
71
97
|
this.secrets = new NotebookSecretApi(client);
|
|
72
98
|
this.preview = new NotebookPreviewApi(client);
|
|
73
99
|
this.mail = new NotebookMailApi(client);
|
|
100
|
+
this.deployments = new NotebookDeploymentApi(client);
|
|
74
101
|
}
|
|
75
102
|
async create(template, input = {}, init = true) {
|
|
76
103
|
const response = await this.client.post('/notebook', { template, ...input });
|
|
@@ -122,6 +149,7 @@ function normalizeApiBaseUrl(url) {
|
|
|
122
149
|
export class Client {
|
|
123
150
|
constructor(token, url = 'https://api.phpsandbox.io/v1', options = {}) {
|
|
124
151
|
this.fetch = globalThis.fetch;
|
|
152
|
+
this.deployments = new DeploymentApi(this);
|
|
125
153
|
this.notebook = new NotebookApi(this);
|
|
126
154
|
this.options = Object.assign({ startClosed: true }, options);
|
|
127
155
|
this.baseUrl = normalizeApiBaseUrl(url);
|
|
@@ -146,6 +174,19 @@ export class Client {
|
|
|
146
174
|
put(path, body) {
|
|
147
175
|
return this.makeRequest('PUT', path, { body: body === undefined ? undefined : JSON.stringify(body) });
|
|
148
176
|
}
|
|
177
|
+
async stream(path) {
|
|
178
|
+
const response = await this.fetch(new Request(new URL(path.replace(/^\//, ''), this.baseUrl), {
|
|
179
|
+
method: 'GET',
|
|
180
|
+
headers: this.headers,
|
|
181
|
+
}));
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
throw new ApiError(response, await response.text());
|
|
184
|
+
}
|
|
185
|
+
if (!response.body) {
|
|
186
|
+
throw new Error('PHPSandbox API Error: response body is not readable');
|
|
187
|
+
}
|
|
188
|
+
return response.body;
|
|
189
|
+
}
|
|
149
190
|
async makeRequest(method, path, init) {
|
|
150
191
|
const response = await this.fetch(new Request(new URL(path.replace(/^\//, ''), this.baseUrl), {
|
|
151
192
|
method,
|
|
@@ -293,6 +334,9 @@ export class NotebookInstance {
|
|
|
293
334
|
fork(input = {}) {
|
|
294
335
|
return this.client.notebook.fork(this.data.id, input);
|
|
295
336
|
}
|
|
337
|
+
deploy(input = {}) {
|
|
338
|
+
return this.client.notebook.deployments.create(this.data.id, input);
|
|
339
|
+
}
|
|
296
340
|
gitCredentials() {
|
|
297
341
|
return this.client.notebook.gitCredentials(this.data.id);
|
|
298
342
|
}
|
package/package.json
CHANGED