@phpsandbox/sdk 0.2.3 → 0.3.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 CHANGED
@@ -81,7 +81,7 @@ console.log(persistentFork.data.policy);
81
81
 
82
82
  Notes:
83
83
 
84
- - Runtime actions wait for the sandbox to become ready before Okra handles them.
84
+ - Runtime actions wait for the sandbox to become ready before the runtime handles them.
85
85
  - Call `ready()` explicitly only when you need provisioning results such as the preview URL or opened ports.
86
86
  - API notebook creates and forks are ephemeral by default. `persistent: true` requires an entitled account.
87
87
  - Use `NotebookData.runtimeUrl`, `runtimeUrlProvider`, and `PublicationData.eventStreamUrl` for runtime access.
@@ -370,32 +370,51 @@ try {
370
370
 
371
371
  MIT
372
372
 
373
- ### Publishing without Helfer
373
+ ### Publishing apps
374
374
 
375
- Publishing is a platform capability. An API-key client can assign production settings with `notebook.secrets`, discover destinations and owned resources through `notebook.publication.catalog`, and submit its application choices through `prepareApplication`.
375
+ Save your app configuration, prepare a proposal for the apps you want to publish, and submit that proposal after explicit confirmation. Use `notebook.secrets` for production secrets and `notebook.publication.catalog` to discover destinations and available resources.
376
376
 
377
377
  ```ts
378
378
  const notebook = await client.notebook.get('SANDBOX_ID');
379
- const review = await notebook.publication.prepareApplication({
380
- schemaVersion: 1,
381
- components: [{
382
- id: 'web', kind: 'http-service', root: '.',
383
- build: { mode: 'dockerfile', context: '.', dockerfile: { source: 'project', path: 'Dockerfile' } },
384
- runtime: { kind: 'http', port: 3333, healthCheck: { path: '/' } },
385
- placement: { provider: 'ssh-server', serverId: 'OWNED_SERVER_ID' },
386
- }],
387
- });
388
- if (!review.review.ready) {
389
- console.log(review.review.blockers);
390
- } else {
391
- // Present this exact review and obtain confirmation before executing.
392
- const application = await notebook.publication.publishApplication({ reviewId: review.review.id });
393
- const current = await notebook.publication.application(application.id);
394
- console.log(current.status); // publishing, healthy, failed, or deleted
379
+ try {
380
+ const configuration = await notebook.publication.updateConfiguration({
381
+ expectedRevision: 0,
382
+ operations: [{ op: 'add-app', app: {
383
+ name: 'Backend', kind: 'http', root: '.',
384
+ build: { mode: 'dockerfile', context: '.', dockerfile: { source: 'project', path: 'Dockerfile' } },
385
+ runtime: { mode: 'container', port: 3333, healthCheck: { path: '/' } },
386
+ destination: { provider: 'ssh-server', serverId: 'OWNED_SERVER_ID' },
387
+ routing: { mode: 'managed' }, resourceIds: [],
388
+ } }],
389
+ });
390
+ const appIds = [configuration.apps[0].id];
391
+ const plan = await notebook.publication.prepare({
392
+ expectedRevision: configuration.revision, appIds,
393
+ });
394
+ if (!plan.review.ready) {
395
+ console.log(plan.review.blockers);
396
+ } else {
397
+ // Show this proposal to the user and wait for their confirmation.
398
+ const result = await notebook.publication.publish({
399
+ reviewId: plan.review.id, proposal: plan.review.proposal, appIds,
400
+ });
401
+ if ('confirmationRequired' in result) {
402
+ // Show the changes and updated proposal; obtain a new confirmation.
403
+ console.log(result.changes, result.plan);
404
+ } else {
405
+ const current = await notebook.publication.application(result.id);
406
+ console.log(current.status); // publishing, healthy, partial, failed, or deleted
407
+ }
408
+ }
409
+ } finally {
410
+ notebook.dispose();
395
411
  }
396
- notebook.dispose();
397
412
  ```
398
413
 
399
- Core owns validation, source snapshots, review expiry, identity, resource ownership, execution and recovery. The confirmation reference binds the resolved review; another client does not copy source revisions or recreate provider logic. Repeated confirmation of an executed reference returns its existing application. A corrected review retains the publication and address. `retryApplication(id)` asks the platform to revalidate and retry failed components; inspect current state and logs when an outcome is uncertain. `destroyApplication(id)` unpublishes, and resource deletion requires the explicit `deleteResources` option.
414
+ `configuration()` returns saved apps and actual deployment inventory. Configuration edits require `expectedRevision`; omitted apps remain unchanged, and removing an app from configuration does not unpublish it. An existing deployment is adopted explicitly using its exact publication ID.
415
+
416
+ Preparing or viewing a proposal does not start publishing. Confirmation sends the signed `proposal` unchanged along with its `reviewId` and app selection. Current source is captured when that confirmation is submitted. If material settings changed, `publish()` returns `confirmationRequired` without starting a deployment. Show those changes and obtain confirmation of the updated proposal before trying again. Repeating an already executed confirmation returns its existing operation.
417
+
418
+ Inspect deployment, runtime and routing outcomes for each selected app; a partial outcome is not full success. `retryApplication(id)` retries failed apps after revalidation. If an outcome is uncertain, inspect status and logs before retrying. `destroyApplication(id)` unpublishes; deleting managed resources additionally requires `deleteResources: true`.
400
419
 
401
- Helfer presents choices, recommendations and explanations, and resumes its own conversation from platform outcomes. Its chat monitor does not own builds or publication state. The CLI exposes the same operations as `application plan`, `application publish`, `application status`, `application retry`, and `application delete`; JSON input is available for multi-component plans.
420
+ Shared managed-resource creation currently starts with one app. After creation, update the resource definition to `reuse` with the catalog resource ID before attaching other apps. Simultaneous first-time shared-resource creation is unsupported.
@@ -15146,17 +15146,6 @@ var PublicationInstance = class _PublicationInstance {
15146
15146
  follow() {
15147
15147
  return new PublicationRun(this, this.client).start();
15148
15148
  }
15149
- async publish() {
15150
- if (!this.notebookId) {
15151
- throw new PHPSandboxError("Publishing requires a notebook-scoped publication instance.");
15152
- }
15153
- const response = await this.client.post(
15154
- `/notebook/${encodeURIComponent(this.notebookId)}/publication`
15155
- );
15156
- const run = new PublicationRun(new _PublicationInstance(response.data, this.client, this.notebookId), this.client);
15157
- run.start();
15158
- return run;
15159
- }
15160
15149
  async destroy(options = {}) {
15161
15150
  const query = options.deleteResources ? "?deleteResources=1" : "";
15162
15151
  await this.client.delete(`/publications/${encodeURIComponent(this.data.id)}${query}`);
@@ -15283,24 +15272,28 @@ var NotebookPublication = class {
15283
15272
  async readiness() {
15284
15273
  return (await this.client.get(`${this.path}/publication/readiness`)).data;
15285
15274
  }
15286
- /** Review a publishing plan without committing changes or creating resources. */
15275
+ /** Inspect saved configuration and the actual inventory, including removed and legacy apps. */
15276
+ async configuration() {
15277
+ return (await this.client.get(`${this.path}/publication/configuration`)).data;
15278
+ }
15279
+ /** Explicit operations preserve omitted apps. Removals never stop deployments or delete resource data. */
15280
+ async updateConfiguration(input) {
15281
+ return (await this.client.patch(`${this.path}/publication/configuration`, input)).data;
15282
+ }
15283
+ /** Review all or selected configured apps at an exact saved revision. */
15287
15284
  async prepare(input) {
15288
15285
  return (await this.client.post(`${this.path}/publication/plan`, input)).data;
15289
15286
  }
15290
- /** Review a multi-component publishing plan without creating resources or starting releases. */
15291
- async prepareApplication(input) {
15292
- return (await this.client.post(`${this.path}/publication/application-plan`, input)).data;
15293
- }
15294
- /** Publish every component in a reviewed application plan. */
15295
- async publishApplication(input) {
15296
- const application = (await this.client.post(`${this.path}/publication/application`, input)).data;
15297
- this.startApplicationRuns(application);
15287
+ /** Publish the exact app selection in a server-owned review. */
15288
+ async publish(input) {
15289
+ const application = (await this.client.post(`${this.path}/publication`, input)).data;
15290
+ if (!("confirmationRequired" in application)) this.startApplicationRuns(application);
15298
15291
  return application;
15299
15292
  }
15300
15293
  async application(applicationId) {
15301
15294
  return (await this.client.get(`${this.path}/publication/application/${encodeURIComponent(applicationId)}`)).data;
15302
15295
  }
15303
- /** Retry only failed components while leaving healthy components untouched. */
15296
+ /** Retry failed apps and pending route attachments while preserving running releases. */
15304
15297
  async retryApplication(applicationId) {
15305
15298
  const application = (await this.client.post(
15306
15299
  `${this.path}/publication/application/${encodeURIComponent(applicationId)}/retry`,
@@ -15314,10 +15307,11 @@ var NotebookPublication = class {
15314
15307
  await this.client.delete(`${this.path}/publication/application/${encodeURIComponent(applicationId)}${query}`);
15315
15308
  }
15316
15309
  startApplicationRuns(application) {
15317
- for (const component of application.components) {
15318
- if (!["pending", "queued", "building", "deploying"].includes(component.publication.status)) continue;
15310
+ for (const app of application.apps) {
15311
+ if (!(application.selectedAppIds ?? []).includes(app.appId)) continue;
15312
+ if (!["pending", "queued", "building", "deploying"].includes(app.publication.status)) continue;
15319
15313
  new PublicationRun(
15320
- new PublicationInstance(component.publication, this.client, this.notebookId),
15314
+ new PublicationInstance(app.publication, this.client, this.notebookId),
15321
15315
  this.client
15322
15316
  ).start();
15323
15317
  }
@@ -15329,11 +15323,6 @@ var NotebookPublication = class {
15329
15323
  }
15330
15324
  return (await this.client.get(`${this.path}/publication/catalog?${query}`)).data;
15331
15325
  }
15332
- /** Core validates the plan, prepares source and executes publishing. */
15333
- async publish(input) {
15334
- const response = await this.client.post(`${this.path}/publication`, input);
15335
- return new PublicationRun(new PublicationInstance(response.data, this.client, this.notebookId), this.client).start();
15336
- }
15337
15326
  };
15338
15327
 
15339
15328
  // src/publication/providers/laravel-cloud.ts