@netlify/spark-ui 1.29.0 → 1.31.0-alpha.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 +4 -3
- package/dist/chunks/browser.Ca2rTNTu.js +769 -0
- package/dist/components/articleCopyActions.d.ts +9 -0
- package/dist/components/articleCopyActions.test.d.ts +1 -0
- package/dist/components/index.d.ts +2 -2
- package/dist/components/preact/DropZone/DropZone.d.ts +84 -15
- package/dist/components/preact/DropZone/DropZone.js +117 -85
- package/dist/components/preact/DropZone/drop-core/authedDropClient.d.ts +80 -0
- package/dist/components/preact/DropZone/drop-core/authedDropClient.js +99 -0
- package/dist/components/preact/DropZone/drop-core/buildClient.d.ts +98 -0
- package/dist/components/preact/DropZone/drop-core/buildClient.js +92 -0
- package/dist/components/preact/DropZone/drop-core/client.d.ts +4 -0
- package/dist/components/preact/DropZone/drop-core/client.js +2 -1
- package/dist/components/preact/DropZone/drop-core/deploy.d.ts +31 -0
- package/dist/components/preact/DropZone/drop-core/deploy.js +36 -18
- package/dist/components/preact/DropZone/drop-core/detectBuild.d.ts +26 -0
- package/dist/components/preact/DropZone/drop-core/detectBuild.js +80 -53
- package/dist/components/preact/DropZone/drop-core/errors.d.ts +38 -0
- package/dist/components/preact/DropZone/drop-core/errors.js +50 -5
- package/dist/components/preact/DropZone/drop-core/fileTypes.d.ts +17 -0
- package/dist/components/preact/DropZone/drop-core/fileTypes.js +11 -0
- package/dist/components/preact/DropZone/drop-core/index.d.ts +4 -0
- package/dist/components/preact/DropZone/drop-core/index.js +32 -15
- package/dist/components/preact/DropZone/drop-core/readFiles.js +1 -1
- package/dist/components/preact/DropZone/drop-core/types.d.ts +6 -1
- package/dist/components/preact/DropZone/drop-core/zip.d.ts +46 -0
- package/dist/components/preact/DropZone/drop-core/zip.js +43 -0
- package/dist/components/preact/DropZone/index.d.ts +3 -2
- package/dist/components/preact/DropZone/index.js +27 -9
- package/dist/components/preact/DropZone/useDropDeploy.d.ts +36 -5
- package/dist/components/preact/DropZone/useDropDeploy.js +140 -65
- package/dist/components/preact/index.d.ts +2 -1
- package/dist/components/preact/index.js +17 -12
- package/package.json +5 -2
- package/packages/components/ArticleCopyActions.astro +122 -0
- package/packages/components/articleCopyActions.test.ts +143 -0
- package/packages/components/articleCopyActions.ts +41 -0
- package/packages/components/index.ts +15 -0
- package/packages/components/preact/DropZone/DropZone.tsx +145 -24
- package/packages/components/preact/DropZone/drop-core/authedDropClient.ts +194 -0
- package/packages/components/preact/DropZone/drop-core/buildClient.ts +190 -0
- package/packages/components/preact/DropZone/drop-core/client.ts +1 -1
- package/packages/components/preact/DropZone/drop-core/deploy.ts +65 -0
- package/packages/components/preact/DropZone/drop-core/detectBuild.ts +125 -41
- package/packages/components/preact/DropZone/drop-core/errors.ts +84 -1
- package/packages/components/preact/DropZone/drop-core/fileTypes.ts +34 -0
- package/packages/components/preact/DropZone/drop-core/index.ts +4 -0
- package/packages/components/preact/DropZone/drop-core/readFiles.ts +1 -1
- package/packages/components/preact/DropZone/drop-core/types.ts +12 -1
- package/packages/components/preact/DropZone/drop-core/zip.ts +118 -0
- package/packages/components/preact/DropZone/index.tsx +24 -0
- package/packages/components/preact/DropZone/useDropDeploy.ts +219 -34
- package/packages/components/preact/index.ts +2 -1
- package/dist/chunks/browser.D58rdxmc.js +0 -444
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** The subset of a Netlify Site the drop flow needs to redirect and report. */
|
|
2
|
+
export interface BuildSite {
|
|
3
|
+
/** site id (UUID) */
|
|
4
|
+
id: string;
|
|
5
|
+
/** the *.netlify.app subdomain, also the app's URL segment */
|
|
6
|
+
name: string;
|
|
7
|
+
/** https://<name>.netlify.app */
|
|
8
|
+
ssl_url?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
/** The subset of a Netlify Build returned by `POST /sites/{id}/builds`. */
|
|
12
|
+
export interface BuildResponse {
|
|
13
|
+
/** build id */
|
|
14
|
+
id: string;
|
|
15
|
+
/** the deploy the build produces — present as soon as the build is enqueued */
|
|
16
|
+
deploy_id?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BuildClient {
|
|
19
|
+
createSite(): Promise<BuildSite>;
|
|
20
|
+
createBuildFromZip(siteId: string, zip: File): Promise<BuildResponse>;
|
|
21
|
+
waitUntilBuildReady(build: BuildResponse): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export interface AuthenticatedBuildClientConfig {
|
|
24
|
+
/**
|
|
25
|
+
* Base for JSON API calls, routed through the consumer's access-control
|
|
26
|
+
* rewrite so the session cookie authenticates them. On netlify.com that
|
|
27
|
+
* rewrite is `/access-control/*` → the app's access-control function, which
|
|
28
|
+
* makes `/access-control/bb-api/api/v1` the API root (the default here).
|
|
29
|
+
*/
|
|
30
|
+
proxyBase?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Direct API base for the zip upload. The proxy above runs in a Lambda with a
|
|
33
|
+
* ~6MB request body limit, so the multipart POST has to go straight to
|
|
34
|
+
* `api.netlify.com` (whose `/api/*` CORS policy allows any origin).
|
|
35
|
+
*/
|
|
36
|
+
apiBase?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Mint a short-lived bearer token for that direct upload. On netlify.com this
|
|
39
|
+
* is `GET /access-control/generate-access-control-token`, whose
|
|
40
|
+
* `accessControlToken` the API decrypts back into the user's access token.
|
|
41
|
+
* Resolving `null` means "no session" and surfaces as `NotAuthenticatedError`.
|
|
42
|
+
*/
|
|
43
|
+
getUploadToken: () => Promise<string | null>;
|
|
44
|
+
/** Create the site in this account. Omit to use the user's default account. */
|
|
45
|
+
accountSlug?: string;
|
|
46
|
+
/** Title recorded against the build. */
|
|
47
|
+
title?: string;
|
|
48
|
+
/** How often to re-read the deploy while waiting. Default 1s. */
|
|
49
|
+
pollIntervalMs?: number;
|
|
50
|
+
/** How long to wait before giving up on the build. Default 10 minutes. */
|
|
51
|
+
timeoutMs?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Authenticated drop client for projects that need a build. Unlike
|
|
55
|
+
* `AnonymousDropClient` — which creates an account-less static site and can only
|
|
56
|
+
* upload pre-built files — this creates a real site in the user's account and
|
|
57
|
+
* hands buildbot a source archive to build, mirroring what app.netlify.com does
|
|
58
|
+
* for a drag-and-drop build.
|
|
59
|
+
*
|
|
60
|
+
* Requests split across two hosts by necessity: JSON calls go through the
|
|
61
|
+
* consumer's access-control proxy (cookie session, no token handling in the
|
|
62
|
+
* browser), while the zip upload goes direct to `api.netlify.com` with a
|
|
63
|
+
* short-lived bearer token because the proxy can't carry a body that large.
|
|
64
|
+
*/
|
|
65
|
+
export declare class AuthenticatedBuildClient implements BuildClient {
|
|
66
|
+
private proxyBase;
|
|
67
|
+
private apiBase;
|
|
68
|
+
private getUploadToken;
|
|
69
|
+
private accountSlug?;
|
|
70
|
+
private title;
|
|
71
|
+
private pollIntervalMs;
|
|
72
|
+
private timeoutMs;
|
|
73
|
+
constructor({ proxyBase, apiBase, getUploadToken, accountSlug, title, pollIntervalMs, timeoutMs, }: AuthenticatedBuildClientConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Create the site the build deploys into. Goes through the proxy with
|
|
76
|
+
* `credentials: 'include'` so the app session authorizes it; without an
|
|
77
|
+
* account slug the API picks the user's default account.
|
|
78
|
+
*/
|
|
79
|
+
createSite(): Promise<BuildSite>;
|
|
80
|
+
/**
|
|
81
|
+
* Upload the source archive and enqueue a build. Direct to `api.netlify.com`
|
|
82
|
+
* (see the note on `apiBase`), authorized by a freshly minted bearer token.
|
|
83
|
+
* `Content-Type` is left unset on purpose so the browser adds the multipart
|
|
84
|
+
* boundary itself.
|
|
85
|
+
*/
|
|
86
|
+
createBuildFromZip(siteId: string, zip: File): Promise<BuildResponse>;
|
|
87
|
+
/**
|
|
88
|
+
* Poll the build's deploy through the proxy until it settles, mirroring
|
|
89
|
+
* `AnonymousDropClient.waitUntilReady` — resolve on `ready`, throw on
|
|
90
|
+
* `error`/`rejected`, throw on timeout. A build that hasn't been given a
|
|
91
|
+
* deploy id yet has nothing pollable, so it resolves immediately and the
|
|
92
|
+
* caller falls back to the site page.
|
|
93
|
+
*
|
|
94
|
+
* Optional in the drop flow: a build takes minutes, so the default hand-off
|
|
95
|
+
* redirects to the app's deploy page (live logs) instead of waiting here.
|
|
96
|
+
*/
|
|
97
|
+
waitUntilBuildReady(build: BuildResponse): Promise<void>;
|
|
98
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
var d = Object.defineProperty;
|
|
2
|
+
var p = (r, t, e) => t in r ? d(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
|
+
var i = (r, t, e) => p(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { NotAuthenticatedError as n, SiteCreateError as h, BuildCreateError as u, BuildFailedError as w, BuildTimeoutError as y } from "./errors.js";
|
|
5
|
+
const f = "/access-control/bb-api/api/v1", B = "https://api.netlify.com/api/v1", m = 1e3, S = 10 * 60 * 1e3, T = /* @__PURE__ */ new Set(["ready", "error", "rejected"]);
|
|
6
|
+
class _ {
|
|
7
|
+
constructor({
|
|
8
|
+
proxyBase: t = f,
|
|
9
|
+
apiBase: e = B,
|
|
10
|
+
getUploadToken: a,
|
|
11
|
+
accountSlug: o,
|
|
12
|
+
title: s = "Build from drop deployment",
|
|
13
|
+
pollIntervalMs: l = m,
|
|
14
|
+
timeoutMs: c = S
|
|
15
|
+
}) {
|
|
16
|
+
i(this, "proxyBase");
|
|
17
|
+
i(this, "apiBase");
|
|
18
|
+
i(this, "getUploadToken");
|
|
19
|
+
i(this, "accountSlug");
|
|
20
|
+
i(this, "title");
|
|
21
|
+
i(this, "pollIntervalMs");
|
|
22
|
+
i(this, "timeoutMs");
|
|
23
|
+
this.proxyBase = t, this.apiBase = e, this.getUploadToken = a, this.accountSlug = o, this.title = s, this.pollIntervalMs = l, this.timeoutMs = c;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create the site the build deploys into. Goes through the proxy with
|
|
27
|
+
* `credentials: 'include'` so the app session authorizes it; without an
|
|
28
|
+
* account slug the API picks the user's default account.
|
|
29
|
+
*/
|
|
30
|
+
async createSite() {
|
|
31
|
+
const t = this.accountSlug ? `/${this.accountSlug}/sites` : "/sites", e = await fetch(`${this.proxyBase}${t}`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
credentials: "include",
|
|
34
|
+
headers: { "Content-Type": "application/json" },
|
|
35
|
+
body: JSON.stringify({ created_via: "drop" })
|
|
36
|
+
});
|
|
37
|
+
if (e.status === 401 || e.status === 403) throw new n();
|
|
38
|
+
if (!e.ok) throw new h(e.status);
|
|
39
|
+
return e.json();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Upload the source archive and enqueue a build. Direct to `api.netlify.com`
|
|
43
|
+
* (see the note on `apiBase`), authorized by a freshly minted bearer token.
|
|
44
|
+
* `Content-Type` is left unset on purpose so the browser adds the multipart
|
|
45
|
+
* boundary itself.
|
|
46
|
+
*/
|
|
47
|
+
async createBuildFromZip(t, e) {
|
|
48
|
+
const a = await this.getUploadToken();
|
|
49
|
+
if (!a) throw new n();
|
|
50
|
+
const o = new FormData();
|
|
51
|
+
o.append("zip", e), o.append("title", this.title);
|
|
52
|
+
const s = await fetch(`${this.apiBase}/sites/${t}/builds`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { Authorization: `Bearer ${a}` },
|
|
55
|
+
body: o
|
|
56
|
+
});
|
|
57
|
+
if (s.status === 401 || s.status === 403) throw new n();
|
|
58
|
+
if (!s.ok) throw new u(s.status);
|
|
59
|
+
return s.json();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Poll the build's deploy through the proxy until it settles, mirroring
|
|
63
|
+
* `AnonymousDropClient.waitUntilReady` — resolve on `ready`, throw on
|
|
64
|
+
* `error`/`rejected`, throw on timeout. A build that hasn't been given a
|
|
65
|
+
* deploy id yet has nothing pollable, so it resolves immediately and the
|
|
66
|
+
* caller falls back to the site page.
|
|
67
|
+
*
|
|
68
|
+
* Optional in the drop flow: a build takes minutes, so the default hand-off
|
|
69
|
+
* redirects to the app's deploy page (live logs) instead of waiting here.
|
|
70
|
+
*/
|
|
71
|
+
async waitUntilBuildReady(t) {
|
|
72
|
+
if (!t.deploy_id) return;
|
|
73
|
+
const e = this.timeoutMs / this.pollIntervalMs;
|
|
74
|
+
for (let a = 0; a < e; a++) {
|
|
75
|
+
const o = await fetch(`${this.proxyBase}/deploys/${t.deploy_id}`, {
|
|
76
|
+
credentials: "include"
|
|
77
|
+
});
|
|
78
|
+
if (o.ok) {
|
|
79
|
+
const s = await o.json();
|
|
80
|
+
if (s.state && T.has(s.state)) {
|
|
81
|
+
if (s.state === "ready") return;
|
|
82
|
+
throw new w(s.error_message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await new Promise((s) => setTimeout(s, this.pollIntervalMs));
|
|
86
|
+
}
|
|
87
|
+
throw new y();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
_ as AuthenticatedBuildClient
|
|
92
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { DropResponse, Digest } from './types';
|
|
2
|
+
/** A normal Error with the response's HTTP status attached, so callers can branch on it directly. */
|
|
3
|
+
export declare function apiError(action: string, status: number): Error & {
|
|
4
|
+
status: number;
|
|
5
|
+
};
|
|
2
6
|
export interface DropClient {
|
|
3
7
|
getToken(): Promise<string>;
|
|
4
8
|
createDeploy(digest: Digest, token: string): Promise<DropResponse>;
|
|
@@ -1,6 +1,37 @@
|
|
|
1
|
+
import { BuildClient, BuildResponse, BuildSite } from './buildClient';
|
|
1
2
|
import { DropClient } from './client';
|
|
3
|
+
import { InferredBuildSettings } from './detectBuild';
|
|
2
4
|
import { DeployProgress, DeployResult, ProcessedFile } from './types';
|
|
3
5
|
export interface DeployOptions {
|
|
4
6
|
onProgress?: (e: DeployProgress) => void;
|
|
5
7
|
}
|
|
6
8
|
export declare function deployFiles(client: DropClient, files: ProcessedFile[], opts?: DeployOptions): Promise<DeployResult>;
|
|
9
|
+
export interface BuildDeployResult {
|
|
10
|
+
/** The site created for this build. */
|
|
11
|
+
site: BuildSite;
|
|
12
|
+
/** The enqueued build; `deploy_id` is what the app's deploy page keys off. */
|
|
13
|
+
build: BuildResponse;
|
|
14
|
+
/** Settings synthesised into the uploaded `netlify.toml`, or null if none were. */
|
|
15
|
+
buildSettings: InferredBuildSettings | null;
|
|
16
|
+
/** The site's live URL — only serves content once the build finishes. */
|
|
17
|
+
url: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BuildDeployOptions extends DeployOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Poll until the build finishes instead of returning as soon as it's enqueued.
|
|
22
|
+
* Off by default: a build takes minutes, so the useful hand-off is usually the
|
|
23
|
+
* app's deploy page with its live logs, not a spinner. Turn it on when the
|
|
24
|
+
* caller needs to know the outcome — only then can a `BuildFailedError` reach
|
|
25
|
+
* it with the build's own error message.
|
|
26
|
+
*/
|
|
27
|
+
waitForBuild?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The build counterpart to `deployFiles`: zip the drop, create a site in the
|
|
31
|
+
* user's account, and hand the archive to buildbot. Requires an authenticated
|
|
32
|
+
* client — builds have no anonymous equivalent.
|
|
33
|
+
*
|
|
34
|
+
* Site creation deliberately happens *after* zipping, so a zip that fails
|
|
35
|
+
* doesn't leave an empty site behind in the user's account.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deployBuild(client: BuildClient, files: ProcessedFile[], opts?: BuildDeployOptions): Promise<BuildDeployResult>;
|
|
@@ -1,30 +1,48 @@
|
|
|
1
1
|
import { getDigest as w } from "./digest.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { zipFiles as y } from "./zip.js";
|
|
3
|
+
const f = 5;
|
|
4
|
+
async function m(i, l, n, t, p, a) {
|
|
5
|
+
const u = n.filter((d) => t.has(d.sha));
|
|
6
|
+
let e = 0, h = 0;
|
|
7
|
+
const c = async () => {
|
|
8
|
+
for (; e < u.length; ) {
|
|
9
|
+
const d = u[e++];
|
|
10
|
+
await i.uploadFile(l, d.path, d.content, p), a == null || a(++h);
|
|
10
11
|
}
|
|
11
12
|
};
|
|
12
|
-
await Promise.all(Array.from({ length: Math.min(
|
|
13
|
+
await Promise.all(Array.from({ length: Math.min(f, u.length) }, c));
|
|
13
14
|
}
|
|
14
|
-
async function
|
|
15
|
+
async function s(i, l, n = {}) {
|
|
15
16
|
if (!l.length) throw new Error("No files to deploy");
|
|
16
|
-
const { onProgress: t } =
|
|
17
|
+
const { onProgress: t } = n;
|
|
17
18
|
t == null || t({ phase: "creating" });
|
|
18
|
-
const
|
|
19
|
-
return t == null || t({ phase: "uploading", uploaded: 0, total:
|
|
20
|
-
|
|
19
|
+
const p = await i.getToken(), a = await i.createDeploy(w(l), p), u = a.required.length;
|
|
20
|
+
return t == null || t({ phase: "uploading", uploaded: 0, total: u }), await m(
|
|
21
|
+
i,
|
|
21
22
|
a.deploy_id,
|
|
22
23
|
l,
|
|
23
24
|
new Set(a.required),
|
|
24
|
-
|
|
25
|
-
(
|
|
26
|
-
), t == null || t({ phase: "processing" }), await
|
|
25
|
+
p,
|
|
26
|
+
(e) => t == null ? void 0 : t({ phase: "uploading", uploaded: e, total: u })
|
|
27
|
+
), t == null || t({ phase: "processing" }), await i.waitUntilReady(a, p), t == null || t({ phase: "ready" }), { deploy: a, token: p, url: `https://${a.subdomain}.netlify.app` };
|
|
28
|
+
}
|
|
29
|
+
async function F(i, l, n = {}) {
|
|
30
|
+
if (!l.length) throw new Error("No files to deploy");
|
|
31
|
+
const { onProgress: t, waitForBuild: p = !1 } = n;
|
|
32
|
+
t == null || t({ phase: "zipping" });
|
|
33
|
+
const { file: a, buildSettings: u } = await y(l);
|
|
34
|
+
t == null || t({ phase: "creating" });
|
|
35
|
+
const e = await i.createSite();
|
|
36
|
+
t == null || t({ phase: "uploading" });
|
|
37
|
+
const h = await i.createBuildFromZip(e.id, a);
|
|
38
|
+
return t == null || t({ phase: "building" }), p && await i.waitUntilBuildReady(h), t == null || t({ phase: "ready" }), {
|
|
39
|
+
site: e,
|
|
40
|
+
build: h,
|
|
41
|
+
buildSettings: u,
|
|
42
|
+
url: e.ssl_url || e.url || `https://${e.name}.netlify.app`
|
|
43
|
+
};
|
|
27
44
|
}
|
|
28
45
|
export {
|
|
29
|
-
|
|
46
|
+
F as deployBuild,
|
|
47
|
+
s as deployFiles
|
|
30
48
|
};
|
|
@@ -21,3 +21,29 @@ export interface BuildDetection {
|
|
|
21
21
|
* no build config) returns `{ buildRequired: false }`.
|
|
22
22
|
*/
|
|
23
23
|
export declare function detectBuild(files: ProcessedFile[]): BuildDetection;
|
|
24
|
+
/** Build settings confident enough to write into a `netlify.toml` for buildbot. */
|
|
25
|
+
export interface InferredBuildSettings {
|
|
26
|
+
/** Build command, e.g. `"npm run build"`. */
|
|
27
|
+
command: string;
|
|
28
|
+
/** Publish directory relative to the deploy root, no leading slash, e.g. `"dist"`. */
|
|
29
|
+
publish: string;
|
|
30
|
+
/** The dependency the settings were inferred from, e.g. `"astro"`. */
|
|
31
|
+
framework: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Infer the build command and publish directory for a build-required drop, so
|
|
35
|
+
* `zipFiles` can write them into a `netlify.toml` that buildbot reads.
|
|
36
|
+
*
|
|
37
|
+
* Deliberately conservative: it returns settings **only** when both halves are
|
|
38
|
+
* known — a `build` script (which gives the command) and a recognised framework
|
|
39
|
+
* with a fixed default publish directory (which gives the output). Anything else
|
|
40
|
+
* returns `null`, leaving the zip without a synthesised `[build]` table so
|
|
41
|
+
* buildbot's own framework detection resolves the settings instead. That matters
|
|
42
|
+
* because a `[build]` table with a command but no `publish` makes buildbot
|
|
43
|
+
* publish the deploy root — shipping the project's *source* rather than its
|
|
44
|
+
* built output, which is worse than not guessing at all.
|
|
45
|
+
*
|
|
46
|
+
* Returns `null` too when the drop already declares a `[build]` table: the
|
|
47
|
+
* author's own config always wins.
|
|
48
|
+
*/
|
|
49
|
+
export declare function inferBuildSettings(files: ProcessedFile[]): InferredBuildSettings | null;
|
|
@@ -1,68 +1,95 @@
|
|
|
1
|
-
const
|
|
2
|
-
"astro",
|
|
3
|
-
"next",
|
|
4
|
-
"nuxt",
|
|
5
|
-
"gatsby",
|
|
6
|
-
"vite",
|
|
7
|
-
"react-scripts",
|
|
8
|
-
"parcel",
|
|
9
|
-
"expo",
|
|
10
|
-
"gridsome",
|
|
11
|
-
"vuepress",
|
|
12
|
-
"hexo",
|
|
13
|
-
"@remix-run/dev",
|
|
14
|
-
"@sveltejs/kit",
|
|
15
|
-
"@angular/cli",
|
|
16
|
-
"@vue/cli-service",
|
|
17
|
-
"@11ty/eleventy",
|
|
18
|
-
"@docusaurus/core",
|
|
19
|
-
"@builder.io/qwik",
|
|
20
|
-
"@analogjs/platform",
|
|
21
|
-
"@solidjs/start"
|
|
22
|
-
]),
|
|
23
|
-
function i(
|
|
24
|
-
return
|
|
1
|
+
const l = /* @__PURE__ */ new Map([
|
|
2
|
+
["astro", "dist"],
|
|
3
|
+
["next", ".next"],
|
|
4
|
+
["nuxt", null],
|
|
5
|
+
["gatsby", "public"],
|
|
6
|
+
["vite", "dist"],
|
|
7
|
+
["react-scripts", "build"],
|
|
8
|
+
["parcel", "dist"],
|
|
9
|
+
["expo", "dist"],
|
|
10
|
+
["gridsome", "dist"],
|
|
11
|
+
["vuepress", null],
|
|
12
|
+
["hexo", "public"],
|
|
13
|
+
["@remix-run/dev", null],
|
|
14
|
+
["@sveltejs/kit", null],
|
|
15
|
+
["@angular/cli", null],
|
|
16
|
+
["@vue/cli-service", "dist"],
|
|
17
|
+
["@11ty/eleventy", "_site"],
|
|
18
|
+
["@docusaurus/core", "build"],
|
|
19
|
+
["@builder.io/qwik", "dist"],
|
|
20
|
+
["@analogjs/platform", null],
|
|
21
|
+
["@solidjs/start", null]
|
|
22
|
+
]), a = /^\s*\[build(\.[\w-]+)?\]/m, f = ["/netlify/functions/", "/netlify/edge-functions/"], p = new TextDecoder();
|
|
23
|
+
function i(n, e) {
|
|
24
|
+
return n.find((t) => t.path === e);
|
|
25
25
|
}
|
|
26
|
-
function o(
|
|
27
|
-
return
|
|
26
|
+
function o(n) {
|
|
27
|
+
return p.decode(n.content);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
const t =
|
|
29
|
+
function s(n) {
|
|
30
|
+
const e = n.scripts;
|
|
31
|
+
if (!e || typeof e != "object") return !1;
|
|
32
|
+
const t = e.build;
|
|
33
33
|
return typeof t == "string" && t.trim().length > 0;
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
for (const
|
|
37
|
-
const t = e
|
|
35
|
+
function c(n) {
|
|
36
|
+
for (const e of ["dependencies", "devDependencies"]) {
|
|
37
|
+
const t = n[e];
|
|
38
38
|
if (!(!t || typeof t != "object")) {
|
|
39
39
|
for (const r of Object.keys(t))
|
|
40
|
-
if (
|
|
40
|
+
if (l.has(r)) return r;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
return
|
|
43
|
+
return null;
|
|
44
44
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
function b(n) {
|
|
46
|
+
return c(n) !== null;
|
|
47
|
+
}
|
|
48
|
+
function g(n) {
|
|
49
|
+
const e = i(n, "/netlify.toml");
|
|
50
|
+
if (e && a.test(o(e)))
|
|
48
51
|
return { buildRequired: !0, reason: "netlify-toml-build" };
|
|
49
|
-
const t =
|
|
52
|
+
const t = d(n);
|
|
50
53
|
if (t) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
r = null;
|
|
56
|
-
}
|
|
57
|
-
if (r) {
|
|
58
|
-
if (a(r))
|
|
59
|
-
return { buildRequired: !0, reason: "package-json-build-script" };
|
|
60
|
-
if (f(r))
|
|
61
|
-
return { buildRequired: !0, reason: "framework-dependency" };
|
|
62
|
-
}
|
|
54
|
+
if (s(t))
|
|
55
|
+
return { buildRequired: !0, reason: "package-json-build-script" };
|
|
56
|
+
if (b(t))
|
|
57
|
+
return { buildRequired: !0, reason: "framework-dependency" };
|
|
63
58
|
}
|
|
64
|
-
return
|
|
59
|
+
return n.some((r) => f.some((u) => r.path.startsWith(u))) ? { buildRequired: !0, reason: "functions-directory" } : { buildRequired: !1, reason: null };
|
|
60
|
+
}
|
|
61
|
+
function d(n) {
|
|
62
|
+
const e = i(n, "/package.json");
|
|
63
|
+
if (!e) return null;
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(o(e));
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const m = [
|
|
71
|
+
["/pnpm-lock.yaml", "pnpm"],
|
|
72
|
+
["/yarn.lock", "yarn"],
|
|
73
|
+
["/bun.lockb", "bun"],
|
|
74
|
+
["/bun.lock", "bun"],
|
|
75
|
+
["/package-lock.json", "npm"]
|
|
76
|
+
], y = /^\s*\[build\]/m;
|
|
77
|
+
function k(n) {
|
|
78
|
+
for (const [e, t] of m)
|
|
79
|
+
if (i(n, e)) return t;
|
|
80
|
+
return "npm";
|
|
81
|
+
}
|
|
82
|
+
function E(n) {
|
|
83
|
+
const e = i(n, "/netlify.toml");
|
|
84
|
+
if (e && y.test(o(e))) return null;
|
|
85
|
+
const t = d(n);
|
|
86
|
+
if (!t || !s(t)) return null;
|
|
87
|
+
const r = c(t);
|
|
88
|
+
if (!r) return null;
|
|
89
|
+
const u = l.get(r);
|
|
90
|
+
return u ? { command: `${k(n)} run build`, publish: u, framework: r } : null;
|
|
65
91
|
}
|
|
66
92
|
export {
|
|
67
|
-
|
|
93
|
+
g as detectBuild,
|
|
94
|
+
E as inferBuildSettings
|
|
68
95
|
};
|
|
@@ -8,6 +8,44 @@
|
|
|
8
8
|
export declare class UnsupportedDropError extends Error {
|
|
9
9
|
constructor();
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when an authenticated path (static or build) turns out to have no
|
|
13
|
+
* usable session — the short-lived upload token came back empty, or the
|
|
14
|
+
* session-cookie site create was refused, so nothing was created. For static
|
|
15
|
+
* drops the flow falls back to the anonymous drop + claim; builds have no
|
|
16
|
+
* anonymous equivalent, so the consumer's only recourse is to send the visitor
|
|
17
|
+
* through login/signup and have them drop again.
|
|
18
|
+
*/
|
|
19
|
+
export declare class NotAuthenticatedError extends Error {
|
|
20
|
+
constructor(message?: string);
|
|
21
|
+
}
|
|
22
|
+
/** `POST …/sites` failed, so there is nothing to build into. Carries the HTTP status. */
|
|
23
|
+
export declare class SiteCreateError extends Error {
|
|
24
|
+
status?: number;
|
|
25
|
+
constructor(status?: number);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The multipart `POST /sites/{id}/builds` upload itself failed — the build never
|
|
29
|
+
* started. Distinct from `BuildFailedError`, which is a build that ran and broke.
|
|
30
|
+
*/
|
|
31
|
+
export declare class BuildCreateError extends Error {
|
|
32
|
+
status?: number;
|
|
33
|
+
constructor(status?: number);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The build ran and ended in `error`/`rejected`. `reason` is the API's
|
|
37
|
+
* `error_message` when there is one — it's the only part of a build failure that
|
|
38
|
+
* says anything actionable (a failing build command, a missing dependency), so
|
|
39
|
+
* it is surfaced to the user rather than swallowed.
|
|
40
|
+
*/
|
|
41
|
+
export declare class BuildFailedError extends Error {
|
|
42
|
+
reason?: string | undefined;
|
|
43
|
+
constructor(reason?: string | undefined);
|
|
44
|
+
}
|
|
45
|
+
/** The build hadn't settled before the poller gave up. The build itself may still finish. */
|
|
46
|
+
export declare class BuildTimeoutError extends Error {
|
|
47
|
+
constructor();
|
|
48
|
+
}
|
|
11
49
|
/**
|
|
12
50
|
* Turn a raw deploy failure into copy a non-technical user can act on.
|
|
13
51
|
* The original message is still tracked via analytics — this is only for display.
|
|
@@ -1,12 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
var n = Object.defineProperty;
|
|
2
|
+
var i = (e, t, r) => t in e ? n(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
|
3
|
+
var a = (e, t, r) => i(e, typeof t != "symbol" ? t + "" : t, r);
|
|
4
|
+
class o extends Error {
|
|
2
5
|
constructor() {
|
|
3
6
|
super("unsupported single file"), this.name = "UnsupportedDropError";
|
|
4
7
|
}
|
|
5
8
|
}
|
|
6
|
-
|
|
9
|
+
class s extends Error {
|
|
10
|
+
constructor(t = "not authenticated") {
|
|
11
|
+
super(t), this.name = "NotAuthenticatedError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
class u extends Error {
|
|
15
|
+
constructor(r) {
|
|
16
|
+
super(`site create failed${r ? `: ${r}` : ""}`);
|
|
17
|
+
a(this, "status");
|
|
18
|
+
this.name = "SiteCreateError", this.status = r;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class f extends Error {
|
|
22
|
+
constructor(r) {
|
|
23
|
+
super(`build create failed${r ? `: ${r}` : ""}`);
|
|
24
|
+
a(this, "status");
|
|
25
|
+
this.name = "BuildCreateError", this.status = r;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
class l extends Error {
|
|
29
|
+
constructor(t) {
|
|
30
|
+
super(t ? `build failed: ${t}` : "build failed"), this.reason = t, this.name = "BuildFailedError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class d extends Error {
|
|
34
|
+
constructor() {
|
|
35
|
+
super("Build did not finish in time"), this.name = "BuildTimeoutError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function h(e) {
|
|
7
39
|
if (!(e instanceof Error)) return "Something went wrong. Please try again.";
|
|
8
|
-
if (e instanceof
|
|
40
|
+
if (e instanceof o)
|
|
9
41
|
return "To deploy, drop a folder or a .zip file — or a single HTML page.";
|
|
42
|
+
if (e instanceof s)
|
|
43
|
+
return "Please log in to Netlify to deploy a project that needs a build, then try again.";
|
|
44
|
+
if (e instanceof u)
|
|
45
|
+
return "We couldn't create a project for this build. Please try again.";
|
|
46
|
+
if (e instanceof l)
|
|
47
|
+
return e.reason ? `Your build failed: ${e.reason}` : "Your build failed. Check your build settings and try again.";
|
|
48
|
+
if (e instanceof d)
|
|
49
|
+
return "Your build is taking longer than expected. It may still finish — check your Netlify dashboard.";
|
|
10
50
|
if (e.message === "Deploy did not become ready in time")
|
|
11
51
|
return "Your site is taking longer than expected to go live. Please try again in a moment.";
|
|
12
52
|
if (e instanceof TypeError)
|
|
@@ -32,6 +72,11 @@ function a(e) {
|
|
|
32
72
|
}
|
|
33
73
|
}
|
|
34
74
|
export {
|
|
35
|
-
|
|
36
|
-
|
|
75
|
+
f as BuildCreateError,
|
|
76
|
+
l as BuildFailedError,
|
|
77
|
+
d as BuildTimeoutError,
|
|
78
|
+
s as NotAuthenticatedError,
|
|
79
|
+
u as SiteCreateError,
|
|
80
|
+
o as UnsupportedDropError,
|
|
81
|
+
h as humanizeDropError
|
|
37
82
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distinct MIME types across a drop or file-picker selection, sorted so the same
|
|
3
|
+
* selection always yields the same array.
|
|
4
|
+
*
|
|
5
|
+
* Read from the raw `File.type` at the drop boundary rather than from
|
|
6
|
+
* `ProcessedFile`s: the MIME type only exists on the original `File`, and reading
|
|
7
|
+
* can throw before any `ProcessedFile` does (an unsupported single file) — the
|
|
8
|
+
* very case the file type is most worth knowing about.
|
|
9
|
+
*
|
|
10
|
+
* Browsers leave `File.type` empty for anything they don't recognise — a dragged
|
|
11
|
+
* folder, an `.exe`, an extensionless file — so those collapse to
|
|
12
|
+
* `application/octet-stream` and the property never carries an empty string.
|
|
13
|
+
*
|
|
14
|
+
* Call this synchronously inside the drop handler: a `DataTransfer` detaches once
|
|
15
|
+
* the event turn ends.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getFileTypes(files: FileList | null | undefined): string[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const n = "application/octet-stream";
|
|
2
|
+
function e(t) {
|
|
3
|
+
if (!(t != null && t.length)) return [];
|
|
4
|
+
const r = /* @__PURE__ */ new Set();
|
|
5
|
+
for (const o of Array.from(t))
|
|
6
|
+
r.add(o.type || n);
|
|
7
|
+
return Array.from(r).sort().slice(0, 20);
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
e as getFileTypes
|
|
11
|
+
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export * from './types';
|
|
2
2
|
export * from './digest';
|
|
3
3
|
export * from './readFiles';
|
|
4
|
+
export * from './fileTypes';
|
|
4
5
|
export * from './detectBuild';
|
|
5
6
|
export * from './client';
|
|
7
|
+
export * from './authedDropClient';
|
|
8
|
+
export * from './buildClient';
|
|
9
|
+
export * from './zip';
|
|
6
10
|
export * from './deploy';
|
|
7
11
|
export * from './errors';
|