@netlify/spark-ui 1.31.0-alpha.4 → 1.31.0-alpha.6

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 (53) hide show
  1. package/README.md +3 -4
  2. package/dist/components/preact/DropZone/DropZone.d.ts +23 -98
  3. package/dist/components/preact/DropZone/DropZone.js +5 -5
  4. package/dist/components/preact/DropZone/index.js +29 -29
  5. package/dist/components/preact/DropZone/useDropDeploy.d.ts +0 -1
  6. package/dist/components/preact/DropZone/useDropDeploy.js +25 -27
  7. package/dist/components/preact/index.js +10 -10
  8. package/dist/drop-core/analytics.d.ts +4 -15
  9. package/dist/drop-core/authedApi.d.ts +9 -32
  10. package/dist/drop-core/authedApi.js +15 -20
  11. package/dist/drop-core/authedDropClient.d.ts +15 -64
  12. package/dist/drop-core/authedDropClient.js +27 -49
  13. package/dist/drop-core/buildClient.d.ts +19 -53
  14. package/dist/drop-core/buildClient.js +32 -44
  15. package/dist/drop-core/buildStash.d.ts +6 -20
  16. package/dist/drop-core/client.d.ts +4 -2
  17. package/dist/drop-core/client.js +19 -17
  18. package/dist/drop-core/constants.d.ts +9 -0
  19. package/dist/drop-core/constants.js +10 -0
  20. package/dist/drop-core/deploy.d.ts +7 -17
  21. package/dist/drop-core/deploy.js +56 -43
  22. package/dist/drop-core/detectBuild.d.ts +8 -26
  23. package/dist/drop-core/errors.d.ts +27 -17
  24. package/dist/drop-core/errors.js +70 -33
  25. package/dist/drop-core/fileTypes.d.ts +4 -14
  26. package/dist/drop-core/index.d.ts +22 -11
  27. package/dist/drop-core/index.js +45 -49
  28. package/dist/drop-core/readFiles.d.ts +5 -11
  29. package/dist/drop-core/types.d.ts +2 -4
  30. package/dist/drop-core/zip.d.ts +7 -30
  31. package/package.json +1 -1
  32. package/packages/components/preact/DropZone/DropZone.tsx +27 -122
  33. package/packages/components/preact/DropZone/useDropDeploy.ts +31 -73
  34. package/packages/drop-core/README.md +91 -0
  35. package/packages/drop-core/analytics.ts +4 -15
  36. package/packages/drop-core/authedApi.ts +9 -35
  37. package/packages/drop-core/authedDropClient.ts +23 -86
  38. package/packages/drop-core/buildClient.test.ts +19 -4
  39. package/packages/drop-core/buildClient.ts +23 -66
  40. package/packages/drop-core/buildStash.ts +9 -25
  41. package/packages/drop-core/client.ts +19 -11
  42. package/packages/drop-core/constants.ts +25 -0
  43. package/packages/drop-core/deploy.test.ts +42 -0
  44. package/packages/drop-core/deploy.ts +42 -22
  45. package/packages/drop-core/detectBuild.ts +15 -50
  46. package/packages/drop-core/errors.test.ts +34 -3
  47. package/packages/drop-core/errors.ts +63 -27
  48. package/packages/drop-core/fileTypes.ts +5 -19
  49. package/packages/drop-core/index.ts +41 -11
  50. package/packages/drop-core/readFiles.test.ts +0 -1
  51. package/packages/drop-core/readFiles.ts +5 -12
  52. package/packages/drop-core/types.ts +2 -4
  53. package/packages/drop-core/zip.ts +7 -30
@@ -5,10 +5,11 @@ import { DeployProgress, DeployResult, ProcessedFile } from './types';
5
5
  import { ZipResult } from './zip';
6
6
  export interface DeployOptions {
7
7
  onProgress?: (e: DeployProgress) => void;
8
+ /** Waits between retries of a failed file upload. Override for tests or a different curve. */
9
+ retryDelays?: readonly number[];
8
10
  }
9
11
  export declare function deployFiles(client: DropClient, files: ProcessedFile[], opts?: DeployOptions): Promise<DeployResult>;
