@phpsandbox/sdk 0.1.19 → 0.2.0
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/beacon/index.d.ts +2 -2
- package/dist/browser/phpsandbox-sdk.esm.js +16944 -16822
- package/dist/browser/phpsandbox-sdk.esm.min.js +35 -35
- package/dist/browser/phpsandbox-sdk.iife.js +16933 -16810
- package/dist/browser/phpsandbox-sdk.iife.min.js +24 -24
- package/dist/errors/index.d.ts +2 -2
- package/dist/events/index.d.ts +21 -15
- package/dist/events/index.js +9 -5
- package/dist/index.d.ts +25 -9
- package/dist/index.js +37 -34
- package/dist/publication/domains.d.ts +17 -0
- package/dist/publication/domains.js +25 -0
- package/dist/publication/index.d.ts +8 -0
- package/dist/publication/index.js +6 -0
- package/dist/publication/instance.d.ts +42 -0
- package/dist/publication/instance.js +133 -0
- package/dist/publication/notebook.d.ts +20 -0
- package/dist/publication/notebook.js +46 -0
- package/dist/publication/providers/laravel-cloud.d.ts +114 -0
- package/dist/publication/providers/laravel-cloud.js +13 -0
- package/dist/publication/resources.d.ts +9 -0
- package/dist/publication/resources.js +19 -0
- package/dist/publication/run.d.ts +30 -0
- package/dist/{publications.js → publication/run.js} +11 -133
- package/dist/publication/types.d.ts +303 -0
- package/dist/publication/types.js +1 -0
- package/dist/runtime/rest.d.ts +1 -1
- package/dist/schemas/publications.d.ts +33 -33
- package/dist/servers.d.ts +3 -0
- package/dist/servers.js +3 -0
- package/dist/socket/index.d.ts +4 -4
- package/dist/socket/index.js +5 -3
- package/package.json +1 -1
- package/dist/publications.d.ts +0 -192
package/dist/errors/index.d.ts
CHANGED
|
@@ -36,8 +36,8 @@ export interface HttpResponseDiagnostics {
|
|
|
36
36
|
}
|
|
37
37
|
export declare class TransportError<TCode extends TransportErrorCode = TransportErrorCode> extends PHPSandboxError {
|
|
38
38
|
readonly code: TCode;
|
|
39
|
-
readonly response?: HttpResponseDiagnostics;
|
|
40
|
-
constructor(message: string, code: TCode, cause?: unknown, response?: HttpResponseDiagnostics);
|
|
39
|
+
readonly response?: HttpResponseDiagnostics | undefined;
|
|
40
|
+
constructor(message: string, code: TCode, cause?: unknown, response?: HttpResponseDiagnostics | undefined);
|
|
41
41
|
static is(error: unknown): error is TransportError;
|
|
42
42
|
static is<TCode extends TransportErrorCode>(error: unknown, code: TCode): error is TransportError<TCode>;
|
|
43
43
|
is<TExpectedCode extends TransportErrorCode>(code: TExpectedCode): this is this & TransportError<TExpectedCode>;
|
package/dist/events/index.d.ts
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
import
|
|
1
|
+
import mitt from 'mitt';
|
|
2
2
|
import type { EventHandlerMap, EventType, Handler } from 'mitt';
|
|
3
3
|
import { Disposable } from '../types.js';
|
|
4
|
-
export interface EventDispatcher {
|
|
5
|
-
listen: (event:
|
|
6
|
-
once: (event:
|
|
7
|
-
emit:
|
|
8
|
-
|
|
4
|
+
export interface EventDispatcher<Events extends Record<EventType, unknown> = Record<EventType, unknown>> {
|
|
5
|
+
listen: <Key extends keyof Events>(event: Key, callback: Handler<Events[Key]>, context?: unknown) => Disposable;
|
|
6
|
+
once: <Key extends keyof Events>(event: Key, callback: Handler<Events[Key]>, context?: unknown) => Disposable;
|
|
7
|
+
emit: {
|
|
8
|
+
<Key extends keyof Events>(event: Key, payload: Events[Key]): void;
|
|
9
|
+
<Key extends keyof Events>(event: undefined extends Events[Key] ? Key : never): void;
|
|
10
|
+
};
|
|
11
|
+
removeListener: <Key extends keyof Events>(event?: Key, callbackSignature?: Handler<Events[Key]>) => void;
|
|
9
12
|
}
|
|
10
|
-
export declare function mittWithOnce<Events extends Record<EventType, unknown>>(all?: EventHandlerMap<Events>):
|
|
11
|
-
once<Key extends keyof Events>(type: Key,
|
|
13
|
+
export declare function mittWithOnce<Events extends Record<EventType, unknown>>(all?: EventHandlerMap<Events>): mitt.Emitter<Events> & {
|
|
14
|
+
once: <Key extends keyof Events>(type: Key, fn: Handler<Events[Key]>) => {
|
|
15
|
+
dispose: () => void;
|
|
16
|
+
};
|
|
12
17
|
};
|
|
13
|
-
export default class EventManager implements EventDispatcher {
|
|
18
|
+
export default class EventManager<Events extends Record<EventType, unknown> = Record<EventType, unknown>> implements EventDispatcher<Events> {
|
|
14
19
|
private readonly emitter;
|
|
15
|
-
listen(event:
|
|
16
|
-
emit(event:
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
listen<Key extends keyof Events>(event: Key, callback: Handler<Events[Key]>): Disposable;
|
|
21
|
+
emit<Key extends keyof Events>(event: Key, payload: Events[Key]): void;
|
|
22
|
+
emit<Key extends keyof Events>(event: undefined extends Events[Key] ? Key : never): void;
|
|
23
|
+
once<Key extends keyof Events>(event: Key, callback: Handler<Events[Key]>): Disposable;
|
|
24
|
+
static make<Events extends Record<EventType, unknown> = Record<EventType, unknown>>(): EventDispatcher<Events>;
|
|
19
25
|
static refresh(): EventDispatcher;
|
|
20
|
-
removeListener(event?:
|
|
26
|
+
removeListener<Key extends keyof Events>(event?: Key, callbackSignature?: Handler<Events[Key]>): void;
|
|
21
27
|
static createInstance(): EventDispatcher;
|
|
22
|
-
inspect(): EventHandlerMap<
|
|
28
|
+
inspect(): EventHandlerMap<Events>;
|
|
23
29
|
}
|
package/dist/events/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
const createMitt =
|
|
1
|
+
import mitt from 'mitt';
|
|
2
|
+
const createMitt = typeof mitt === 'function' ? mitt : mitt.default;
|
|
3
3
|
export function mittWithOnce(all) {
|
|
4
4
|
const inst = createMitt(all);
|
|
5
|
-
|
|
5
|
+
const once = (type, fn) => {
|
|
6
6
|
const onceHandler = (event) => {
|
|
7
7
|
inst.off(type, onceHandler);
|
|
8
8
|
fn(event);
|
|
@@ -14,7 +14,7 @@ export function mittWithOnce(all) {
|
|
|
14
14
|
},
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
-
return inst;
|
|
17
|
+
return Object.assign(inst, { once });
|
|
18
18
|
}
|
|
19
19
|
export default class EventManager {
|
|
20
20
|
constructor() {
|
|
@@ -28,7 +28,7 @@ export default class EventManager {
|
|
|
28
28
|
return { dispose };
|
|
29
29
|
}
|
|
30
30
|
emit(event, ...data) {
|
|
31
|
-
this.emitter.emit(event, data
|
|
31
|
+
this.emitter.emit(event, data[0]);
|
|
32
32
|
}
|
|
33
33
|
once(event, callback) {
|
|
34
34
|
return this.emitter.once(event, callback);
|
|
@@ -40,6 +40,10 @@ export default class EventManager {
|
|
|
40
40
|
return new EventManager();
|
|
41
41
|
}
|
|
42
42
|
removeListener(event, callbackSignature) {
|
|
43
|
+
if (event === undefined) {
|
|
44
|
+
this.emitter.all.clear();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
43
47
|
this.emitter.off(event, callbackSignature);
|
|
44
48
|
}
|
|
45
49
|
static createInstance() {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NotebookPublication } from './publication/index.js';
|
|
1
2
|
import { Filesystem, FilesystemActions, FilesystemEvents } from './filesystem.js';
|
|
2
3
|
import Terminals, { TerminalEvents, TerminalActions, type SpawnOptions } from './terminal.js';
|
|
3
4
|
import Auth, { AuthActions } from './auth.js';
|
|
@@ -9,16 +10,16 @@ import Repl, { ReplActions, ReplEvents } from './repl.js';
|
|
|
9
10
|
import { ShellEvents, ShellActions, type ProcessResult, type ShellProcess } from './shell.js';
|
|
10
11
|
import Services, { ServiceActions, ServiceEvents } from './services.js';
|
|
11
12
|
import Config, { ConfigActions } from './config.js';
|
|
12
|
-
import Git, { GitActions } from './git.js';
|
|
13
|
+
import Git, { GitActions, type GitSyncAuthor } from './git.js';
|
|
13
14
|
import { Disposable } from './types.js';
|
|
14
15
|
import { RemoteError } from './errors/index.js';
|
|
15
|
-
import { PublicationApi
|
|
16
|
+
import { PublicationApi } from './publication/index.js';
|
|
16
17
|
import { ServerApi } from './servers.js';
|
|
17
18
|
import { Feedback } from './feedback.js';
|
|
18
19
|
import { IntegrationApi, SandboxIntegrationApi } from './integrations/index.js';
|
|
19
20
|
export type { Disposable } from './types.js';
|
|
20
21
|
export { LspConnection } from './lsp.js';
|
|
21
|
-
export { FileChangeFilter, FileChangeType, FileType
|
|
22
|
+
export { FileChangeFilter, FileChangeType, FileType } from './filesystem.js';
|
|
22
23
|
export type { FileChange, FileContents, FileDeleteOptions, FileDownloadOptions, FileFollowOptions, FileLineRange, FileLineRangeResult, FileListOptions, FileOverwriteOptions, FileResult, FileSearchOptions, FileTailOptions, FileWriteOptions, Filesystem, Stats, TextSearchMatch, TextSearchOptions, TextSearchQuery, TextSearchResult, WatchOptions, } from './filesystem.js';
|
|
23
24
|
export type { PortInfo } from './runtime.js';
|
|
24
25
|
export type { RuntimeLogEntry } from './log.js';
|
|
@@ -30,9 +31,9 @@ export type { GitChangedFile, GitCheckoutResult, GitConflict, GitConflictsResult
|
|
|
30
31
|
export { notebookBuiltinServices, notebookKnownServices } from './services.js';
|
|
31
32
|
export type { NotebookBuiltinServiceName, NotebookKnownServiceName, NotebookServiceCommand, NotebookServiceKind, NotebookServiceName, NotebookServiceSource, NotebookServiceState, NotebookServiceStatus, ServiceLogOptions, ServiceLogStreamOptions, } from './services.js';
|
|
32
33
|
export type { ConfigPortMapping, ProjectConfig } from './config.js';
|
|
33
|
-
export { PHPSandboxError, RemoteError, TransportError
|
|
34
|
+
export { PHPSandboxError, RemoteError, TransportError } from './errors/index.js';
|
|
34
35
|
export type { HttpResponseDiagnostics, RemoteErrorCode, RemoteErrorSource, TransportErrorCode, ValidationErrorDetails, } from './errors/index.js';
|
|
35
|
-
export
|
|
36
|
+
export * from './publication/index.js';
|
|
36
37
|
export type { CreateServerInput, ServerData, ServerInstance, ServerListOptions, ServerSshOptions } from './servers.js';
|
|
37
38
|
export type { ConfigureFeedbackInput, FeedbackData, FeedbackListOptions, FeedbackSource, FeedbackStatus, FeedbackType, FeedbackWidgetConfig, FeedbackWidgetTarget, SubmitFeedbackInput, UpdateFeedbackInput, } from './feedback.js';
|
|
38
39
|
export type { Integration, IntegrationAuthorization, IntegrationAuthorizationType, IntegrationData, IntegrationProvider, IntegrationReference, LinkIntegrationInput, UpdateIntegrationInput, AttachSandboxIntegrationInput, SandboxIntegration, SandboxIntegrationData, SandboxIntegrationEffect, SandboxIntegrationReference, UpdateSandboxIntegrationInput, } from './integrations/index.js';
|
|
@@ -133,7 +134,12 @@ export interface NotebookImportInspectionData {
|
|
|
133
134
|
reason: string | null;
|
|
134
135
|
requiredSecrets: NotebookImportRequiredSecret[];
|
|
135
136
|
}
|
|
137
|
+
export interface NotebookGitConfiguration {
|
|
138
|
+
/** Set a sandbox default identity, or use null to reset it to the Helfer bot. */
|
|
139
|
+
author: GitSyncAuthor | null;
|
|
140
|
+
}
|
|
136
141
|
export interface NotebookLifecycleInput {
|
|
142
|
+
git?: NotebookGitConfiguration;
|
|
137
143
|
persistent?: true;
|
|
138
144
|
}
|
|
139
145
|
export interface CreateNotebookInput extends NotebookLifecycleInput {
|
|
@@ -144,6 +150,11 @@ export interface CreateNotebookInput extends NotebookLifecycleInput {
|
|
|
144
150
|
secrets?: UpsertNotebookSecretItemInput[];
|
|
145
151
|
}
|
|
146
152
|
export type ForkNotebookInput = NotebookLifecycleInput;
|
|
153
|
+
export interface UpdateNotebookInput {
|
|
154
|
+
title?: string;
|
|
155
|
+
visibility?: 'public' | 'private' | 'unlisted';
|
|
156
|
+
git?: NotebookGitConfiguration;
|
|
157
|
+
}
|
|
147
158
|
export interface NotebookPolicyData {
|
|
148
159
|
autoDeleteWhenStale: boolean;
|
|
149
160
|
staleAfterMinutes: number | null;
|
|
@@ -330,8 +341,8 @@ declare class ClientImplementation {
|
|
|
330
341
|
post<T extends unknown>(path: string, body?: unknown): Promise<{
|
|
331
342
|
data: T;
|
|
332
343
|
}>;
|
|
333
|
-
delete<T
|
|
334
|
-
data: T;
|
|
344
|
+
delete<T>(path: string): Promise<{
|
|
345
|
+
data: T | undefined;
|
|
335
346
|
}>;
|
|
336
347
|
put<T extends unknown>(path: string, body?: unknown): Promise<{
|
|
337
348
|
data: T;
|
|
@@ -341,6 +352,7 @@ declare class ClientImplementation {
|
|
|
341
352
|
}>;
|
|
342
353
|
stream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
343
354
|
sse(url: string, signal?: AbortSignal): Promise<ReadableStream<Uint8Array>>;
|
|
355
|
+
private requireData;
|
|
344
356
|
private makeRequest;
|
|
345
357
|
private fetchResponse;
|
|
346
358
|
}
|
|
@@ -365,6 +377,9 @@ export interface NotebookData {
|
|
|
365
377
|
slug?: string;
|
|
366
378
|
description?: string | null;
|
|
367
379
|
policy?: NotebookPolicyData;
|
|
380
|
+
git?: {
|
|
381
|
+
author: GitSyncAuthor;
|
|
382
|
+
};
|
|
368
383
|
}
|
|
369
384
|
export declare class NotebookInstance {
|
|
370
385
|
#private;
|
|
@@ -386,6 +401,7 @@ export declare class NotebookInstance {
|
|
|
386
401
|
readonly preview: NotebookPreview;
|
|
387
402
|
readonly mail: NotebookMail;
|
|
388
403
|
readonly feedback: Feedback;
|
|
404
|
+
readonly publication: NotebookPublication;
|
|
389
405
|
private readonly socket;
|
|
390
406
|
private readonly restInvoker;
|
|
391
407
|
private readonly emitter;
|
|
@@ -394,9 +410,9 @@ export declare class NotebookInstance {
|
|
|
394
410
|
private readonly disposables;
|
|
395
411
|
constructor(data: NotebookData, client: Client);
|
|
396
412
|
ready(): Promise<NotebookInitSuccessResult>;
|
|
413
|
+
/** Update sandbox metadata and Git defaults without restarting it. */
|
|
414
|
+
update(input: UpdateNotebookInput): Promise<NotebookData>;
|
|
397
415
|
fork(input?: Partial<ForkNotebookInput>): Promise<NotebookInstance>;
|
|
398
|
-
publication(): Promise<PublicationInstance | null>;
|
|
399
|
-
publish(input?: PublishInput): Promise<PublicationRun>;
|
|
400
416
|
run(command: string | string[], opts?: SpawnOptions): ShellProcess;
|
|
401
417
|
run(command: string, args: string[], opts?: SpawnOptions): ShellProcess;
|
|
402
418
|
exec(command: string | string[], opts?: SpawnOptions): Promise<ProcessResult>;
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
12
|
var _NotebookInstance_instances, _NotebookInstance_initPromise, _NotebookInstance_init;
|
|
13
|
+
import { NotebookPublication } from './publication/index.js';
|
|
13
14
|
import { Filesystem } from './filesystem.js';
|
|
14
15
|
import Terminals from './terminal.js';
|
|
15
16
|
import Auth from './auth.js';
|
|
@@ -23,17 +24,18 @@ import Config from './config.js';
|
|
|
23
24
|
import { Transport } from './socket/index.js';
|
|
24
25
|
import EventManager from './events/index.js';
|
|
25
26
|
import Git from './git.js';
|
|
26
|
-
import { PHPSandboxError, RemoteError, TransportError, remoteError
|
|
27
|
-
import { PublicationApi
|
|
27
|
+
import { PHPSandboxError, RemoteError, TransportError, remoteError } from './errors/index.js';
|
|
28
|
+
import { PublicationApi } from './publication/index.js';
|
|
28
29
|
import { ServerApi } from './servers.js';
|
|
29
30
|
import { RestRuntimeInvoker } from './runtime/rest.js';
|
|
30
31
|
import { Feedback } from './feedback.js';
|
|
31
32
|
import { IntegrationApi, SandboxIntegrationApi } from './integrations/index.js';
|
|
32
33
|
import { authenticatedRequest } from './http.js';
|
|
33
34
|
export { LspConnection } from './lsp.js';
|
|
34
|
-
export { FileChangeFilter, FileChangeType, FileType
|
|
35
|
+
export { FileChangeFilter, FileChangeType, FileType } from './filesystem.js';
|
|
35
36
|
export { notebookBuiltinServices, notebookKnownServices } from './services.js';
|
|
36
|
-
export { PHPSandboxError, RemoteError, TransportError
|
|
37
|
+
export { PHPSandboxError, RemoteError, TransportError } from './errors/index.js';
|
|
38
|
+
export * from './publication/index.js';
|
|
37
39
|
function normalizeNotebookSecretInputs(input) {
|
|
38
40
|
if (Array.isArray(input)) {
|
|
39
41
|
return input;
|
|
@@ -91,25 +93,25 @@ class ClientImplementation {
|
|
|
91
93
|
this.fetch = options.fetch;
|
|
92
94
|
}
|
|
93
95
|
this.headers = {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
Accept: 'application/json',
|
|
97
|
+
Authorization: `Bearer ${token}`,
|
|
96
98
|
'Content-Type': 'application/json',
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
get(path) {
|
|
100
|
-
return this.makeRequest('GET', path);
|
|
102
|
+
return this.requireData(this.makeRequest('GET', path));
|
|
101
103
|
}
|
|
102
104
|
post(path, body) {
|
|
103
|
-
return this.makeRequest('POST', path, { body: body === undefined ? undefined : JSON.stringify(body) });
|
|
105
|
+
return this.requireData(this.makeRequest('POST', path, { body: body === undefined ? undefined : JSON.stringify(body) }));
|
|
104
106
|
}
|
|
105
107
|
delete(path) {
|
|
106
108
|
return this.makeRequest('DELETE', path);
|
|
107
109
|
}
|
|
108
110
|
put(path, body) {
|
|
109
|
-
return this.makeRequest('PUT', path, { body: body === undefined ? undefined : JSON.stringify(body) });
|
|
111
|
+
return this.requireData(this.makeRequest('PUT', path, { body: body === undefined ? undefined : JSON.stringify(body) }));
|
|
110
112
|
}
|
|
111
113
|
patch(path, body) {
|
|
112
|
-
return this.makeRequest('PATCH', path, { body: body === undefined ? undefined : JSON.stringify(body) });
|
|
114
|
+
return this.requireData(this.makeRequest('PATCH', path, { body: body === undefined ? undefined : JSON.stringify(body) }));
|
|
113
115
|
}
|
|
114
116
|
async stream(path) {
|
|
115
117
|
const response = await this.fetchResponse(authenticatedRequest(new URL(path.replace(/^\//, ''), this.baseUrl), {
|
|
@@ -129,7 +131,7 @@ class ClientImplementation {
|
|
|
129
131
|
method: 'GET',
|
|
130
132
|
headers: {
|
|
131
133
|
...this.headers,
|
|
132
|
-
|
|
134
|
+
Accept: 'text/event-stream',
|
|
133
135
|
},
|
|
134
136
|
...(signal === undefined ? {} : { signal }),
|
|
135
137
|
}));
|
|
@@ -141,6 +143,13 @@ class ClientImplementation {
|
|
|
141
143
|
}
|
|
142
144
|
return response.body;
|
|
143
145
|
}
|
|
146
|
+
async requireData(request) {
|
|
147
|
+
const response = await request;
|
|
148
|
+
if (response.data === undefined) {
|
|
149
|
+
throw new TransportError('PHPSandbox API returned no data for a data request.', 'InvalidResponse');
|
|
150
|
+
}
|
|
151
|
+
return { ...response, data: response.data };
|
|
152
|
+
}
|
|
144
153
|
async makeRequest(method, path, init) {
|
|
145
154
|
const response = await this.fetchResponse(authenticatedRequest(new URL(path.replace(/^\//, ''), this.baseUrl), {
|
|
146
155
|
method,
|
|
@@ -159,7 +168,10 @@ class ClientImplementation {
|
|
|
159
168
|
}
|
|
160
169
|
try {
|
|
161
170
|
const payload = JSON.parse(body);
|
|
162
|
-
if (payload === null ||
|
|
171
|
+
if (payload === null ||
|
|
172
|
+
typeof payload !== 'object' ||
|
|
173
|
+
Array.isArray(payload) ||
|
|
174
|
+
!Object.prototype.hasOwnProperty.call(payload, 'data')) {
|
|
163
175
|
throw new TransportError('PHPSandbox API returned an invalid success response.', 'InvalidResponse', response);
|
|
164
176
|
}
|
|
165
177
|
return payload;
|
|
@@ -234,9 +246,7 @@ export class NotebookInstance {
|
|
|
234
246
|
this.emitter = EventManager.createInstance();
|
|
235
247
|
if (client.runtimeTransport === 'rest') {
|
|
236
248
|
this.socket = null;
|
|
237
|
-
this.restInvoker = new RestRuntimeInvoker(data, client.options.fetch ?? globalThis.fetch, runtimeUrlProvider === undefined
|
|
238
|
-
? undefined
|
|
239
|
-
: () => runtimeUrlProvider(data.id));
|
|
249
|
+
this.restInvoker = new RestRuntimeInvoker(data, client.options.fetch ?? globalThis.fetch, runtimeUrlProvider === undefined ? undefined : () => runtimeUrlProvider(data.id));
|
|
240
250
|
}
|
|
241
251
|
else {
|
|
242
252
|
this.restInvoker = null;
|
|
@@ -273,6 +283,7 @@ export class NotebookInstance {
|
|
|
273
283
|
this.preview = new NotebookPreview(client, this.data.id);
|
|
274
284
|
this.mail = new NotebookMail(client, this.data.id);
|
|
275
285
|
this.feedback = new Feedback(client, this.data.id);
|
|
286
|
+
this.publication = new NotebookPublication(this.data.id, client);
|
|
276
287
|
}
|
|
277
288
|
async ready() {
|
|
278
289
|
if (this.restInvoker !== null) {
|
|
@@ -297,28 +308,16 @@ export class NotebookInstance {
|
|
|
297
308
|
// Just apply a reasonable timeout for the entire initialization process
|
|
298
309
|
return ready();
|
|
299
310
|
}
|
|
311
|
+
/** Update sandbox metadata and Git defaults without restarting it. */
|
|
312
|
+
async update(input) {
|
|
313
|
+
const response = await this.client.put(`/notebook/${this.data.id}`, input);
|
|
314
|
+
Object.assign(this.data, response.data);
|
|
315
|
+
return this.data;
|
|
316
|
+
}
|
|
300
317
|
async fork(input = {}) {
|
|
301
318
|
const response = await this.client.post(`/notebook/${this.data.id}/fork`, input);
|
|
302
319
|
return new NotebookInstance(response.data, this.client);
|
|
303
320
|
}
|
|
304
|
-
async publication() {
|
|
305
|
-
try {
|
|
306
|
-
const response = await this.client.get(`/notebook/${this.data.id}/publication`);
|
|
307
|
-
return new PublicationInstance(response.data, this.client, this.data.id);
|
|
308
|
-
}
|
|
309
|
-
catch (error) {
|
|
310
|
-
if (RemoteError.is(error) && error.status === 404) {
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
throw error;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async publish(input) {
|
|
317
|
-
const response = await this.client.post(`/notebook/${this.data.id}/publication`, input);
|
|
318
|
-
const run = new PublicationRun(new PublicationInstance(response.data, this.client, this.data.id), this.client);
|
|
319
|
-
run.start();
|
|
320
|
-
return run;
|
|
321
|
-
}
|
|
322
321
|
run(command, argsOrOpts = [], opts) {
|
|
323
322
|
if (Array.isArray(argsOrOpts)) {
|
|
324
323
|
return this.shell.run(command, argsOrOpts, opts);
|
|
@@ -441,7 +440,11 @@ export class NotebookInstance {
|
|
|
441
440
|
return disposable;
|
|
442
441
|
}
|
|
443
442
|
onDidBootError(handler) {
|
|
444
|
-
const disposable = this.realtimeSocket().listen('okra.boot_error',
|
|
443
|
+
const disposable = this.realtimeSocket().listen('okra.boot_error', (error) => {
|
|
444
|
+
if (RemoteError.is(error, 'NotebookUnavailable')) {
|
|
445
|
+
handler(error);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
445
448
|
this.disposables.push(disposable);
|
|
446
449
|
return disposable;
|
|
447
450
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Client } from '../index.js';
|
|
2
|
+
import type { PublicationDomainData } from './types.js';
|
|
3
|
+
export declare class PublicationDomains {
|
|
4
|
+
private readonly client;
|
|
5
|
+
private readonly publicationId;
|
|
6
|
+
constructor(client: Client, publicationId: string);
|
|
7
|
+
list(): Promise<PublicationDomainData[]>;
|
|
8
|
+
create(hostname: string): Promise<PublicationDomainData>;
|
|
9
|
+
refresh(id: string): Promise<PublicationDomainData>;
|
|
10
|
+
/** Sets production APP_URL. Publish again to apply it to the running app. */
|
|
11
|
+
useAsApplicationUrl(id: string): Promise<{
|
|
12
|
+
url: string;
|
|
13
|
+
requiresPublication: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
delete(id: string): Promise<void>;
|
|
16
|
+
private path;
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class PublicationDomains {
|
|
2
|
+
constructor(client, publicationId) {
|
|
3
|
+
this.client = client;
|
|
4
|
+
this.publicationId = publicationId;
|
|
5
|
+
}
|
|
6
|
+
async list() {
|
|
7
|
+
return (await this.client.get(this.path())).data;
|
|
8
|
+
}
|
|
9
|
+
async create(hostname) {
|
|
10
|
+
return (await this.client.post(this.path(), { hostname })).data;
|
|
11
|
+
}
|
|
12
|
+
async refresh(id) {
|
|
13
|
+
return (await this.client.post(`${this.path()}/${encodeURIComponent(id)}/refresh`)).data;
|
|
14
|
+
}
|
|
15
|
+
/** Sets production APP_URL. Publish again to apply it to the running app. */
|
|
16
|
+
async useAsApplicationUrl(id) {
|
|
17
|
+
return (await this.client.post(`${this.path()}/${encodeURIComponent(id)}/application-url`)).data;
|
|
18
|
+
}
|
|
19
|
+
async delete(id) {
|
|
20
|
+
await this.client.delete(`${this.path()}/${encodeURIComponent(id)}`);
|
|
21
|
+
}
|
|
22
|
+
path() {
|
|
23
|
+
return `/publications/${encodeURIComponent(this.publicationId)}/domains`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { NotebookPublication } from './notebook.js';
|
|
2
|
+
export { PublicationApi, PublicationInstance } from './instance.js';
|
|
3
|
+
export { PublicationRun } from './run.js';
|
|
4
|
+
export type * from './types.js';
|
|
5
|
+
export type { BuiltInPublicationProviderName, PublicationStatus, PublicationBuildStatus, PublicationReleaseStatus, PublicationSize, PublicationRegion, PublicationJurisdiction, PublicationProtectionMode, PublicationLogStream, PublicationEventData, PublicationLogChunkData, PublishStreamPhase, PublishStreamLog, PublishStreamResult, PublishStreamEvent, PublishStreamSseEvent, } from '../schemas/publications.js';
|
|
6
|
+
export { laravelCloudSetupForRepublish } from './providers/laravel-cloud.js';
|
|
7
|
+
export { PublicationResources } from './resources.js';
|
|
8
|
+
export { PublicationDomains } from './domains.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { NotebookPublication } from './notebook.js';
|
|
2
|
+
export { PublicationApi, PublicationInstance } from './instance.js';
|
|
3
|
+
export { PublicationRun } from './run.js';
|
|
4
|
+
export { laravelCloudSetupForRepublish } from './providers/laravel-cloud.js';
|
|
5
|
+
export { PublicationResources } from './resources.js';
|
|
6
|
+
export { PublicationDomains } from './domains.js';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Client } from '../index.js';
|
|
2
|
+
import type { PublicationEventData, PublicationLogChunkData } from '../schemas/publications.js';
|
|
3
|
+
import type { PublicationProtectionData, LaravelCloudSetupInput, PublicationProviderName, PublicationData, UpdatePublicationProtectionInput, PublicationProtectionSessionData, PublicationDestroyOptions } from './types.js';
|
|
4
|
+
import { PublicationRun } from './run.js';
|
|
5
|
+
import { PublicationResources } from './resources.js';
|
|
6
|
+
import { PublicationDomains } from './domains.js';
|
|
7
|
+
export declare class PublicationApi {
|
|
8
|
+
private readonly client;
|
|
9
|
+
readonly resources: PublicationResources;
|
|
10
|
+
constructor(client: Client);
|
|
11
|
+
get<TProvider extends PublicationProviderName = PublicationProviderName>(id: string): Promise<PublicationInstance<TProvider>>;
|
|
12
|
+
}
|
|
13
|
+
export declare class PublicationInstance<TProvider extends PublicationProviderName = PublicationProviderName> {
|
|
14
|
+
readonly data: PublicationData<TProvider>;
|
|
15
|
+
private readonly client;
|
|
16
|
+
private readonly notebookId?;
|
|
17
|
+
readonly domains: PublicationDomains;
|
|
18
|
+
constructor(data: PublicationData<TProvider>, client: Client, notebookId?: string | undefined);
|
|
19
|
+
reconcileLaravelCloudResource(resourceId: string): Promise<PublicationInstance<TProvider>>;
|
|
20
|
+
configureLaravelCloud(setup: LaravelCloudSetupInput): Promise<PublicationInstance<TProvider>>;
|
|
21
|
+
refresh(): Promise<PublicationInstance<TProvider>>;
|
|
22
|
+
/** Start or reattach to the current release stream without queuing another release. */
|
|
23
|
+
follow(): PublicationRun<TProvider>;
|
|
24
|
+
publish(): Promise<PublicationRun<TProvider>>;
|
|
25
|
+
destroy(options?: PublicationDestroyOptions): Promise<void>;
|
|
26
|
+
wait(options?: {
|
|
27
|
+
intervalMs?: number;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
}): Promise<PublicationInstance<TProvider>>;
|
|
30
|
+
events(): Promise<ReadableStream<PublicationEventData>>;
|
|
31
|
+
buildLogs(buildId?: string): Promise<ReadableStream<PublicationLogChunkData>>;
|
|
32
|
+
logSnapshot(stream: 'build' | 'runtime', limit?: number): Promise<{
|
|
33
|
+
stream: 'build' | 'runtime';
|
|
34
|
+
content: string;
|
|
35
|
+
truncated: boolean;
|
|
36
|
+
}>;
|
|
37
|
+
logs(): Promise<ReadableStream<PublicationLogChunkData>>;
|
|
38
|
+
setProtection(input: UpdatePublicationProtectionInput): Promise<PublicationInstance<TProvider>>;
|
|
39
|
+
protection(): Promise<PublicationProtectionData>;
|
|
40
|
+
createProtectionSession(): Promise<PublicationProtectionSessionData>;
|
|
41
|
+
disableProtection(): Promise<PublicationInstance<TProvider>>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { PublicationEventDataSchema, PublicationLogChunkDataSchema } from '../schemas/publications.js';
|
|
2
|
+
import { PHPSandboxError, TransportError } from '../errors/index.js';
|
|
3
|
+
import { PublicationRun } from './run.js';
|
|
4
|
+
import { PublicationResources } from './resources.js';
|
|
5
|
+
import { PublicationDomains } from './domains.js';
|
|
6
|
+
export class PublicationApi {
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
this.resources = new PublicationResources(client);
|
|
10
|
+
}
|
|
11
|
+
async get(id) {
|
|
12
|
+
const response = await this.client.get(`/publications/${encodeURIComponent(id)}`);
|
|
13
|
+
return new PublicationInstance(response.data, this.client);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class PublicationInstance {
|
|
17
|
+
constructor(data, client, notebookId) {
|
|
18
|
+
this.data = data;
|
|
19
|
+
this.client = client;
|
|
20
|
+
this.notebookId = notebookId;
|
|
21
|
+
this.domains = new PublicationDomains(client, data.id);
|
|
22
|
+
}
|
|
23
|
+
async reconcileLaravelCloudResource(resourceId) {
|
|
24
|
+
const response = await this.client.post(`/publications/${encodeURIComponent(this.data.id)}/laravel-cloud/reconcile`, { resourceId });
|
|
25
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
26
|
+
}
|
|
27
|
+
async configureLaravelCloud(setup) {
|
|
28
|
+
const response = await this.client.put(`/publications/${encodeURIComponent(this.data.id)}/laravel-cloud/setup`, { setup });
|
|
29
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
30
|
+
}
|
|
31
|
+
async refresh() {
|
|
32
|
+
const response = await this.client.get(`/publications/${encodeURIComponent(this.data.id)}`);
|
|
33
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
34
|
+
}
|
|
35
|
+
/** Start or reattach to the current release stream without queuing another release. */
|
|
36
|
+
follow() {
|
|
37
|
+
return new PublicationRun(this, this.client).start();
|
|
38
|
+
}
|
|
39
|
+
async publish() {
|
|
40
|
+
if (!this.notebookId) {
|
|
41
|
+
throw new PHPSandboxError('Publishing requires a notebook-scoped publication instance.');
|
|
42
|
+
}
|
|
43
|
+
const response = await this.client.post(`/notebook/${encodeURIComponent(this.notebookId)}/publication`);
|
|
44
|
+
const run = new PublicationRun(new PublicationInstance(response.data, this.client, this.notebookId), this.client);
|
|
45
|
+
run.start();
|
|
46
|
+
return run;
|
|
47
|
+
}
|
|
48
|
+
async destroy(options = {}) {
|
|
49
|
+
const query = options.deleteResources ? '?deleteResources=1' : '';
|
|
50
|
+
await this.client.delete(`/publications/${encodeURIComponent(this.data.id)}${query}`);
|
|
51
|
+
}
|
|
52
|
+
async wait(options = {}) {
|
|
53
|
+
const intervalMs = options.intervalMs ?? 1000;
|
|
54
|
+
const timeoutMs = options.timeoutMs ?? 300000;
|
|
55
|
+
const startedAt = Date.now();
|
|
56
|
+
let current = this;
|
|
57
|
+
while (!publicationStatusIsTerminal(current.data.status)) {
|
|
58
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
59
|
+
throw new PHPSandboxError(`Timed out waiting for publication ${this.data.id}`);
|
|
60
|
+
}
|
|
61
|
+
await delay(intervalMs);
|
|
62
|
+
current = await current.refresh();
|
|
63
|
+
}
|
|
64
|
+
return current;
|
|
65
|
+
}
|
|
66
|
+
async events() {
|
|
67
|
+
return parseNdjsonStream(await this.client.stream(`/publications/${encodeURIComponent(this.data.id)}/events/stream`), PublicationEventDataSchema);
|
|
68
|
+
}
|
|
69
|
+
buildLogs(buildId = this.data.latestBuild?.id ?? '') {
|
|
70
|
+
if (buildId === '') {
|
|
71
|
+
return Promise.reject(new PHPSandboxError('Publication has no latest build id'));
|
|
72
|
+
}
|
|
73
|
+
return this.client
|
|
74
|
+
.stream(`/publications/${encodeURIComponent(this.data.id)}/builds/${encodeURIComponent(buildId)}/logs/stream`)
|
|
75
|
+
.then((stream) => parseNdjsonStream(stream, PublicationLogChunkDataSchema));
|
|
76
|
+
}
|
|
77
|
+
async logSnapshot(stream, limit = 50) {
|
|
78
|
+
const query = new URLSearchParams({ stream, limit: String(limit) });
|
|
79
|
+
return (await this.client.get(`/publications/${encodeURIComponent(this.data.id)}/logs?${query}`)).data;
|
|
80
|
+
}
|
|
81
|
+
async logs() {
|
|
82
|
+
return parseNdjsonStream(await this.client.stream(`/publications/${encodeURIComponent(this.data.id)}/logs/stream`), PublicationLogChunkDataSchema);
|
|
83
|
+
}
|
|
84
|
+
async setProtection(input) {
|
|
85
|
+
const response = await this.client.put(`/publications/${encodeURIComponent(this.data.id)}/protection`, input);
|
|
86
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
87
|
+
}
|
|
88
|
+
async protection() {
|
|
89
|
+
const response = await this.client.get(`/publications/${encodeURIComponent(this.data.id)}/protection`);
|
|
90
|
+
return response.data;
|
|
91
|
+
}
|
|
92
|
+
async createProtectionSession() {
|
|
93
|
+
const response = await this.client.post(`/publications/${encodeURIComponent(this.data.id)}/protection/session`);
|
|
94
|
+
return response.data;
|
|
95
|
+
}
|
|
96
|
+
async disableProtection() {
|
|
97
|
+
const response = await this.client.delete(`/publications/${encodeURIComponent(this.data.id)}/protection`);
|
|
98
|
+
if (!response.data) {
|
|
99
|
+
throw new TransportError('Protection response has no publication data.', 'InvalidResponse');
|
|
100
|
+
}
|
|
101
|
+
return new PublicationInstance(response.data, this.client, this.notebookId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function publicationStatusIsTerminal(status) {
|
|
105
|
+
return ['healthy', 'failed', 'stopped', 'deleted', 'delete_failed'].includes(status);
|
|
106
|
+
}
|
|
107
|
+
function delay(ms) {
|
|
108
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
109
|
+
}
|
|
110
|
+
function parseNdjsonStream(input, schema) {
|
|
111
|
+
const decoder = new TextDecoder();
|
|
112
|
+
let buffer = '';
|
|
113
|
+
return input.pipeThrough(new TransformStream({
|
|
114
|
+
transform(chunk, controller) {
|
|
115
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
116
|
+
const lines = buffer.split('\n');
|
|
117
|
+
buffer = lines.pop() ?? '';
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const trimmed = line.trim();
|
|
120
|
+
if (trimmed !== '') {
|
|
121
|
+
controller.enqueue(schema.parse(JSON.parse(trimmed)));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
flush(controller) {
|
|
126
|
+
buffer += decoder.decode();
|
|
127
|
+
const trimmed = buffer.trim();
|
|
128
|
+
if (trimmed !== '') {
|
|
129
|
+
controller.enqueue(schema.parse(JSON.parse(trimmed)));
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Client } from '../index.js';
|
|
2
|
+
import { PublicationInstance } from './instance.js';
|
|
3
|
+
import { PublicationRun } from './run.js';
|
|
4
|
+
import { PublicationResources } from './resources.js';
|
|
5
|
+
import type { PlannedPublishInput, PublicationPlan, PublicationPlanInput, PublicationProviderName, PublicationReadiness, PublicationResourceCatalog } from './types.js';
|
|
6
|
+
export declare class NotebookPublication {
|
|
7
|
+
private readonly notebookId;
|
|
8
|
+
private readonly client;
|
|
9
|
+
readonly resources: PublicationResources;
|
|
10
|
+
constructor(notebookId: string, client: Client);
|
|
11
|
+
private get path();
|
|
12
|
+
current(): Promise<PublicationInstance | null>;
|
|
13
|
+
readiness(): Promise<PublicationReadiness>;
|
|
14
|
+
/** Review a publishing plan without committing changes or creating resources. */
|
|
15
|
+
prepare<TName extends PublicationProviderName>(input: PublicationPlanInput<TName>): Promise<PublicationPlan<TName>>;
|
|
16
|
+
catalog(provider: 'laravel-cloud' | 'cloudflare-containers'): Promise<PublicationResourceCatalog>;
|
|
17
|
+
catalog(provider: 'ssh-server', serverId: string): Promise<PublicationResourceCatalog>;
|
|
18
|
+
/** Core validates the plan, prepares source and executes publishing. */
|
|
19
|
+
publish(input?: PlannedPublishInput): Promise<PublicationRun>;
|
|
20
|
+
}
|