@phpsandbox/sdk 0.0.52 → 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/README.md +6 -5
- package/dist/browser/phpsandbox-sdk.esm.js +276 -9
- package/dist/browser/phpsandbox-sdk.esm.min.js +3 -2
- package/dist/browser/phpsandbox-sdk.iife.js +276 -9
- 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/git.d.ts +20 -8
- package/dist/git.js +31 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +45 -1
- package/examples/git-merge-smoke.ts +9 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,16 +220,15 @@ await notebook.git.revert({ path: 'README.md' });
|
|
|
220
220
|
await notebook.git.revert({ path: 'staged-file.php', staged: true });
|
|
221
221
|
|
|
222
222
|
const fork = await notebook.fork();
|
|
223
|
-
const forkCredentials = await fork.git.credentials();
|
|
224
223
|
const preview = await notebook.git.diff({
|
|
225
|
-
|
|
226
|
-
token:
|
|
224
|
+
notebookId: fork.data.id,
|
|
225
|
+
token: process.env.PHPSANDBOX_TOKEN,
|
|
227
226
|
});
|
|
228
227
|
|
|
229
228
|
if (preview.status === 'ready') {
|
|
230
229
|
const result = await notebook.git.merge({
|
|
231
|
-
|
|
232
|
-
token:
|
|
230
|
+
notebookId: fork.data.id,
|
|
231
|
+
token: process.env.PHPSANDBOX_TOKEN,
|
|
233
232
|
expectedBaseRef: preview.baseRef,
|
|
234
233
|
author: 'PHPSandbox <hi@phpsandbox.io>',
|
|
235
234
|
message: 'Merge fork into base',
|
|
@@ -241,6 +240,8 @@ if (preview.status === 'ready') {
|
|
|
241
240
|
}
|
|
242
241
|
```
|
|
243
242
|
|
|
243
|
+
Use `notebookId` when diffing or merging from another PHPSandbox notebook. Use `url` for external Git remotes. `notebookId`, `url`, and `target` are mutually exclusive.
|
|
244
|
+
|
|
244
245
|
Fork diff requires the base and fork to share Git history. If they do not, `diff()` returns `status: 'unrelated'`.
|
|
245
246
|
|
|
246
247
|
### Mail
|
|
@@ -2848,15 +2848,15 @@ var ReconnectingWebSocket = (
|
|
|
2848
2848
|
};
|
|
2849
2849
|
ReconnectingWebSocket3.prototype._getNextDelay = function() {
|
|
2850
2850
|
var _a = this._options, _b = _a.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d;
|
|
2851
|
-
var
|
|
2851
|
+
var delay2 = 0;
|
|
2852
2852
|
if (this._retryCount > 0) {
|
|
2853
|
-
|
|
2854
|
-
if (
|
|
2855
|
-
|
|
2853
|
+
delay2 = minReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, this._retryCount - 1);
|
|
2854
|
+
if (delay2 > maxReconnectionDelay) {
|
|
2855
|
+
delay2 = maxReconnectionDelay;
|
|
2856
2856
|
}
|
|
2857
2857
|
}
|
|
2858
|
-
this._debug("next delay",
|
|
2859
|
-
return
|
|
2858
|
+
this._debug("next delay", delay2);
|
|
2859
|
+
return delay2;
|
|
2860
2860
|
};
|
|
2861
2861
|
ReconnectingWebSocket3.prototype._wait = function() {
|
|
2862
2862
|
var _this = this;
|
|
@@ -3825,10 +3825,10 @@ var Git = class {
|
|
|
3825
3825
|
return this.okra.invoke("git.log", { ref });
|
|
3826
3826
|
}
|
|
3827
3827
|
diff(input) {
|
|
3828
|
-
return this.okra.invoke("git.diff", input);
|
|
3828
|
+
return this.okra.invoke("git.diff", this.normalizeRemoteInput(input));
|
|
3829
3829
|
}
|
|
3830
3830
|
merge(input) {
|
|
3831
|
-
return this.okra.invoke("git.merge", input);
|
|
3831
|
+
return this.okra.invoke("git.merge", this.normalizeRemoteInput(input));
|
|
3832
3832
|
}
|
|
3833
3833
|
conflicts() {
|
|
3834
3834
|
return this.okra.invoke("git.conflicts", {});
|
|
@@ -3860,6 +3860,35 @@ var Git = class {
|
|
|
3860
3860
|
status() {
|
|
3861
3861
|
return this.okra.invoke("git.status", {});
|
|
3862
3862
|
}
|
|
3863
|
+
normalizeRemoteInput(input) {
|
|
3864
|
+
if (input.notebookId === void 0) {
|
|
3865
|
+
return input;
|
|
3866
|
+
}
|
|
3867
|
+
const notebookId = input.notebookId.trim();
|
|
3868
|
+
if (!notebookId) {
|
|
3869
|
+
throw new Error("'notebookId' cannot be empty.");
|
|
3870
|
+
}
|
|
3871
|
+
if (input.url?.trim()) {
|
|
3872
|
+
throw new Error("Pass either 'url' or 'notebookId', not both.");
|
|
3873
|
+
}
|
|
3874
|
+
if (input.target?.trim()) {
|
|
3875
|
+
throw new Error("Pass either 'target' or 'notebookId', not both.");
|
|
3876
|
+
}
|
|
3877
|
+
const { notebookId: _notebookId, ...payload } = input;
|
|
3878
|
+
return {
|
|
3879
|
+
...payload,
|
|
3880
|
+
url: this.gitUrlForNotebook(notebookId)
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3883
|
+
gitUrlForNotebook(notebookId) {
|
|
3884
|
+
const url = new URL(this.okra.data.gitUrl);
|
|
3885
|
+
url.username = "";
|
|
3886
|
+
url.password = "";
|
|
3887
|
+
url.pathname = `/${encodeURIComponent(notebookId)}.git`;
|
|
3888
|
+
url.search = "";
|
|
3889
|
+
url.hash = "";
|
|
3890
|
+
return url.toString();
|
|
3891
|
+
}
|
|
3863
3892
|
};
|
|
3864
3893
|
|
|
3865
3894
|
// src/beacon/navigator.ts
|
|
@@ -4588,6 +4617,198 @@ function isBeaconSupported() {
|
|
|
4588
4617
|
}
|
|
4589
4618
|
}
|
|
4590
4619
|
|
|
4620
|
+
// src/deployments.ts
|
|
4621
|
+
var NotebookDeploymentApi = class {
|
|
4622
|
+
constructor(client) {
|
|
4623
|
+
this.client = client;
|
|
4624
|
+
}
|
|
4625
|
+
async create(id, input = {}) {
|
|
4626
|
+
const response = await this.client.post(`/notebook/${id}/deployments`, input);
|
|
4627
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4628
|
+
}
|
|
4629
|
+
async list(id) {
|
|
4630
|
+
const response = await this.client.get(`/notebook/${id}/deployments`);
|
|
4631
|
+
return response.data;
|
|
4632
|
+
}
|
|
4633
|
+
async slugAvailability(id, slug) {
|
|
4634
|
+
const query = new URLSearchParams({ slug }).toString();
|
|
4635
|
+
const response = await this.client.get(
|
|
4636
|
+
`/notebook/${id}/deployments/slug-availability?${query}`
|
|
4637
|
+
);
|
|
4638
|
+
return response.data;
|
|
4639
|
+
}
|
|
4640
|
+
};
|
|
4641
|
+
var DeploymentApi = class {
|
|
4642
|
+
constructor(client) {
|
|
4643
|
+
this.client = client;
|
|
4644
|
+
}
|
|
4645
|
+
async get(id) {
|
|
4646
|
+
const response = await this.client.get(`/deployments/${id}`);
|
|
4647
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4648
|
+
}
|
|
4649
|
+
async redeploy(id, input = {}) {
|
|
4650
|
+
const response = await this.client.post(`/deployments/${id}/redeploy`, input);
|
|
4651
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4652
|
+
}
|
|
4653
|
+
async delete(id) {
|
|
4654
|
+
await this.client.delete(`/deployments/${id}`);
|
|
4655
|
+
}
|
|
4656
|
+
async setProtection(id, input) {
|
|
4657
|
+
const response = await this.client.put(`/deployments/${id}/protection`, input);
|
|
4658
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4659
|
+
}
|
|
4660
|
+
async protection(id) {
|
|
4661
|
+
const response = await this.client.get(`/deployments/${id}/protection`);
|
|
4662
|
+
return response.data;
|
|
4663
|
+
}
|
|
4664
|
+
async createProtectionSession(id) {
|
|
4665
|
+
const response = await this.client.post(`/deployments/${id}/protection/session`);
|
|
4666
|
+
return response.data;
|
|
4667
|
+
}
|
|
4668
|
+
async disableProtection(id) {
|
|
4669
|
+
const response = await this.client.delete(`/deployments/${id}/protection`);
|
|
4670
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4671
|
+
}
|
|
4672
|
+
async setFeedback(id, input) {
|
|
4673
|
+
const response = await this.client.put(`/deployments/${id}/feedback`, input);
|
|
4674
|
+
return new DeploymentInstance(response.data, this.client);
|
|
4675
|
+
}
|
|
4676
|
+
async listDomains(id) {
|
|
4677
|
+
const response = await this.client.get(
|
|
4678
|
+
`/deployments/${id}/domains`
|
|
4679
|
+
);
|
|
4680
|
+
return unwrapDeploymentDomainCollection(response.data);
|
|
4681
|
+
}
|
|
4682
|
+
async createDomain(id, input) {
|
|
4683
|
+
const response = await this.client.post(`/deployments/${id}/domains`, input);
|
|
4684
|
+
return response.data;
|
|
4685
|
+
}
|
|
4686
|
+
async refreshDomain(id, domainId) {
|
|
4687
|
+
const response = await this.client.post(`/deployments/${id}/domains/${domainId}/refresh`);
|
|
4688
|
+
return response.data;
|
|
4689
|
+
}
|
|
4690
|
+
async deleteDomain(id, domainId) {
|
|
4691
|
+
await this.client.delete(`/deployments/${id}/domains/${domainId}`);
|
|
4692
|
+
}
|
|
4693
|
+
async events(id) {
|
|
4694
|
+
return parseNdjsonStream(await this.client.stream(`/deployments/${id}/events/stream`));
|
|
4695
|
+
}
|
|
4696
|
+
async buildLogs(id, buildId) {
|
|
4697
|
+
return parseNdjsonStream(
|
|
4698
|
+
await this.client.stream(`/deployments/${id}/builds/${buildId}/logs/stream`)
|
|
4699
|
+
);
|
|
4700
|
+
}
|
|
4701
|
+
async logs(id) {
|
|
4702
|
+
return parseNdjsonStream(await this.client.stream(`/deployments/${id}/logs/stream`));
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
var DeploymentInstance = class {
|
|
4706
|
+
constructor(data, client) {
|
|
4707
|
+
this.data = data;
|
|
4708
|
+
this.client = client;
|
|
4709
|
+
}
|
|
4710
|
+
refresh() {
|
|
4711
|
+
return this.client.deployments.get(this.data.id);
|
|
4712
|
+
}
|
|
4713
|
+
redeploy(input = {}) {
|
|
4714
|
+
return this.client.deployments.redeploy(this.data.id, input);
|
|
4715
|
+
}
|
|
4716
|
+
delete() {
|
|
4717
|
+
return this.client.deployments.delete(this.data.id);
|
|
4718
|
+
}
|
|
4719
|
+
async wait(options = {}) {
|
|
4720
|
+
const intervalMs = options.intervalMs ?? 1e3;
|
|
4721
|
+
const timeoutMs = options.timeoutMs ?? 3e5;
|
|
4722
|
+
const startedAt = Date.now();
|
|
4723
|
+
let current = this;
|
|
4724
|
+
while (!deploymentStatusIsTerminal(current.data.status)) {
|
|
4725
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
4726
|
+
throw new Error(`Timed out waiting for deployment ${this.data.id}`);
|
|
4727
|
+
}
|
|
4728
|
+
await delay(intervalMs);
|
|
4729
|
+
current = await current.refresh();
|
|
4730
|
+
}
|
|
4731
|
+
return current;
|
|
4732
|
+
}
|
|
4733
|
+
events() {
|
|
4734
|
+
return this.client.deployments.events(this.data.id);
|
|
4735
|
+
}
|
|
4736
|
+
buildLogs(buildId = this.data.latest_build?.id ?? "") {
|
|
4737
|
+
if (buildId === "") {
|
|
4738
|
+
return Promise.reject(new Error("Deployment has no latest build id"));
|
|
4739
|
+
}
|
|
4740
|
+
return this.client.deployments.buildLogs(this.data.id, buildId);
|
|
4741
|
+
}
|
|
4742
|
+
logs() {
|
|
4743
|
+
return this.client.deployments.logs(this.data.id);
|
|
4744
|
+
}
|
|
4745
|
+
setProtection(input) {
|
|
4746
|
+
return this.client.deployments.setProtection(this.data.id, input);
|
|
4747
|
+
}
|
|
4748
|
+
protection() {
|
|
4749
|
+
return this.client.deployments.protection(this.data.id);
|
|
4750
|
+
}
|
|
4751
|
+
createProtectionSession() {
|
|
4752
|
+
return this.client.deployments.createProtectionSession(this.data.id);
|
|
4753
|
+
}
|
|
4754
|
+
disableProtection() {
|
|
4755
|
+
return this.client.deployments.disableProtection(this.data.id);
|
|
4756
|
+
}
|
|
4757
|
+
setFeedback(input) {
|
|
4758
|
+
return this.client.deployments.setFeedback(this.data.id, input);
|
|
4759
|
+
}
|
|
4760
|
+
domains() {
|
|
4761
|
+
return this.client.deployments.listDomains(this.data.id);
|
|
4762
|
+
}
|
|
4763
|
+
addDomain(input) {
|
|
4764
|
+
return this.client.deployments.createDomain(this.data.id, input);
|
|
4765
|
+
}
|
|
4766
|
+
refreshDomain(domainId) {
|
|
4767
|
+
return this.client.deployments.refreshDomain(this.data.id, domainId);
|
|
4768
|
+
}
|
|
4769
|
+
deleteDomain(domainId) {
|
|
4770
|
+
return this.client.deployments.deleteDomain(this.data.id, domainId);
|
|
4771
|
+
}
|
|
4772
|
+
};
|
|
4773
|
+
function deploymentStatusIsTerminal(status) {
|
|
4774
|
+
return ["healthy", "failed", "stopped", "deleted", "delete_failed"].includes(status);
|
|
4775
|
+
}
|
|
4776
|
+
function delay(ms) {
|
|
4777
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4778
|
+
}
|
|
4779
|
+
function unwrapDeploymentDomainCollection(input) {
|
|
4780
|
+
if (Array.isArray(input)) {
|
|
4781
|
+
return input;
|
|
4782
|
+
}
|
|
4783
|
+
return Array.isArray(input.data) ? input.data : [];
|
|
4784
|
+
}
|
|
4785
|
+
function parseNdjsonStream(input) {
|
|
4786
|
+
const decoder = new TextDecoder();
|
|
4787
|
+
let buffer = "";
|
|
4788
|
+
return input.pipeThrough(
|
|
4789
|
+
new TransformStream({
|
|
4790
|
+
transform(chunk, controller) {
|
|
4791
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
4792
|
+
const lines = buffer.split("\n");
|
|
4793
|
+
buffer = lines.pop() ?? "";
|
|
4794
|
+
for (const line of lines) {
|
|
4795
|
+
const trimmed = line.trim();
|
|
4796
|
+
if (trimmed !== "") {
|
|
4797
|
+
controller.enqueue(JSON.parse(trimmed));
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
},
|
|
4801
|
+
flush(controller) {
|
|
4802
|
+
buffer += decoder.decode();
|
|
4803
|
+
const trimmed = buffer.trim();
|
|
4804
|
+
if (trimmed !== "") {
|
|
4805
|
+
controller.enqueue(JSON.parse(trimmed));
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
})
|
|
4809
|
+
);
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4591
4812
|
// src/index.ts
|
|
4592
4813
|
function normalizeNotebookSecretInputs(input) {
|
|
4593
4814
|
if (Array.isArray(input)) {
|
|
@@ -4608,18 +4829,42 @@ var NotebookInitError = class extends Error {
|
|
|
4608
4829
|
};
|
|
4609
4830
|
var ApiError = class extends Error {
|
|
4610
4831
|
constructor(response, body) {
|
|
4611
|
-
|
|
4832
|
+
const data = parseApiErrorBody(body);
|
|
4833
|
+
const apiMessage = apiErrorMessage(data, body);
|
|
4834
|
+
super(`PHPSandbox API Error: ${response.status} ${response.statusText}${apiMessage === "" ? "" : ` - ${apiMessage}`}`);
|
|
4612
4835
|
this.response = response;
|
|
4613
4836
|
this.body = body;
|
|
4614
4837
|
this.status = response.status;
|
|
4838
|
+
this.data = data;
|
|
4839
|
+
this.apiMessage = apiMessage === "" ? void 0 : apiMessage;
|
|
4615
4840
|
}
|
|
4616
4841
|
};
|
|
4842
|
+
function parseApiErrorBody(body) {
|
|
4843
|
+
try {
|
|
4844
|
+
return JSON.parse(body);
|
|
4845
|
+
} catch {
|
|
4846
|
+
return null;
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
function apiErrorMessage(data, fallback) {
|
|
4850
|
+
if (data !== null && typeof data === "object") {
|
|
4851
|
+
const record = data;
|
|
4852
|
+
if (typeof record.message === "string" && record.message.trim() !== "") {
|
|
4853
|
+
return record.message.trim();
|
|
4854
|
+
}
|
|
4855
|
+
if (record.error !== void 0) {
|
|
4856
|
+
return typeof record.error === "string" ? record.error.trim() : JSON.stringify(record.error);
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
return fallback.trim();
|
|
4860
|
+
}
|
|
4617
4861
|
var NotebookApi = class {
|
|
4618
4862
|
constructor(client) {
|
|
4619
4863
|
this.client = client;
|
|
4620
4864
|
this.secrets = new NotebookSecretApi(client);
|
|
4621
4865
|
this.preview = new NotebookPreviewApi(client);
|
|
4622
4866
|
this.mail = new NotebookMailApi(client);
|
|
4867
|
+
this.deployments = new NotebookDeploymentApi(client);
|
|
4623
4868
|
}
|
|
4624
4869
|
async create(template, input = {}, init = true) {
|
|
4625
4870
|
const response = await this.client.post("/notebook", { template, ...input });
|
|
@@ -4671,6 +4916,7 @@ function normalizeApiBaseUrl(url) {
|
|
|
4671
4916
|
var Client = class {
|
|
4672
4917
|
constructor(token, url = "https://api.phpsandbox.io/v1", options = {}) {
|
|
4673
4918
|
this.fetch = globalThis.fetch;
|
|
4919
|
+
this.deployments = new DeploymentApi(this);
|
|
4674
4920
|
this.notebook = new NotebookApi(this);
|
|
4675
4921
|
this.options = Object.assign({ startClosed: true }, options);
|
|
4676
4922
|
this.baseUrl = normalizeApiBaseUrl(url);
|
|
@@ -4695,6 +4941,21 @@ var Client = class {
|
|
|
4695
4941
|
put(path, body) {
|
|
4696
4942
|
return this.makeRequest("PUT", path, { body: body === void 0 ? void 0 : JSON.stringify(body) });
|
|
4697
4943
|
}
|
|
4944
|
+
async stream(path) {
|
|
4945
|
+
const response = await this.fetch(
|
|
4946
|
+
new Request(new URL(path.replace(/^\//, ""), this.baseUrl), {
|
|
4947
|
+
method: "GET",
|
|
4948
|
+
headers: this.headers
|
|
4949
|
+
})
|
|
4950
|
+
);
|
|
4951
|
+
if (!response.ok) {
|
|
4952
|
+
throw new ApiError(response, await response.text());
|
|
4953
|
+
}
|
|
4954
|
+
if (!response.body) {
|
|
4955
|
+
throw new Error("PHPSandbox API Error: response body is not readable");
|
|
4956
|
+
}
|
|
4957
|
+
return response.body;
|
|
4958
|
+
}
|
|
4698
4959
|
async makeRequest(method, path, init) {
|
|
4699
4960
|
const response = await this.fetch(
|
|
4700
4961
|
new Request(new URL(path.replace(/^\//, ""), this.baseUrl), {
|
|
@@ -4841,6 +5102,9 @@ var NotebookInstance = class {
|
|
|
4841
5102
|
fork(input = {}) {
|
|
4842
5103
|
return this.client.notebook.fork(this.data.id, input);
|
|
4843
5104
|
}
|
|
5105
|
+
deploy(input = {}) {
|
|
5106
|
+
return this.client.notebook.deployments.create(this.data.id, input);
|
|
5107
|
+
}
|
|
4844
5108
|
gitCredentials() {
|
|
4845
5109
|
return this.client.notebook.gitCredentials(this.data.id);
|
|
4846
5110
|
}
|
|
@@ -5073,6 +5337,8 @@ export {
|
|
|
5073
5337
|
BeaconTimeoutError,
|
|
5074
5338
|
Client,
|
|
5075
5339
|
CommandError,
|
|
5340
|
+
DeploymentApi,
|
|
5341
|
+
DeploymentInstance,
|
|
5076
5342
|
ErrorEvent,
|
|
5077
5343
|
FileChangeFilter,
|
|
5078
5344
|
FileChangeType,
|
|
@@ -5083,6 +5349,7 @@ export {
|
|
|
5083
5349
|
LspConnection,
|
|
5084
5350
|
Navigator,
|
|
5085
5351
|
NotebookApi,
|
|
5352
|
+
NotebookDeploymentApi,
|
|
5086
5353
|
NotebookInitError,
|
|
5087
5354
|
NotebookInstance,
|
|
5088
5355
|
NotebookMail,
|