10
12
  export interface BuildDeployResult {
11
- /** The site created for this build. */
12
13
  site: BuildSite;
13
14
  /** The enqueued build; `deploy_id` is what the app's deploy page keys off. */
14
15
  build: BuildResponse;
@@ -19,26 +20,15 @@ export interface BuildDeployResult {
19
20
  }
20
21
  export interface BuildDeployOptions extends DeployOptions {
21
22
  /**
22
- * Poll until the build finishes instead of returning as soon as it's enqueued.
23
- * Off by default: a build takes minutes, so the useful hand-off is usually the
24
- * app's deploy page with its live logs, not a spinner. Turn it on when the
25
- * caller needs to know the outcome — only then can a `BuildFailedError` reach
26
- * it with the build's own error message.
23
+ * Wait for the build instead of returning at enqueue. Off by default (builds
24
+ * take minutes); on is the only way a BuildFailedError reaches the caller.
27
25
  */
28
26
  waitForBuild?: boolean;
29
27
  }
30
28
  /**
31
- * The build counterpart to `deployFiles`: zip the drop, create a site in the
32
- * user's account, and hand the archive to buildbot. Requires an authenticated
33
- * client — builds have no anonymous equivalent.
34
- *
35
- * Site creation deliberately happens *after* zipping, so a zip that fails
36
- * doesn't leave an empty site behind in the user's account.
29
+ * Zip the drop, create a site, hand buildbot the archive. Zipping comes first
30
+ * on purpose: a failed zip must not leave an empty site behind.
37
31
  */
38
32
  export declare function deployBuild(client: BuildClient, files: ProcessedFile[], opts?: BuildDeployOptions): Promise<BuildDeployResult>;
39
- /**
40
- * Deploy an archive that was already zipped — the resume path for a drop
41
- * stashed across the signup round-trip (see `buildStash`), where `source.zip`
42
- * and its synthesised settings were produced before the visitor left.
43
- */
33
+ /** Deploy an already-zipped archive — the resume path for a stashed drop (see `buildStash`). */
44
34
  export declare function deployZippedBuild(client: BuildClient, { file: zip, buildSettings }: ZipResult, opts?: BuildDeployOptions): Promise<BuildDeployResult>;
@@ -1,53 +1,66 @@
1
- import { getDigest as w } from "./digest.js";
2
- import { zipFiles as y } from "./zip.js";
3
- const r = 5;
4
- async function f(i, n, p, a, t, e) {
5
- const l = p.filter((h) => a.has(h.sha));
6
- let u = 0, c = 0;
1
+ import { UPLOAD_RETRY_DELAYS_MS as w, MAX_CONCURRENT_UPLOADS as o } from "./constants.js";
2
+ import { getDigest as y } from "./digest.js";
3
+ import { zipFiles as f } from "./zip.js";
4
+ const s = /* @__PURE__ */ new Set([400, 422]);
5
+ async function m(e, l, n, t, a) {
6
+ for (let u = 0; ; u++)
7
+ try {
8
+ await e.uploadFile(l, n.path, n.content, t);
9
+ return;
10
+ } catch (i) {
11
+ const p = i.status;
12
+ if (p !== void 0 && s.has(p) || u >= a.length) throw i;
13
+ await new Promise((h) => setTimeout(h, a[u]));
14
+ }
15
+ }
16
+ async function R(e, l, n, t, a, u, i) {
17
+ const p = n.filter((c) => t.has(c.sha));
18
+ let h = 0, r = 0;
7
19
  const d = async () => {
8
- for (; u < l.length; ) {
9
- const h = l[u++];
10
- await i.uploadFile(n, h.path, h.content, t), e == null || e(++c);
20
+ for (; h < p.length; ) {
21
+ const c = p[h++];
22
+ await m(e, l, c, a, u), i == null || i(++r);
11
23
  }
12
24
  };
13
- await Promise.all(Array.from({ length: Math.min(r, l.length) }, d));
25
+ await Promise.all(Array.from({ length: Math.min(o, p.length) }, d));
14
26
  }
15
- async function B(i, n, p = {}) {
16
- if (!n.length) throw new Error("No files to deploy");
17
- const { onProgress: a } = p;
18
- a == null || a({ phase: "creating" });
19
- const t = await i.getToken(), e = await i.createDeploy(w(n), t), l = e.required.length;
20
- return a == null || a({ phase: "uploading", uploaded: 0, total: l }), await f(
21
- i,
22
- e.deploy_id,
23
- n,
24
- new Set(e.required),
25
- t,
26
- (u) => a == null ? void 0 : a({ phase: "uploading", uploaded: u, total: l })
27
- ), a == null || a({ phase: "processing" }), await i.waitUntilReady(e, t), a == null || a({ phase: "ready" }), { deploy: e, token: t, url: `https://${e.subdomain}.netlify.app` };
27
+ async function T(e, l, n = {}) {
28
+ if (!l.length) throw new Error("No files to deploy");
29
+ const { onProgress: t, retryDelays: a = w } = n;
30
+ t == null || t({ phase: "creating" });
31
+ const u = await e.getToken(), i = await e.createDeploy(y(l), u), p = i.required.length;
32
+ return t == null || t({ phase: "uploading", uploaded: 0, total: p }), await R(
33
+ e,
34
+ i.deploy_id,
35
+ l,
36
+ new Set(i.required),
37
+ u,
38
+ a,
39
+ (h) => t == null ? void 0 : t({ phase: "uploading", uploaded: h, total: p })
40
+ ), t == null || t({ phase: "processing" }), await e.waitUntilReady(i, u), t == null || t({ phase: "ready" }), { deploy: i, token: u, url: `https://${i.subdomain}.netlify.app` };
28
41
  }
29
- async function F(i, n, p = {}) {
30
- var t;
31
- if (!n.length) throw new Error("No files to deploy");
32
- (t = p.onProgress) == null || t.call(p, { phase: "zipping" });
33
- const a = await y(n);
34
- return o(i, a, p);
42
+ async function B(e, l, n = {}) {
43
+ var a;
44
+ if (!l.length) throw new Error("No files to deploy");
45
+ (a = n.onProgress) == null || a.call(n, { phase: "zipping" });
46
+ const t = await f(l);
47
+ return S(e, t, n);
35
48
  }
36
- async function o(i, { file: n, buildSettings: p }, a = {}) {
37
- const { onProgress: t, waitForBuild: e = !1 } = a;
38
- t == null || t({ phase: "creating" });
39
- const l = await i.createSite();
40
- t == null || t({ phase: "uploading" });
41
- const u = await i.createBuildFromZip(l.id, n);
42
- return t == null || t({ phase: "building" }), e && await i.waitUntilBuildReady(u), t == null || t({ phase: "ready" }), {
43
- site: l,
44
- build: u,
45
- buildSettings: p,
46
- url: l.ssl_url || l.url || `https://${l.name}.netlify.app`
49
+ async function S(e, { file: l, buildSettings: n }, t = {}) {
50
+ const { onProgress: a, waitForBuild: u = !1 } = t;
51
+ a == null || a({ phase: "creating" });
52
+ const i = await e.createSite();
53
+ a == null || a({ phase: "uploading" });
54
+ const p = await e.createBuildFromZip(i.id, l);
55
+ return a == null || a({ phase: "building" }), u && await e.waitUntilBuildReady(p), a == null || a({ phase: "ready" }), {
56
+ site: i,
57
+ build: p,
58
+ buildSettings: n,
59
+ url: i.ssl_url || i.url || `https://${i.name}.netlify.app`
47
60
  };
48
61
  }
49
62
  export {
50
- F as deployBuild,
51
- B as deployFiles,
52
- o as deployZippedBuild
63
+ B as deployBuild,
64
+ T as deployFiles,
65
+ S as deployZippedBuild
53
66
  };
@@ -2,23 +2,15 @@ import { ProcessedFile } from './types';
2
2
  /** Why a drop was judged to need a build — surfaced to analytics and `onBuildRequired`. */
3
3
  export type BuildReason = 'netlify-toml-build' | 'package-json-build-script' | 'framework-dependency' | 'functions-directory';
4
4
  export interface BuildDetection {
5
- /** True when the dropped project needs a build step and can't be served as static files. */
5
+ /** The drop can't be served as static files. */
6
6
  buildRequired: boolean;
7
7
  /** The signal that decided it (first match wins), or null for a plain static drop. */
8
8
  reason: BuildReason | null;
9
9
  }
10
10
  /**
11
- * Decide whether a dropped project needs a build. Runs on the already-read,
12
- * root-normalized `ProcessedFile[]` (a dropped `.zip` is expanded and the common
13
- * root folder stripped upstream in `readFiles`), so build config sits at the
14
- * deploy root, e.g. `/netlify.toml`, `/package.json`.
15
- *
16
- * The anonymous drop API only performs static deploys, so a build-required
17
- * project can't go through it — the consumer redirects such drops to the
18
- * authenticated Drop page instead. This heuristic is deliberately lightweight
19
- * (no framework-detection dependency): it reads the two config files and looks
20
- * for the zero-config functions directories. A plain static site (HTML/CSS/JS,
21
- * no build config) returns `{ buildRequired: false }`.
11
+ * Does this drop need a build? Deliberately lightweight (two config files +
12
+ * the functions dirs; no framework-detection dependency). Input is
13
+ * root-normalized by `readFiles`, so config sits at `/netlify.toml` etc.
22
14
  */
23
15
  export declare function detectBuild(files: ProcessedFile[]): BuildDetection;
24
16
  /** Build settings confident enough to write into a `netlify.toml` for buildbot. */
@@ -31,19 +23,9 @@ export interface InferredBuildSettings {
31
23
  framework: string;
32
24
  }
33
25
  /**
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.
26
+ * Build settings for the synthesised netlify.toml — only when BOTH halves are
27
+ * known (build script → command, known framework → publish). Guessing publish
28
+ * wrong ships source instead of output, so `null` beats a bad guess. An
29
+ * author-declared [build] table always wins (also `null`).
48
30
  */
49
31
  export declare function inferBuildSettings(files: ProcessedFile[]): InferredBuildSettings | null;
@@ -1,26 +1,27 @@
1
1
  /**
2
- * Thrown when the user drops or picks a single loose file that Drop can't turn
3
- * into a site on its own — anything that isn't a `.zip` (a site archive) or an
4
- * HTML page (served as index.html). A folder, multiple files, a zip, or a lone
5
- * HTML file are all fine; any other single file is rejected rather than
6
- * deployed as a one-asset site (matches react-ui).
2
+ * A single loose file that can't stand up a site — only a zip, folder,
3
+ * multiple files, or a lone HTML page may deploy (matches react-ui).
7
4
  */
8
5
  export declare class UnsupportedDropError extends Error {
6
+ readonly code = "unsupported-drop";
9
7
  constructor();
10
8
  }
11
9
  /**
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.
10
+ * The pre-mutation "no session" signal: nothing was created yet, so static
11
+ * drops may fall back to the anonymous flow and build drops stash + hand off.
18
12
  */
19
13
  export declare class NotAuthenticatedError extends Error {
14
+ readonly code = "not-authenticated";
20
15
  constructor(message?: string);
21
16
  }
17
+ /**
18
+ * Copy-proof check for the "no session" error — `instanceof` misses class
19
+ * copies from the package's other entrypoint. Fallback gates must use this.
20
+ */
21
+ export declare function isNotAuthenticatedError(err: unknown): err is NotAuthenticatedError;
22
22
  /** `POST …/sites` failed, so there is nothing to build into. Carries the HTTP status. */
23
23
  export declare class SiteCreateError extends Error {
24
+ readonly code = "site-create-failed";
24
25
  status?: number;
25
26
  constructor(status?: number);
26
27
  }
@@ -29,21 +30,30 @@ export declare class SiteCreateError extends Error {
29
30
  * started. Distinct from `BuildFailedError`, which is a build that ran and broke.
30
31
  */
31
32
  export declare class BuildCreateError extends Error {
33
+ readonly code = "build-create-failed";
32
34
  status?: number;
33
35
  constructor(status?: number);
34
36
  }
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
- */
37
+ /** The build ran and broke. `reason` carries the API's `error_message` — the only actionable part. */
41
38
  export declare class BuildFailedError extends Error {
42
39
  reason?: string | undefined;
40
+ readonly code = "build-failed";
43
41
  constructor(reason?: string | undefined);
44
42
  }
45
43
  /** The build hadn't settled before the poller gave up. The build itself may still finish. */
46
44
  export declare class BuildTimeoutError extends Error {
45
+ readonly code = "build-timeout";
46
+ constructor();
47
+ }
48
+ /** A static deploy ran and ended in `error`/`rejected`; `reason` carries the API's `error_message`. */
49
+ export declare class DeployFailedError extends Error {
50
+ reason?: string | undefined;
51
+ readonly code = "deploy-failed";
52
+ constructor(reason?: string | undefined);
53
+ }
54
+ /** The deploy hadn't gone ready before the poller gave up. It may still finish. */
55
+ export declare class DeployTimeoutError extends Error {
56
+ readonly code = "deploy-timeout";
47
57
  constructor();
48
58
  }
49
59
  /**
@@ -1,53 +1,87 @@
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 {
1
+ var a = Object.defineProperty;
2
+ var n = (e, r, t) => r in e ? a(e, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[r] = t;
3
+ var o = (e, r, t) => n(e, typeof r != "symbol" ? r + "" : r, t);
4
+ class l extends Error {
5
5
  constructor() {
6
- super("unsupported single file"), this.name = "UnsupportedDropError";
6
+ super("unsupported single file");
7
+ o(this, "code", "unsupported-drop");
8
+ this.name = "UnsupportedDropError";
7
9
  }
8
10
  }
9
11
  class s extends Error {
10
12
  constructor(t = "not authenticated") {
11
- super(t), this.name = "NotAuthenticatedError";
13
+ super(t);
14
+ o(this, "code", "not-authenticated");
15
+ this.name = "NotAuthenticatedError";
12
16
  }
13
17
  }
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;
18
+ function u(e) {
19
+ return e instanceof s ? !0 : e instanceof Error && e.code === "not-authenticated";
20
+ }
21
+ class c extends Error {
22
+ constructor(t) {
23
+ super(`site create failed${t ? `: ${t}` : ""}`);
24
+ o(this, "code", "site-create-failed");
25
+ o(this, "status");
26
+ this.name = "SiteCreateError", this.status = t;
27
+ }
28
+ }
29
+ class p extends Error {
30
+ constructor(t) {
31
+ super(`build create failed${t ? `: ${t}` : ""}`);
32
+ o(this, "code", "build-create-failed");
33
+ o(this, "status");
34
+ this.name = "BuildCreateError", this.status = t;
19
35
  }
20
36
  }
21
37
  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;
38
+ constructor(t) {
39
+ super(t ? `build failed: ${t}` : "build failed");
40
+ o(this, "code", "build-failed");
41
+ this.reason = t, this.name = "BuildFailedError";
26
42
  }
27
43
  }
28
- class l extends Error {
44
+ class y extends Error {
45
+ constructor() {
46
+ super("Build did not finish in time");
47
+ o(this, "code", "build-timeout");
48
+ this.name = "BuildTimeoutError";
49
+ }
50
+ }
51
+ class h extends Error {
29
52
  constructor(t) {
30
- super(t ? `build failed: ${t}` : "build failed"), this.reason = t, this.name = "BuildFailedError";
53
+ super(t ? `deploy failed: ${t}` : "deploy failed");
54
+ o(this, "code", "deploy-failed");
55
+ this.reason = t, this.name = "DeployFailedError";
31
56
  }
32
57
  }
33
- class d extends Error {
58
+ class g extends Error {
34
59
  constructor() {
35
- super("Build did not finish in time"), this.name = "BuildTimeoutError";
60
+ super("Deploy did not become ready in time");
61
+ o(this, "code", "deploy-timeout");
62
+ this.name = "DeployTimeoutError";
36
63
  }
37
64
  }
38
- function h(e) {
65
+ function m(e) {
39
66
  if (!(e instanceof Error)) return "Something went wrong. Please try again.";
40
- if (e instanceof o)
67
+ const r = e.code;
68
+ if (r === "unsupported-drop")
41
69
  return "To deploy, drop a folder or a .zip file — or a single HTML page.";
42
- if (e instanceof s)
70
+ if (r === "not-authenticated")
43
71
  return "Please log in to Netlify to deploy this project, then try again.";
44
- if (e instanceof u)
72
+ if (r === "site-create-failed")
45
73
  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)
74
+ if (r === "build-failed") {
75
+ const i = e.reason;
76
+ return i ? `Your build failed: ${i}` : "Your build failed. Check your build settings and try again.";
77
+ }
78
+ if (r === "deploy-failed") {
79
+ const i = e.reason;
80
+ return i ? `Your deploy failed: ${i}` : "Your deploy failed. Please try again.";
81
+ }
82
+ if (r === "build-timeout")
49
83
  return "Your build is taking longer than expected. It may still finish — check your Netlify dashboard.";
50
- if (e.message === "Deploy did not become ready in time")
84
+ if (r === "deploy-timeout")
51
85
  return "Your site is taking longer than expected to go live. Please try again in a moment.";
52
86
  if (e instanceof TypeError)
53
87
  return "Couldn't connect to Netlify. Check your internet connection and try again.";
@@ -72,11 +106,14 @@ function h(e) {
72
106
  }
73
107
  }
74
108
  export {
75
- f as BuildCreateError,
76
- l as BuildFailedError,
77
- d as BuildTimeoutError,
109
+ p as BuildCreateError,
110
+ f as BuildFailedError,
111
+ y as BuildTimeoutError,
112
+ h as DeployFailedError,
113
+ g as DeployTimeoutError,
78
114
  s as NotAuthenticatedError,
79
- u as SiteCreateError,
80
- o as UnsupportedDropError,
81
- h as humanizeDropError
115
+ c as SiteCreateError,
116
+ l as UnsupportedDropError,
117
+ m as humanizeDropError,
118
+ u as isNotAuthenticatedError
82
119
  };
@@ -1,17 +1,7 @@
1
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.
2
+ * Distinct, sorted MIME types of a selection. Read at the drop boundary — the
3
+ * type only exists on the original File, and reading can throw before any
4
+ * ProcessedFile exists. Call synchronously in the drop handler: a DataTransfer
5
+ * detaches after the event turn.
16
6
  */
17
7
  export declare function getFileTypes(files: FileList | null | undefined): string[];
@@ -1,14 +1,25 @@
1
+ /**
2
+ * The public surface of drop-core — nothing is public unless named here.
3
+ * `export *` is reserved for the three modules that are contracts in their
4
+ * entirety: types, errors, and the analytics event map.
5
+ */
1
6
  export * from './types';
2
- export * from './digest';
3
- export * from './readFiles';
4
- export * from './fileTypes';
5
- export * from './detectBuild';
6
- export * from './client';
7
- export * from './authedApi';
8
- export * from './authedDropClient';
9
- export * from './buildClient';
10
- export * from './zip';
11
- export * from './buildStash';
12
- export * from './deploy';
13
7
  export * from './errors';
14
8
  export * from './analytics';
9
+ export { getSingleNonIndexHtmlFileName, hasMultipleHtmlFilesWithoutIndex, readDataTransfer, readFileList, renameSingleNonIndexHtmlToIndex, } from './readFiles';
10
+ export { getFileTypes } from './fileTypes';
11
+ export { detectBuild, inferBuildSettings } from './detectBuild';
12
+ export type { BuildDetection, BuildReason, InferredBuildSettings } from './detectBuild';
13
+ export { zipFiles } from './zip';
14
+ export type { ZipOptions, ZipResult } from './zip';
15
+ export { AnonymousDropClient } from './client';
16
+ export type { DropClient } from './client';
17
+ export { AuthenticatedDropClient } from './authedDropClient';
18
+ export type { AuthenticatedDropClientConfig } from './authedDropClient';
19
+ export { AuthenticatedBuildClient } from './buildClient';
20
+ export type { AuthenticatedBuildClientConfig, BuildClient, BuildResponse } from './buildClient';
21
+ export { deployBuild, deployFiles, deployZippedBuild } from './deploy';
22
+ export type { BuildDeployOptions, BuildDeployResult, DeployOptions } from './deploy';
23
+ export { clearDropStash, hasDropStashMarker, loadDropStash, saveDropStash } from './buildStash';
24
+ export type { DropBuildStash } from './buildStash';
25
+ export { DEFAULT_API_BASE, DEFAULT_PROXY_BASE, UPLOAD_RETRY_DELAYS_MS } from './constants';
@@ -1,51 +1,47 @@
1
- import { getDigest as o } from "./digest.js";
2
- import { getSingleNonIndexHtmlFileName as i, hasMultipleHtmlFilesWithoutIndex as l, readDataTransfer as p, readFileList as a, renameSingleNonIndexHtmlToIndex as d } from "./readFiles.js";
3
- import { getFileTypes as m } from "./fileTypes.js";
4
- import { detectBuild as u, inferBuildSettings as s } from "./detectBuild.js";
5
- import { AnonymousDropClient as f, apiError as D } from "./client.js";
6
- import { DEFAULT_API_BASE as A, DEFAULT_POLL_INTERVAL_MS as T, DEFAULT_PROXY_BASE as h, DEFAULT_TIMEOUT_MS as F, createSiteInAccount as B, pollDeployUntilSettled as _ } from "./authedApi.js";
7
- import { AuthenticatedDropClient as g } from "./authedDropClient.js";
8
- import { AuthenticatedBuildClient as L } from "./buildClient.js";
9
- import { generateNetlifyToml as y, zipFiles as U } from "./zip.js";
10
- import { clearDropStash as M, hasDropStashMarker as O, loadDropStash as P, saveDropStash as H } from "./buildStash.js";
11
- import { deployBuild as z, deployFiles as V, deployZippedBuild as Z } from "./deploy.js";
12
- import { BuildCreateError as v, BuildFailedError as W, BuildTimeoutError as X, NotAuthenticatedError as Y, SiteCreateError as b, UnsupportedDropError as j, humanizeDropError as q } from "./errors.js";
13
- import { DROPZONE_EVENTS as G } from "./analytics.js";
1
+ import { BuildCreateError as o, BuildFailedError as t, BuildTimeoutError as i, DeployFailedError as l, DeployTimeoutError as p, NotAuthenticatedError as d, SiteCreateError as a, UnsupportedDropError as n, humanizeDropError as m, isNotAuthenticatedError as u } from "./errors.js";
2
+ import { DROPZONE_EVENTS as s } from "./analytics.js";
3
+ import { getSingleNonIndexHtmlFileName as D, hasMultipleHtmlFilesWithoutIndex as f, readDataTransfer as S, readFileList as h, renameSingleNonIndexHtmlToIndex as A } from "./readFiles.js";
4
+ import { getFileTypes as F } from "./fileTypes.js";
5
+ import { detectBuild as _, inferBuildSettings as y } from "./detectBuild.js";
6
+ import { zipFiles as c } from "./zip.js";
7
+ import { AnonymousDropClient as C } from "./client.js";
8
+ import { AuthenticatedDropClient as L } from "./authedDropClient.js";
9
+ import { AuthenticatedBuildClient as P } from "./buildClient.js";
10
+ import { deployBuild as U, deployFiles as H, deployZippedBuild as M } from "./deploy.js";
11
+ import { clearDropStash as z, hasDropStashMarker as Z, loadDropStash as k, saveDropStash as v } from "./buildStash.js";
12
+ import { DEFAULT_API_BASE as W, DEFAULT_PROXY_BASE as X, UPLOAD_RETRY_DELAYS_MS as b } from "./constants.js";
14
13
  export {
15
- f as AnonymousDropClient,
16
- L as AuthenticatedBuildClient,
17
- g as AuthenticatedDropClient,
18
- v as BuildCreateError,
19
- W as BuildFailedError,
20
- X as BuildTimeoutError,
21
- A as DEFAULT_API_BASE,
22
- T as DEFAULT_POLL_INTERVAL_MS,
23
- h as DEFAULT_PROXY_BASE,
24
- F as DEFAULT_TIMEOUT_MS,
25
- G as DROPZONE_EVENTS,
26
- Y as NotAuthenticatedError,
27
- b as SiteCreateError,
28
- j as UnsupportedDropError,
29
- D as apiError,
30
- M as clearDropStash,
31
- B as createSiteInAccount,
32
- z as deployBuild,
33
- V as deployFiles,
34
- Z as deployZippedBuild,
35
- u as detectBuild,
36
- y as generateNetlifyToml,
37
- o as getDigest,
38
- m as getFileTypes,
39
- i as getSingleNonIndexHtmlFileName,
40
- O as hasDropStashMarker,
41
- l as hasMultipleHtmlFilesWithoutIndex,
42
- q as humanizeDropError,
43
- s as inferBuildSettings,
44
- P as loadDropStash,
45
- _ as pollDeployUntilSettled,
46
- p as readDataTransfer,
47
- a as readFileList,
48
- d as renameSingleNonIndexHtmlToIndex,
49
- H as saveDropStash,
50
- U as zipFiles
14
+ C as AnonymousDropClient,
15
+ P as AuthenticatedBuildClient,
16
+ L as AuthenticatedDropClient,
17
+ o as BuildCreateError,
18
+ t as BuildFailedError,
19
+ i as BuildTimeoutError,
20
+ W as DEFAULT_API_BASE,
21
+ X as DEFAULT_PROXY_BASE,
22
+ s as DROPZONE_EVENTS,
23
+ l as DeployFailedError,
24
+ p as DeployTimeoutError,
25
+ d as NotAuthenticatedError,
26
+ a as SiteCreateError,
27
+ b as UPLOAD_RETRY_DELAYS_MS,
28
+ n as UnsupportedDropError,
29
+ z as clearDropStash,
30
+ U as deployBuild,
31
+ H as deployFiles,
32
+ M as deployZippedBuild,
33
+ _ as detectBuild,
34
+ F as getFileTypes,
35
+ D as getSingleNonIndexHtmlFileName,
36
+ Z as hasDropStashMarker,
37
+ f as hasMultipleHtmlFilesWithoutIndex,
38
+ m as humanizeDropError,
39
+ y as inferBuildSettings,
40
+ u as isNotAuthenticatedError,
41
+ k as loadDropStash,
42
+ S as readDataTransfer,
43
+ h as readFileList,
44
+ A as renameSingleNonIndexHtmlToIndex,
45
+ v as saveDropStash,
46
+ c as zipFiles
51
47
  };
@@ -1,21 +1,15 @@
1
1
  import { ProcessedFile } from './types';
2
2
  /**
3
- * Read a DataTransfer from a drop event into ProcessedFiles.
4
- *
5
- * NOTE: `webkitGetAsEntry()` must be called synchronously inside the drop
6
- * handler — the DataTransfer is detached once the event turn ends. The
7
- * component captures entries first (see `readDroppedEntries`) then calls the
8
- * async readers, so this function is safe to `await`.
3
+ * Read a drop's DataTransfer into ProcessedFiles. `webkitGetAsEntry()` runs
4
+ * synchronously before the first await — the DataTransfer detaches once the
5
+ * event turn ends.
9
6
  */
10
7
  export declare function readDataTransfer(dt: DataTransfer): Promise<ProcessedFile[]>;
11
8
  export declare function readFileList(files: FileList): Promise<ProcessedFile[]>;
12
9
  export declare function getSingleNonIndexHtmlFileName(files: ProcessedFile[]): string | null;
13
10
  export declare function hasMultipleHtmlFilesWithoutIndex(files: ProcessedFile[]): boolean;
14
11
  /**
15
- * When the set has no index.html but exactly one HTML file (a lone page
16
- * alongside its assets, or a single dropped file), rename that file to
17
- * index.html — keeping its directory — so it is served at the site root
18
- * instead of 404ing. Content and sha are untouched. Any other set (already has
19
- * an index, multiple HTML files, or no HTML) is returned unchanged.
12
+ * A lone non-index HTML page is renamed to index.html (same directory,
13
+ * content/sha untouched) so it serves instead of 404ing. Other sets unchanged.
20
14
  */
21
15
  export declare function renameSingleNonIndexHtmlToIndex(files: ProcessedFile[]): ProcessedFile[];
@@ -9,10 +9,8 @@ export interface ProcessedFile {
9
9
  }
10
10
  export type Digest = Record<string, string>;
11
11
  /**
12
- * Response body of `POST /api/v1/drop`. Not a canonical Deploy resource —
13
- * it's a mixed shape carrying both the anonymous site and the initial deploy
14
- * so the client has everything it needs to upload, poll, and hand off to the
15
- * user in one round trip.
12
+ * Response of `POST /api/v1/drop` — a mixed site+deploy shape, everything the
13
+ * client needs to upload, poll, and hand off in one round trip.
16
14
  */
17
15
  export interface DropResponse {
18
16
  /** site id (UUID) — surfaced to callers so they can build claim links */