@netlify/spark-ui 1.30.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.
Files changed (51) hide show
  1. package/README.md +4 -3
  2. package/dist/chunks/browser.Ca2rTNTu.js +769 -0
  3. package/dist/components/articleCopyActions.d.ts +9 -0
  4. package/dist/components/articleCopyActions.test.d.ts +1 -0
  5. package/dist/components/index.d.ts +2 -2
  6. package/dist/components/preact/DropZone/DropZone.d.ts +76 -14
  7. package/dist/components/preact/DropZone/DropZone.js +111 -84
  8. package/dist/components/preact/DropZone/drop-core/authedDropClient.d.ts +80 -0
  9. package/dist/components/preact/DropZone/drop-core/authedDropClient.js +99 -0
  10. package/dist/components/preact/DropZone/drop-core/buildClient.d.ts +98 -0
  11. package/dist/components/preact/DropZone/drop-core/buildClient.js +92 -0
  12. package/dist/components/preact/DropZone/drop-core/client.d.ts +4 -0
  13. package/dist/components/preact/DropZone/drop-core/client.js +2 -1
  14. package/dist/components/preact/DropZone/drop-core/deploy.d.ts +31 -0
  15. package/dist/components/preact/DropZone/drop-core/deploy.js +36 -18
  16. package/dist/components/preact/DropZone/drop-core/detectBuild.d.ts +26 -0
  17. package/dist/components/preact/DropZone/drop-core/detectBuild.js +80 -53
  18. package/dist/components/preact/DropZone/drop-core/errors.d.ts +38 -0
  19. package/dist/components/preact/DropZone/drop-core/errors.js +50 -5
  20. package/dist/components/preact/DropZone/drop-core/index.d.ts +3 -0
  21. package/dist/components/preact/DropZone/drop-core/index.js +33 -18
  22. package/dist/components/preact/DropZone/drop-core/readFiles.js +1 -1
  23. package/dist/components/preact/DropZone/drop-core/types.d.ts +6 -1
  24. package/dist/components/preact/DropZone/drop-core/zip.d.ts +46 -0
  25. package/dist/components/preact/DropZone/drop-core/zip.js +43 -0
  26. package/dist/components/preact/DropZone/index.d.ts +3 -2
  27. package/dist/components/preact/DropZone/index.js +27 -11
  28. package/dist/components/preact/DropZone/useDropDeploy.d.ts +35 -4
  29. package/dist/components/preact/DropZone/useDropDeploy.js +139 -70
  30. package/dist/components/preact/index.d.ts +2 -1
  31. package/dist/components/preact/index.js +17 -12
  32. package/package.json +5 -2
  33. package/packages/components/ArticleCopyActions.astro +122 -0
  34. package/packages/components/articleCopyActions.test.ts +143 -0
  35. package/packages/components/articleCopyActions.ts +41 -0
  36. package/packages/components/index.ts +15 -0
  37. package/packages/components/preact/DropZone/DropZone.tsx +123 -20
  38. package/packages/components/preact/DropZone/drop-core/authedDropClient.ts +194 -0
  39. package/packages/components/preact/DropZone/drop-core/buildClient.ts +190 -0
  40. package/packages/components/preact/DropZone/drop-core/client.ts +1 -1
  41. package/packages/components/preact/DropZone/drop-core/deploy.ts +65 -0
  42. package/packages/components/preact/DropZone/drop-core/detectBuild.ts +125 -41
  43. package/packages/components/preact/DropZone/drop-core/errors.ts +84 -1
  44. package/packages/components/preact/DropZone/drop-core/index.ts +3 -0
  45. package/packages/components/preact/DropZone/drop-core/readFiles.ts +1 -1
  46. package/packages/components/preact/DropZone/drop-core/types.ts +12 -1
  47. package/packages/components/preact/DropZone/drop-core/zip.ts +118 -0
  48. package/packages/components/preact/DropZone/index.tsx +23 -0
  49. package/packages/components/preact/DropZone/useDropDeploy.ts +195 -30
  50. package/packages/components/preact/index.ts +2 -1
  51. 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>;
@@ -40,5 +40,6 @@ class p {
40
40
  }
41
41
  }
42
42
  export {
43
- p as AnonymousDropClient
43
+ p as AnonymousDropClient,
44
+ r as apiError
44
45
  };
@@ -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
- const y = 5;
3
- async function d(e, l, u, t, i, a) {
4
- const n = u.filter((h) => t.has(h.sha));
5
- let p = 0, c = 0;
6
- const o = async () => {
7
- for (; p < n.length; ) {
8
- const h = n[p++];
9
- await e.uploadFile(l, h.path, h.content, i), a == null || a(++c);
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(y, n.length) }, o));
13
+ await Promise.all(Array.from({ length: Math.min(f, u.length) }, c));
13
14
  }
14
- async function f(e, l, u = {}) {
15
+ async function s(i, l, n = {}) {
15
16
  if (!l.length) throw new Error("No files to deploy");
16
- const { onProgress: t } = u;
17
+ const { onProgress: t } = n;
17
18
  t == null || t({ phase: "creating" });
18
- const i = await e.getToken(), a = await e.createDeploy(w(l), i), n = a.required.length;
19
- return t == null || t({ phase: "uploading", uploaded: 0, total: n }), await d(
20
- e,
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
- i,
25
- (p) => t == null ? void 0 : t({ phase: "uploading", uploaded: p, total: n })
26
- ), t == null || t({ phase: "processing" }), await e.waitUntilReady(a, i), t == null || t({ phase: "ready" }), { deploy: a, token: i, url: `https://${a.subdomain}.netlify.app` };
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
- f as deployFiles
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 u = /* @__PURE__ */ new Set([
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
- ]), c = /^\s*\[build(\.[\w-]+)?\]/m, d = ["/netlify/functions/", "/netlify/edge-functions/"], l = new TextDecoder();
23
- function i(e, n) {
24
- return e.find((t) => t.path === n);
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(e) {
27
- return l.decode(e.content);
26
+ function o(n) {
27
+ return p.decode(n.content);
28
28
  }
29
- function a(e) {
30
- const n = e.scripts;
31
- if (!n || typeof n != "object") return !1;
32
- const t = n.build;
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 f(e) {
36
- for (const n of ["dependencies", "devDependencies"]) {
37
- const t = e[n];
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 (u.has(r)) return !0;
40
+ if (l.has(r)) return r;
41
41
  }
42
42
  }
43
- return !1;
43
+ return null;
44
44
  }
45
- function p(e) {
46
- const n = i(e, "/netlify.toml");
47
- if (n && c.test(o(n)))
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 = i(e, "/package.json");
52
+ const t = d(n);
50
53
  if (t) {
51
- let r = null;
52
- try {
53
- r = JSON.parse(o(t));
54
- } catch {
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 e.some((r) => d.some((s) => r.path.startsWith(s))) ? { buildRequired: !0, reason: "functions-directory" } : { buildRequired: !1, reason: null };
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
- p as detectBuild
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
- class n extends Error {
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
- function a(e) {
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 n)
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
- n as UnsupportedDropError,
36
- a as humanizeDropError
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
  };
@@ -4,5 +4,8 @@ export * from './readFiles';
4
4
  export * from './fileTypes';
5
5
  export * from './detectBuild';
6
6
  export * from './client';
7
+ export * from './authedDropClient';
8
+ export * from './buildClient';
9
+ export * from './zip';
7
10
  export * from './deploy';
8
11
  export * from './errors';