@phpsandbox/sdk 0.1.6 → 0.1.10
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 +42 -50
- package/dist/beacon/index.d.ts +1 -7
- package/dist/beacon/index.js +14 -13
- package/dist/beacon/navigator.d.ts +8 -36
- package/dist/beacon/navigator.js +1 -62
- package/dist/browser/phpsandbox-sdk.esm.js +547 -691
- package/dist/browser/phpsandbox-sdk.esm.min.js +23 -23
- package/dist/browser/phpsandbox-sdk.iife.js +547 -691
- package/dist/browser/phpsandbox-sdk.iife.min.js +35 -35
- package/dist/composer.d.ts +10 -8
- package/dist/composer.js +18 -18
- package/dist/errors/index.d.ts +43 -8
- package/dist/errors/index.js +120 -14
- package/dist/feedback.js +1 -2
- package/dist/filesystem.d.ts +0 -17
- package/dist/filesystem.js +2 -21
- package/dist/git.d.ts +1 -5
- package/dist/git.js +6 -8
- package/dist/index.d.ts +66 -156
- package/dist/index.js +172 -289
- package/dist/integrations.d.ts +0 -2
- package/dist/integrations.js +5 -11
- package/dist/log.d.ts +0 -2
- package/dist/lsp.js +1 -1
- package/dist/metrics.d.ts +3 -3
- package/dist/ports.d.ts +1 -1
- package/dist/publications.d.ts +4 -54
- package/dist/publications.js +25 -103
- package/dist/runtime/rest.js +34 -17
- package/dist/runtime.d.ts +68 -0
- package/dist/runtime.js +46 -0
- package/dist/sandbox-integrations.d.ts +1 -2
- package/dist/sandbox-integrations.js +11 -14
- package/dist/schemas/publications.d.ts +0 -6
- package/dist/schemas/publications.js +0 -1
- package/dist/servers.d.ts +4 -2
- package/dist/servers.js +5 -8
- package/dist/shell.d.ts +2 -14
- package/dist/shell.js +1 -21
- package/dist/socket/index.d.ts +6 -7
- package/dist/socket/index.js +39 -25
- package/dist/types.d.ts +0 -12
- package/dist/types.js +1 -15
- package/docs/api-summary.md +28 -28
- package/docs/cdn-usage.md +43 -55
- package/docs/getting-started.md +43 -26
- package/examples/README.md +5 -35
- package/examples/basic.ts +9 -18
- package/examples/get.ts +2 -2
- package/examples/git-merge-smoke.ts +2 -3
- package/examples/laravel-load-test.ts +31 -36
- package/examples/notebook-readonly-smoke.ts +12 -26
- package/examples/publication-provider-label.ts +1 -1
- package/examples/publish-cloudflare-container.ts +2 -2
- package/examples/publish-laravel-cloud.ts +2 -2
- package/examples/publish-ssh-agent.ts +2 -2
- package/package.json +4 -3
- package/dist/container.d.ts +0 -65
- package/dist/container.js +0 -30
package/dist/integrations.d.ts
CHANGED
|
@@ -27,8 +27,6 @@ export declare class IntegrationApi {
|
|
|
27
27
|
link(input: LinkIntegrationInput): Promise<Integration>;
|
|
28
28
|
list(): Promise<Integration[]>;
|
|
29
29
|
get(integration: IntegrationReference): Promise<Integration>;
|
|
30
|
-
update(integration: IntegrationReference, input: UpdateIntegrationInput): Promise<Integration>;
|
|
31
|
-
unlink(integration: IntegrationReference): Promise<void>;
|
|
32
30
|
}
|
|
33
31
|
export declare class Integration {
|
|
34
32
|
readonly data: IntegrationData;
|
package/dist/integrations.js
CHANGED
|
@@ -14,13 +14,6 @@ export class IntegrationApi {
|
|
|
14
14
|
const response = await this.client.get(`/integrations/${encodeURIComponent(integrationId(integration))}`);
|
|
15
15
|
return new Integration(response.data, this.client);
|
|
16
16
|
}
|
|
17
|
-
async update(integration, input) {
|
|
18
|
-
const response = await this.client.patch(`/integrations/${encodeURIComponent(integrationId(integration))}`, input);
|
|
19
|
-
return new Integration(response.data, this.client);
|
|
20
|
-
}
|
|
21
|
-
async unlink(integration) {
|
|
22
|
-
await this.client.delete(`/integrations/${encodeURIComponent(integrationId(integration))}`);
|
|
23
|
-
}
|
|
24
17
|
}
|
|
25
18
|
export class Integration {
|
|
26
19
|
constructor(data, client) {
|
|
@@ -36,11 +29,12 @@ export class Integration {
|
|
|
36
29
|
get label() {
|
|
37
30
|
return this.data.label;
|
|
38
31
|
}
|
|
39
|
-
update(input) {
|
|
40
|
-
|
|
32
|
+
async update(input) {
|
|
33
|
+
const response = await this.client.patch(`/integrations/${encodeURIComponent(this.id)}`, input);
|
|
34
|
+
return new Integration(response.data, this.client);
|
|
41
35
|
}
|
|
42
|
-
unlink() {
|
|
43
|
-
|
|
36
|
+
async unlink() {
|
|
37
|
+
await this.client.delete(`/integrations/${encodeURIComponent(this.id)}`);
|
|
44
38
|
}
|
|
45
39
|
}
|
|
46
40
|
export function integrationId(integration) {
|
package/dist/log.d.ts
CHANGED
package/dist/lsp.js
CHANGED
package/dist/metrics.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { NotebookInstance } from './index.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RuntimeStats } from './runtime.js';
|
|
3
3
|
import { RuntimeTelemetry, type RuntimeWatchOptions } from './runtime-telemetry.js';
|
|
4
4
|
export default class Metrics {
|
|
5
5
|
private readonly okra;
|
|
6
6
|
private readonly telemetry;
|
|
7
7
|
constructor(okra: NotebookInstance, telemetry: RuntimeTelemetry);
|
|
8
|
-
current(): Promise<
|
|
9
|
-
watch(options?: RuntimeWatchOptions): ReadableStream<
|
|
8
|
+
current(): Promise<RuntimeStats | null>;
|
|
9
|
+
watch(options?: RuntimeWatchOptions): ReadableStream<RuntimeStats>;
|
|
10
10
|
}
|
package/dist/ports.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NotebookInstance } from './index.js';
|
|
2
|
-
import type { PortInfo } from './
|
|
2
|
+
import type { PortInfo } from './runtime.js';
|
|
3
3
|
import { RuntimeTelemetry, type RuntimeWatchOptions } from './runtime-telemetry.js';
|
|
4
4
|
export default class Ports {
|
|
5
5
|
private readonly okra;
|
package/dist/publications.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { PublicationBuildStatus,
|
|
3
|
-
export
|
|
1
|
+
import type { Client } from './index.js';
|
|
2
|
+
import type { PublicationBuildStatus, PublicationEventData, PublicationJurisdiction, PublicationLogChunkData, PublicationProtectionMode, PublicationRegion, PublicationReleaseStatus, PublicationSize, PublicationStatus, PublishStreamEvent, PublishStreamResult } from './schemas/publications.js';
|
|
3
|
+
export type { BuiltInPublicationProviderName, PublicationBuildStatus, PublicationEventData, PublicationJurisdiction, PublicationLogChunkData, PublicationLogStream, PublicationProtectionMode, PublicationRegion, PublicationReleaseStatus, PublicationSize, PublicationStatus, PublishStreamEvent, PublishStreamLog, PublishStreamPhase, PublishStreamResult, PublishStreamSseEvent, } from './schemas/publications.js';
|
|
4
4
|
export interface PublicationPlacement {
|
|
5
5
|
regions?: PublicationRegion[];
|
|
6
6
|
jurisdiction?: PublicationJurisdiction;
|
|
@@ -66,7 +66,6 @@ export interface PublishInput<TName extends PublicationProviderName = Publicatio
|
|
|
66
66
|
protection?: PublicationProtectionInput;
|
|
67
67
|
metadata?: Record<string, unknown>;
|
|
68
68
|
}
|
|
69
|
-
export type PublicationRunResult = PublishStreamResult;
|
|
70
69
|
export interface PublicationBuildData<TProvider extends PublicationProviderName = PublicationProviderName> {
|
|
71
70
|
id: string;
|
|
72
71
|
status: PublicationBuildStatus;
|
|
@@ -81,32 +80,6 @@ export interface PublicationReleaseData {
|
|
|
81
80
|
status: PublicationReleaseStatus;
|
|
82
81
|
manifest: Record<string, unknown>;
|
|
83
82
|
}
|
|
84
|
-
export interface PublicationDomainDnsData {
|
|
85
|
-
type: PublicationDomainDnsRecordType;
|
|
86
|
-
name: string;
|
|
87
|
-
value: string;
|
|
88
|
-
}
|
|
89
|
-
export interface PublicationDomainData {
|
|
90
|
-
id: string;
|
|
91
|
-
publicationId: string | null;
|
|
92
|
-
hostname: string;
|
|
93
|
-
status: string;
|
|
94
|
-
provider: string;
|
|
95
|
-
providerHostnameId: string | null;
|
|
96
|
-
dns: PublicationDomainDnsData;
|
|
97
|
-
ssl: {
|
|
98
|
-
status: string | null;
|
|
99
|
-
};
|
|
100
|
-
validationErrors: unknown[];
|
|
101
|
-
validationRecords: unknown[];
|
|
102
|
-
metadata: Record<string, unknown>;
|
|
103
|
-
verifiedAt: string | null;
|
|
104
|
-
createdAt: string | null;
|
|
105
|
-
updatedAt: string | null;
|
|
106
|
-
}
|
|
107
|
-
export interface CreatePublicationDomainInput {
|
|
108
|
-
hostname: string;
|
|
109
|
-
}
|
|
110
83
|
export interface PublicationData<TProvider extends PublicationProviderName = PublicationProviderName> {
|
|
111
84
|
id: string;
|
|
112
85
|
slug: string;
|
|
@@ -118,7 +91,6 @@ export interface PublicationData<TProvider extends PublicationProviderName = Pub
|
|
|
118
91
|
eventStreamUrl: string | null;
|
|
119
92
|
originUrl: string | null;
|
|
120
93
|
currentRelease?: PublicationReleaseData | null;
|
|
121
|
-
domains?: PublicationDomainData[];
|
|
122
94
|
latestBuild?: PublicationBuildData<TProvider> | null;
|
|
123
95
|
deployedAt: string | null;
|
|
124
96
|
createdAt: string | null;
|
|
@@ -134,28 +106,10 @@ export interface PublicationProtectionSessionData {
|
|
|
134
106
|
expiresAt: string;
|
|
135
107
|
url: string;
|
|
136
108
|
}
|
|
137
|
-
export declare class NotebookPublicationApi {
|
|
138
|
-
private readonly client;
|
|
139
|
-
constructor(client: Client);
|
|
140
|
-
current<TProvider extends PublicationProviderName = PublicationProviderName>(notebookId: string): Promise<PublicationInstance<TProvider> | null>;
|
|
141
|
-
publish<TProvider extends PublicationProviderName = PublicationProviderName>(notebookId: string, input?: PublishInput): Promise<PublicationRun<TProvider>>;
|
|
142
|
-
}
|
|
143
109
|
export declare class PublicationApi {
|
|
144
110
|
private readonly client;
|
|
145
111
|
constructor(client: Client);
|
|
146
112
|
get<TProvider extends PublicationProviderName = PublicationProviderName>(id: string): Promise<PublicationInstance<TProvider>>;
|
|
147
|
-
destroy(id: string): Promise<void>;
|
|
148
|
-
setProtection<TProvider extends PublicationProviderName = PublicationProviderName>(id: string, input: UpdatePublicationProtectionInput): Promise<PublicationInstance<TProvider>>;
|
|
149
|
-
protection(id: string): Promise<PublicationProtectionData>;
|
|
150
|
-
createProtectionSession(id: string): Promise<PublicationProtectionSessionData>;
|
|
151
|
-
disableProtection<TProvider extends PublicationProviderName = PublicationProviderName>(id: string): Promise<PublicationInstance<TProvider>>;
|
|
152
|
-
listDomains(id: string): Promise<PublicationDomainData[]>;
|
|
153
|
-
createDomain(id: string, input: CreatePublicationDomainInput): Promise<PublicationDomainData>;
|
|
154
|
-
refreshDomain(id: string, domainId: string): Promise<PublicationDomainData>;
|
|
155
|
-
deleteDomain(id: string, domainId: string): Promise<void>;
|
|
156
|
-
events(id: string): Promise<ReadableStream<PublicationEventData>>;
|
|
157
|
-
buildLogs(id: string, buildId: string): Promise<ReadableStream<PublicationLogChunkData>>;
|
|
158
|
-
logs(id: string): Promise<ReadableStream<PublicationLogChunkData>>;
|
|
159
113
|
}
|
|
160
114
|
export declare class PublicationRun<TProvider extends PublicationProviderName = PublicationProviderName> {
|
|
161
115
|
readonly initial: PublicationInstance<TProvider>;
|
|
@@ -171,7 +125,7 @@ export declare class PublicationRun<TProvider extends PublicationProviderName =
|
|
|
171
125
|
private readonly subscribers;
|
|
172
126
|
constructor(initial: PublicationInstance<TProvider>, client: Client);
|
|
173
127
|
events(): AsyncIterable<PublishStreamEvent>;
|
|
174
|
-
result(): Promise<
|
|
128
|
+
result(): Promise<PublishStreamResult>;
|
|
175
129
|
publication(): Promise<PublicationInstance<TProvider>>;
|
|
176
130
|
start(): this;
|
|
177
131
|
private subscribe;
|
|
@@ -199,8 +153,4 @@ export declare class PublicationInstance<TProvider extends PublicationProviderNa
|
|
|
199
153
|
protection(): Promise<PublicationProtectionData>;
|
|
200
154
|
createProtectionSession(): Promise<PublicationProtectionSessionData>;
|
|
201
155
|
disableProtection(): Promise<PublicationInstance<TProvider>>;
|
|
202
|
-
domains(): Promise<PublicationDomainData[]>;
|
|
203
|
-
addDomain(input: CreatePublicationDomainInput): Promise<PublicationDomainData>;
|
|
204
|
-
refreshDomain(domainId: string): Promise<PublicationDomainData>;
|
|
205
|
-
deleteDomain(domainId: string): Promise<void>;
|
|
206
156
|
}
|
package/dist/publications.js
CHANGED
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
import { ApiError } from './index.js';
|
|
2
1
|
import { PublicationEventDataSchema, PublicationLogChunkDataSchema, PublishStreamSseEventNameSchema, PublishStreamSseEventSchema, } from './schemas/publications.js';
|
|
3
|
-
export * from './schemas/publications.js';
|
|
4
|
-
export class NotebookPublicationApi {
|
|
5
|
-
constructor(client) {
|
|
6
|
-
this.client = client;
|
|
7
|
-
}
|
|
8
|
-
async current(notebookId) {
|
|
9
|
-
try {
|
|
10
|
-
const response = await this.client.get(`/notebook/${notebookId}/publication`);
|
|
11
|
-
return new PublicationInstance(response.data, this.client, notebookId);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
if (error instanceof ApiError && error.status === 404) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
throw error;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
async publish(notebookId, input) {
|
|
21
|
-
const response = await this.client.post(`/notebook/${notebookId}/publication`, input);
|
|
22
|
-
const run = new PublicationRun(new PublicationInstance(response.data, this.client, notebookId), this.client);
|
|
23
|
-
run.start();
|
|
24
|
-
return run;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
2
|
export class PublicationApi {
|
|
28
3
|
constructor(client) {
|
|
29
4
|
this.client = client;
|
|
@@ -32,49 +7,6 @@ export class PublicationApi {
|
|
|
32
7
|
const response = await this.client.get(`/publications/${id}`);
|
|
33
8
|
return new PublicationInstance(response.data, this.client);
|
|
34
9
|
}
|
|
35
|
-
async destroy(id) {
|
|
36
|
-
await this.client.delete(`/publications/${id}`);
|
|
37
|
-
}
|
|
38
|
-
async setProtection(id, input) {
|
|
39
|
-
const response = await this.client.put(`/publications/${id}/protection`, input);
|
|
40
|
-
return new PublicationInstance(response.data, this.client);
|
|
41
|
-
}
|
|
42
|
-
async protection(id) {
|
|
43
|
-
const response = await this.client.get(`/publications/${id}/protection`);
|
|
44
|
-
return response.data;
|
|
45
|
-
}
|
|
46
|
-
async createProtectionSession(id) {
|
|
47
|
-
const response = await this.client.post(`/publications/${id}/protection/session`);
|
|
48
|
-
return response.data;
|
|
49
|
-
}
|
|
50
|
-
async disableProtection(id) {
|
|
51
|
-
const response = await this.client.delete(`/publications/${id}/protection`);
|
|
52
|
-
return new PublicationInstance(response.data, this.client);
|
|
53
|
-
}
|
|
54
|
-
async listDomains(id) {
|
|
55
|
-
const response = await this.client.get(`/publications/${id}/domains`);
|
|
56
|
-
return unwrapPublicationDomainCollection(response.data);
|
|
57
|
-
}
|
|
58
|
-
async createDomain(id, input) {
|
|
59
|
-
const response = await this.client.post(`/publications/${id}/domains`, input);
|
|
60
|
-
return response.data;
|
|
61
|
-
}
|
|
62
|
-
async refreshDomain(id, domainId) {
|
|
63
|
-
const response = await this.client.post(`/publications/${id}/domains/${domainId}/refresh`);
|
|
64
|
-
return response.data;
|
|
65
|
-
}
|
|
66
|
-
async deleteDomain(id, domainId) {
|
|
67
|
-
await this.client.delete(`/publications/${id}/domains/${domainId}`);
|
|
68
|
-
}
|
|
69
|
-
async events(id) {
|
|
70
|
-
return parseNdjsonStream(await this.client.stream(`/publications/${id}/events/stream`), PublicationEventDataSchema);
|
|
71
|
-
}
|
|
72
|
-
async buildLogs(id, buildId) {
|
|
73
|
-
return parseNdjsonStream(await this.client.stream(`/publications/${id}/builds/${buildId}/logs/stream`), PublicationLogChunkDataSchema);
|
|
74
|
-
}
|
|
75
|
-
async logs(id) {
|
|
76
|
-
return parseNdjsonStream(await this.client.stream(`/publications/${id}/logs/stream`), PublicationLogChunkDataSchema);
|
|
77
|
-
}
|
|
78
10
|
}
|
|
79
11
|
export class PublicationRun {
|
|
80
12
|
constructor(initial, client) {
|
|
@@ -197,14 +129,17 @@ export class PublicationInstance {
|
|
|
197
129
|
const response = await this.client.get(`/publications/${this.data.id}`);
|
|
198
130
|
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
199
131
|
}
|
|
200
|
-
publish() {
|
|
132
|
+
async publish() {
|
|
201
133
|
if (!this.notebookId) {
|
|
202
134
|
return Promise.reject(new Error('Publishing requires a notebook-scoped publication instance.'));
|
|
203
135
|
}
|
|
204
|
-
|
|
136
|
+
const response = await this.client.post(`/notebook/${this.notebookId}/publication`);
|
|
137
|
+
const run = new PublicationRun(new PublicationInstance(response.data, this.client, this.notebookId), this.client);
|
|
138
|
+
run.start();
|
|
139
|
+
return run;
|
|
205
140
|
}
|
|
206
|
-
destroy() {
|
|
207
|
-
|
|
141
|
+
async destroy() {
|
|
142
|
+
await this.client.delete(`/publications/${this.data.id}`);
|
|
208
143
|
}
|
|
209
144
|
async wait(options = {}) {
|
|
210
145
|
const intervalMs = options.intervalMs ?? 1000;
|
|
@@ -220,41 +155,34 @@ export class PublicationInstance {
|
|
|
220
155
|
}
|
|
221
156
|
return current;
|
|
222
157
|
}
|
|
223
|
-
events() {
|
|
224
|
-
return this.client.publications
|
|
158
|
+
async events() {
|
|
159
|
+
return parseNdjsonStream(await this.client.stream(`/publications/${this.data.id}/events/stream`), PublicationEventDataSchema);
|
|
225
160
|
}
|
|
226
161
|
buildLogs(buildId = this.data.latestBuild?.id ?? '') {
|
|
227
162
|
if (buildId === '') {
|
|
228
163
|
return Promise.reject(new Error('Publication has no latest build id'));
|
|
229
164
|
}
|
|
230
|
-
return this.client.publications
|
|
165
|
+
return this.client.stream(`/publications/${this.data.id}/builds/${buildId}/logs/stream`)
|
|
166
|
+
.then((stream) => parseNdjsonStream(stream, PublicationLogChunkDataSchema));
|
|
231
167
|
}
|
|
232
|
-
logs() {
|
|
233
|
-
return this.client.publications
|
|
168
|
+
async logs() {
|
|
169
|
+
return parseNdjsonStream(await this.client.stream(`/publications/${this.data.id}/logs/stream`), PublicationLogChunkDataSchema);
|
|
234
170
|
}
|
|
235
|
-
setProtection(input) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
protection() {
|
|
239
|
-
return this.client.publications.protection(this.data.id);
|
|
240
|
-
}
|
|
241
|
-
createProtectionSession() {
|
|
242
|
-
return this.client.publications.createProtectionSession(this.data.id);
|
|
243
|
-
}
|
|
244
|
-
disableProtection() {
|
|
245
|
-
return this.client.publications.disableProtection(this.data.id);
|
|
246
|
-
}
|
|
247
|
-
domains() {
|
|
248
|
-
return this.client.publications.listDomains(this.data.id);
|
|
171
|
+
async setProtection(input) {
|
|
172
|
+
const response = await this.client.put(`/publications/${this.data.id}/protection`, input);
|
|
173
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
249
174
|
}
|
|
250
|
-
|
|
251
|
-
|
|
175
|
+
async protection() {
|
|
176
|
+
const response = await this.client.get(`/publications/${this.data.id}/protection`);
|
|
177
|
+
return response.data;
|
|
252
178
|
}
|
|
253
|
-
|
|
254
|
-
|
|
179
|
+
async createProtectionSession() {
|
|
180
|
+
const response = await this.client.post(`/publications/${this.data.id}/protection/session`);
|
|
181
|
+
return response.data;
|
|
255
182
|
}
|
|
256
|
-
|
|
257
|
-
|
|
183
|
+
async disableProtection() {
|
|
184
|
+
const response = await this.client.delete(`/publications/${this.data.id}/protection`);
|
|
185
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
258
186
|
}
|
|
259
187
|
}
|
|
260
188
|
function publicationStatusIsTerminal(status) {
|
|
@@ -263,12 +191,6 @@ function publicationStatusIsTerminal(status) {
|
|
|
263
191
|
function delay(ms) {
|
|
264
192
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
265
193
|
}
|
|
266
|
-
function unwrapPublicationDomainCollection(input) {
|
|
267
|
-
if (Array.isArray(input)) {
|
|
268
|
-
return input;
|
|
269
|
-
}
|
|
270
|
-
return Array.isArray(input.data) ? input.data : [];
|
|
271
|
-
}
|
|
272
194
|
class AsyncPublishEventQueue {
|
|
273
195
|
constructor() {
|
|
274
196
|
this.values = [];
|
package/dist/runtime/rest.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { UnsupportedRuntimeTransportError } from '../errors/index.js';
|
|
1
|
+
import { PHPSandboxError, RemoteError, TransportError, remoteError } from '../errors/index.js';
|
|
3
2
|
const restActionRoutes = {
|
|
4
3
|
'runtime.ready': { method: 'GET', path: '/runtime' },
|
|
5
|
-
ping: { method: 'GET', path: '/runtime/ping' },
|
|
6
4
|
'config.get': { method: 'GET', path: '/runtime/config' },
|
|
7
5
|
'config.update': { method: 'PATCH', path: '/runtime/config' },
|
|
8
6
|
'config.set-ports': { method: 'PUT', path: '/runtime/config/ports' },
|
|
9
|
-
'container.state': { method: 'GET', path: '/runtime/container' },
|
|
10
|
-
'container.start': { method: 'POST', path: '/runtime/container/start' },
|
|
11
7
|
'container.restart': { method: 'POST', path: '/runtime/container/restart' },
|
|
12
8
|
'container.stop': { method: 'POST', path: '/runtime/container/stop' },
|
|
13
9
|
'container.set-php': { method: 'PUT', path: '/runtime/container/php' },
|
|
@@ -60,10 +56,15 @@ export class RestRuntimeInvoker {
|
|
|
60
56
|
const actionUrl = new URL(runtimeUrl);
|
|
61
57
|
const ticket = actionUrl.searchParams.get('ticket') ?? '';
|
|
62
58
|
if (ticket === '') {
|
|
63
|
-
throw new
|
|
59
|
+
throw new PHPSandboxError('The notebook connection does not contain a runtime ticket.');
|
|
64
60
|
}
|
|
65
61
|
this.ticket = ticket;
|
|
66
|
-
|
|
62
|
+
if (actionUrl.protocol === 'wss:') {
|
|
63
|
+
actionUrl.protocol = 'https:';
|
|
64
|
+
}
|
|
65
|
+
else if (actionUrl.protocol === 'ws:') {
|
|
66
|
+
actionUrl.protocol = 'http:';
|
|
67
|
+
}
|
|
67
68
|
actionUrl.pathname = `/api/v1/notebooks/${encodeURIComponent(this.notebookId)}`;
|
|
68
69
|
actionUrl.searchParams.delete('ticket');
|
|
69
70
|
actionUrl.hash = '';
|
|
@@ -79,27 +80,28 @@ export class RestRuntimeInvoker {
|
|
|
79
80
|
return this.invokeRaw(action, data ?? {}, options);
|
|
80
81
|
}
|
|
81
82
|
send() {
|
|
82
|
-
throw new
|
|
83
|
+
throw new PHPSandboxError('Fire-and-forget actions require the realtime transport.');
|
|
83
84
|
}
|
|
84
85
|
async invokeRaw(action, data, options) {
|
|
85
86
|
const abort = runtimeAbort(options);
|
|
86
87
|
try {
|
|
87
88
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
88
|
-
const response = await this.fetch
|
|
89
|
+
const response = await runtimeFetch(this.fetch, this.request(action, data, abort.signal));
|
|
89
90
|
if (response.status === 401 && attempt === 0 && this.refresh !== undefined) {
|
|
90
91
|
await this.refreshAuthorization();
|
|
91
92
|
continue;
|
|
92
93
|
}
|
|
93
94
|
const payload = await runtimeActionResponse(response);
|
|
94
95
|
if (!response.ok || payload.error !== undefined) {
|
|
95
|
-
|
|
96
|
-
const message = typeof error.message === 'string' ? error.message : `Runtime action ${action} failed.`;
|
|
97
|
-
const code = typeof error.code === 'number' ? error.code : response.status;
|
|
98
|
-
throw new ErrorEvent(code, message, error);
|
|
96
|
+
throw remoteError('runtime', payload.error, response);
|
|
99
97
|
}
|
|
100
98
|
return payload.data;
|
|
101
99
|
}
|
|
102
|
-
throw new
|
|
100
|
+
throw new RemoteError(`Runtime action ${action} could not be authorized.`, {
|
|
101
|
+
source: 'runtime',
|
|
102
|
+
status: 401,
|
|
103
|
+
code: 'AuthenticationRequired',
|
|
104
|
+
});
|
|
103
105
|
}
|
|
104
106
|
finally {
|
|
105
107
|
abort.dispose();
|
|
@@ -108,7 +110,7 @@ export class RestRuntimeInvoker {
|
|
|
108
110
|
request(action, data, signal) {
|
|
109
111
|
const route = restActionRoutes[action];
|
|
110
112
|
if (route === undefined) {
|
|
111
|
-
throw new
|
|
113
|
+
throw new PHPSandboxError(`Runtime action ${action} requires the realtime transport.`);
|
|
112
114
|
}
|
|
113
115
|
const url = new URL(this.actionUrl);
|
|
114
116
|
url.pathname += route.path;
|
|
@@ -122,6 +124,7 @@ export class RestRuntimeInvoker {
|
|
|
122
124
|
headers,
|
|
123
125
|
body: route.method === 'GET' ? undefined : body,
|
|
124
126
|
signal,
|
|
127
|
+
redirect: 'error',
|
|
125
128
|
});
|
|
126
129
|
}
|
|
127
130
|
async refreshAuthorization() {
|
|
@@ -136,19 +139,33 @@ export class RestRuntimeInvoker {
|
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
}
|
|
142
|
+
async function runtimeFetch(fetch, request) {
|
|
143
|
+
try {
|
|
144
|
+
return await fetch(request);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
throw new TransportError('Unable to reach the PHPSandbox runtime.', 'ConnectionFailed', error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
139
153
|
async function runtimeActionResponse(response) {
|
|
140
154
|
if (response.ok && response.headers.get('content-type')?.toLowerCase().startsWith('application/octet-stream')) {
|
|
141
155
|
return { data: new Uint8Array(await response.arrayBuffer()) };
|
|
142
156
|
}
|
|
143
157
|
const body = await response.text();
|
|
144
158
|
if (body === '') {
|
|
159
|
+
if (response.ok) {
|
|
160
|
+
throw new TransportError('PHPSandbox runtime returned an empty response.', 'InvalidResponse', response);
|
|
161
|
+
}
|
|
145
162
|
return {};
|
|
146
163
|
}
|
|
147
164
|
try {
|
|
148
165
|
return JSON.parse(body);
|
|
149
166
|
}
|
|
150
|
-
catch {
|
|
151
|
-
|
|
167
|
+
catch (error) {
|
|
168
|
+
throw new TransportError('PHPSandbox runtime returned an invalid JSON response.', 'InvalidResponse', error);
|
|
152
169
|
}
|
|
153
170
|
}
|
|
154
171
|
function runtimeActionRequestBody(action, data, url, headers) {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Action, NotebookInstance } from './index.js';
|
|
2
|
+
import Logs, { type RuntimeLogEntry } from './log.js';
|
|
3
|
+
import Metrics from './metrics.js';
|
|
4
|
+
import Ports from './ports.js';
|
|
5
|
+
import { type RuntimeTelemetryFeature, type RuntimeWatchOptions } from './runtime-telemetry.js';
|
|
6
|
+
export interface PortInfo {
|
|
7
|
+
subdomain: string;
|
|
8
|
+
url: string;
|
|
9
|
+
default: boolean;
|
|
10
|
+
localPort?: number;
|
|
11
|
+
externalPort?: number;
|
|
12
|
+
port: number;
|
|
13
|
+
}
|
|
14
|
+
export interface RuntimeResourceUsage {
|
|
15
|
+
usage: number;
|
|
16
|
+
limit: number;
|
|
17
|
+
}
|
|
18
|
+
export interface RuntimeStats {
|
|
19
|
+
cpu: RuntimeResourceUsage;
|
|
20
|
+
memory: RuntimeResourceUsage;
|
|
21
|
+
disk: RuntimeResourceUsage;
|
|
22
|
+
}
|
|
23
|
+
export interface RuntimeEvents {
|
|
24
|
+
'container.stats': RuntimeStats;
|
|
25
|
+
'container.ports': PortInfo[];
|
|
26
|
+
}
|
|
27
|
+
export interface RuntimeActions {
|
|
28
|
+
'container.restart': Action<{}, void>;
|
|
29
|
+
'container.stop': Action<{}, void>;
|
|
30
|
+
'container.opened-ports': Action<{}, PortInfo[]>;
|
|
31
|
+
'container.stats': Action<{}, RuntimeStats | null>;
|
|
32
|
+
'container.set-php': Action<{
|
|
33
|
+
version: string;
|
|
34
|
+
}, {
|
|
35
|
+
version: string;
|
|
36
|
+
}>;
|
|
37
|
+
'container.stream-telemetry': Action<{
|
|
38
|
+
features: RuntimeTelemetryFeature[];
|
|
39
|
+
}, void>;
|
|
40
|
+
'container.stop-telemetry': Action<{}, void>;
|
|
41
|
+
}
|
|
42
|
+
export declare class RuntimeMetrics {
|
|
43
|
+
private readonly metrics;
|
|
44
|
+
constructor(metrics: Metrics);
|
|
45
|
+
current(): Promise<RuntimeStats | null>;
|
|
46
|
+
watch(options?: RuntimeWatchOptions): ReadableStream<RuntimeStats>;
|
|
47
|
+
}
|
|
48
|
+
export declare class RuntimeLogs {
|
|
49
|
+
private readonly logs;
|
|
50
|
+
constructor(logs: Logs);
|
|
51
|
+
follow(options?: RuntimeWatchOptions): ReadableStream<RuntimeLogEntry>;
|
|
52
|
+
}
|
|
53
|
+
export declare class RuntimePorts {
|
|
54
|
+
private readonly ports;
|
|
55
|
+
constructor(ports: Ports);
|
|
56
|
+
list(): Promise<PortInfo[]>;
|
|
57
|
+
watch(options?: RuntimeWatchOptions): ReadableStream<PortInfo[]>;
|
|
58
|
+
}
|
|
59
|
+
export default class Runtime {
|
|
60
|
+
private readonly notebook;
|
|
61
|
+
readonly metrics: RuntimeMetrics;
|
|
62
|
+
readonly logs: RuntimeLogs;
|
|
63
|
+
readonly ports: RuntimePorts;
|
|
64
|
+
constructor(notebook: NotebookInstance);
|
|
65
|
+
setPhpVersion(version: string): Promise<{
|
|
66
|
+
version: string;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Logs from './log.js';
|
|
2
|
+
import Metrics from './metrics.js';
|
|
3
|
+
import Ports from './ports.js';
|
|
4
|
+
import { RuntimeTelemetry, } from './runtime-telemetry.js';
|
|
5
|
+
export class RuntimeMetrics {
|
|
6
|
+
constructor(metrics) {
|
|
7
|
+
this.metrics = metrics;
|
|
8
|
+
}
|
|
9
|
+
current() {
|
|
10
|
+
return this.metrics.current();
|
|
11
|
+
}
|
|
12
|
+
watch(options = {}) {
|
|
13
|
+
return this.metrics.watch(options);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class RuntimeLogs {
|
|
17
|
+
constructor(logs) {
|
|
18
|
+
this.logs = logs;
|
|
19
|
+
}
|
|
20
|
+
follow(options = {}) {
|
|
21
|
+
return this.logs.follow(options);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class RuntimePorts {
|
|
25
|
+
constructor(ports) {
|
|
26
|
+
this.ports = ports;
|
|
27
|
+
}
|
|
28
|
+
list() {
|
|
29
|
+
return this.ports.list();
|
|
30
|
+
}
|
|
31
|
+
watch(options = {}) {
|
|
32
|
+
return this.ports.watch(options);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export default class Runtime {
|
|
36
|
+
constructor(notebook) {
|
|
37
|
+
this.notebook = notebook;
|
|
38
|
+
const telemetry = new RuntimeTelemetry(notebook);
|
|
39
|
+
this.metrics = new RuntimeMetrics(new Metrics(notebook, telemetry));
|
|
40
|
+
this.logs = new RuntimeLogs(new Logs(notebook, telemetry));
|
|
41
|
+
this.ports = new RuntimePorts(new Ports(notebook, telemetry));
|
|
42
|
+
}
|
|
43
|
+
setPhpVersion(version) {
|
|
44
|
+
return this.notebook.invoke('container.set-php', { version });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -25,8 +25,6 @@ export declare class SandboxIntegrationApi {
|
|
|
25
25
|
attach(input: AttachSandboxIntegrationInput): Promise<SandboxIntegration>;
|
|
26
26
|
list(): Promise<SandboxIntegration[]>;
|
|
27
27
|
get(integration: SandboxIntegrationReference): Promise<SandboxIntegration>;
|
|
28
|
-
update(integration: SandboxIntegrationReference, input: UpdateSandboxIntegrationInput): Promise<SandboxIntegration>;
|
|
29
|
-
detach(integration: SandboxIntegrationReference): Promise<void>;
|
|
30
28
|
private path;
|
|
31
29
|
private bindingPath;
|
|
32
30
|
}
|
|
@@ -40,5 +38,6 @@ export declare class SandboxIntegration {
|
|
|
40
38
|
get effects(): SandboxIntegrationEffect[];
|
|
41
39
|
update(input: UpdateSandboxIntegrationInput): Promise<SandboxIntegration>;
|
|
42
40
|
detach(): Promise<void>;
|
|
41
|
+
private path;
|
|
43
42
|
}
|
|
44
43
|
export declare function sandboxIntegrationId(integration: SandboxIntegrationReference): string;
|
|
@@ -19,16 +19,6 @@ export class SandboxIntegrationApi {
|
|
|
19
19
|
const response = await this.client.get(this.bindingPath(integration));
|
|
20
20
|
return new SandboxIntegration(response.data, this.notebookId, this.client);
|
|
21
21
|
}
|
|
22
|
-
async update(integration, input) {
|
|
23
|
-
const response = await this.client.patch(this.bindingPath(integration), {
|
|
24
|
-
...input,
|
|
25
|
-
integration: input.integration === undefined ? undefined : integrationId(input.integration),
|
|
26
|
-
});
|
|
27
|
-
return new SandboxIntegration(response.data, this.notebookId, this.client);
|
|
28
|
-
}
|
|
29
|
-
async detach(integration) {
|
|
30
|
-
await this.client.delete(this.bindingPath(integration));
|
|
31
|
-
}
|
|
32
22
|
path() {
|
|
33
23
|
return `/notebook/${this.notebookId}/integrations`;
|
|
34
24
|
}
|
|
@@ -51,11 +41,18 @@ export class SandboxIntegration {
|
|
|
51
41
|
get effects() {
|
|
52
42
|
return this.data.effects;
|
|
53
43
|
}
|
|
54
|
-
update(input) {
|
|
55
|
-
|
|
44
|
+
async update(input) {
|
|
45
|
+
const response = await this.client.patch(this.path(), {
|
|
46
|
+
...input,
|
|
47
|
+
integration: input.integration === undefined ? undefined : integrationId(input.integration),
|
|
48
|
+
});
|
|
49
|
+
return new SandboxIntegration(response.data, this.notebookId, this.client);
|
|
50
|
+
}
|
|
51
|
+
async detach() {
|
|
52
|
+
await this.client.delete(this.path());
|
|
56
53
|
}
|
|
57
|
-
|
|
58
|
-
return
|
|
54
|
+
path() {
|
|
55
|
+
return `/notebook/${this.notebookId}/integrations/${encodeURIComponent(this.id)}`;
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
58
|
export function sandboxIntegrationId(integration) {
|