@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,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire up the "Copy URL" / "Copy page" buttons rendered by ArticleCopyActions.astro.
|
|
3
|
+
*
|
|
4
|
+
* This runs on every `astro:page-load` (initial load *and* every client-side
|
|
5
|
+
* navigation via `<ClientRouter />`), so the buttons keep working after routing
|
|
6
|
+
* to another article/post. Each wrapper is guarded so re-initialising the same
|
|
7
|
+
* DOM node never attaches duplicate listeners.
|
|
8
|
+
*/
|
|
9
|
+
export declare function initArticleCopyActions(root?: ParentNode): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,6 +5,6 @@ export { default as SearchLink } from './preact/SearchModal/components/SearchLin
|
|
|
5
5
|
export { default as SearchHeading } from './preact/SearchModal/components/SearchHeading/SearchHeading';
|
|
6
6
|
export { default as SearchToggle } from './preact/SearchModal/components/SearchToggle/SearchToggle';
|
|
7
7
|
export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
|
|
8
|
-
export { DropZone, AnonymousDropClient, deployFiles, readDataTransfer, readFileList, } from './preact/DropZone';
|
|
9
|
-
export type { DropClient, DropResponse, Digest, DeployResult, DeployProgress, DeployPhase, ProcessedFile, } from './preact/DropZone';
|
|
8
|
+
export { DropZone, AnonymousDropClient, AuthenticatedBuildClient, AuthenticatedDropClient, deployBuild, deployFiles, detectBuild, inferBuildSettings, readDataTransfer, readFileList, zipFiles, } from './preact/DropZone';
|
|
9
|
+
export type { AuthenticatedBuildClientConfig, AuthenticatedDropClientConfig, BuildClient, BuildDeployResult, BuildDetection, BuildSite, DeployedBuild, DeployedSite, DropClient, DropResponse, Digest, DeployResult, DeployProgress, DeployPhase, InferredBuildSettings, ProcessedFile, } from './preact/DropZone';
|
|
10
10
|
export { type IconName } from './preact/Icon';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentChildren } from 'preact';
|
|
2
|
-
import { BuildDetection, DropClient } from './drop-core';
|
|
3
|
-
import { DeployedSite, DeployError, TrackFn } from './useDropDeploy';
|
|
2
|
+
import { BuildClient, BuildDetection, DropClient } from './drop-core';
|
|
3
|
+
import { DeployedBuild, DeployedSite, DeployError, TrackFn } from './useDropDeploy';
|
|
4
4
|
interface Props {
|
|
5
5
|
/** Content the drop layer sits on top of. The zone is invisible until you drag over it. */
|
|
6
6
|
children?: ComponentChildren;
|
|
@@ -10,23 +10,81 @@ interface Props {
|
|
|
10
10
|
client?: DropClient;
|
|
11
11
|
/** Build the "claim this site" URL from the assigned site name (subdomain). */
|
|
12
12
|
claimUrl?: (siteName: string) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Where an authenticated static deploy sends the visitor — the site already
|
|
15
|
+
* lives in their account, so there is no claim step. Defaults to the new
|
|
16
|
+
* site's project overview on app.netlify.com.
|
|
17
|
+
*/
|
|
18
|
+
siteDashboardUrl?: (siteName: string) => string;
|
|
13
19
|
/**
|
|
14
20
|
* Where to send a build-required drop (framework source, build command,
|
|
15
|
-
* functions)
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
21
|
+
* functions) that can't be built here — no `getUploadToken`/`buildClient`, or a
|
|
22
|
+
* visitor who isn't logged in. Such projects can't deploy through the anonymous
|
|
23
|
+
* static drop API, so by default the user is redirected here — the app signup
|
|
24
|
+
* page with `next=/drop` — to build on the authenticated Drop page. Override to
|
|
25
|
+
* point at your own destination.
|
|
19
26
|
*/
|
|
20
27
|
buildSignupUrl?: string;
|
|
21
28
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
29
|
+
* Mint a short-lived bearer token for direct api.netlify.com uploads — pass it
|
|
30
|
+
* to switch on the whole authenticated path for logged-in visitors: static
|
|
31
|
+
* drops deploy straight into their account (then `siteDashboardUrl`), and
|
|
32
|
+
* build-required drops build in place instead of being handed off to the app.
|
|
33
|
+
* On netlify.com this reads `GET /access-control/generate-access-control-token`.
|
|
34
|
+
* Resolving `null` means "no session": static drops fall back to the anonymous
|
|
35
|
+
* claim flow, build drops to `buildSignupUrl`.
|
|
36
|
+
* See [Logged-in visitors](#logged-in-visitors).
|
|
37
|
+
*/
|
|
38
|
+
getUploadToken?: () => Promise<string | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Inject a custom `BuildClient` (tests, staging, a different account flow).
|
|
41
|
+
* Takes precedence over `getUploadToken` for the build path.
|
|
42
|
+
*/
|
|
43
|
+
buildClient?: BuildClient;
|
|
44
|
+
/**
|
|
45
|
+
* Inject a custom authenticated `DropClient` for static drops (tests, staging,
|
|
46
|
+
* a different account flow). Takes precedence over `getUploadToken` for the
|
|
47
|
+
* static path. Distinct from `client`, which is the anonymous fallback.
|
|
48
|
+
*/
|
|
49
|
+
authenticatedDropClient?: DropClient;
|
|
50
|
+
/**
|
|
51
|
+
* API root for the authenticated paths' JSON calls, which go through your
|
|
52
|
+
* access-control rewrite so the session cookie authorizes them. Defaults to
|
|
53
|
+
* `/access-control/bb-api/api/v1`. (Uploads always go direct to
|
|
54
|
+
* `api.netlify.com` — the proxy can't carry bodies that large.)
|
|
55
|
+
*/
|
|
56
|
+
proxyBase?: string;
|
|
57
|
+
/** Create the visitor's new project in this account. Omit for their default account. */
|
|
58
|
+
accountSlug?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Where an enqueued build sends the visitor. Defaults to the new site's
|
|
61
|
+
* project overview, same as a static deploy; `build.deployId` is available for
|
|
62
|
+
* consumers who want the deploy-log page instead.
|
|
63
|
+
*/
|
|
64
|
+
buildDeployUrl?: (build: DeployedBuild) => string;
|
|
65
|
+
/**
|
|
66
|
+
* Poll until the build finishes before handing off, instead of redirecting as
|
|
67
|
+
* soon as it's enqueued. The trade-off: waiting means a failing build surfaces
|
|
68
|
+
* its own error message here (via `onError` and the overlay) rather than the
|
|
69
|
+
* visitor discovering it on the deploy page — at the cost of holding them on a
|
|
70
|
+
* spinner for the length of the build, which is minutes. Off by default.
|
|
71
|
+
*/
|
|
72
|
+
waitForBuild?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Called when a build-required drop is detected, instead of building it or
|
|
75
|
+
* redirecting. Use it to own the hand-off yourself (custom routing, persisting
|
|
76
|
+
* the drop, gating on auth). When set, the component neither builds nor
|
|
77
|
+
* redirects. The static drop path is unaffected either way.
|
|
26
78
|
*/
|
|
27
79
|
onBuildRequired?: (info: BuildDetection) => void;
|
|
28
80
|
/** Called once the deploy is live. */
|
|
29
81
|
onDeploy?: (result: DeployedSite) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Called once a build-required drop has been zipped, uploaded and enqueued —
|
|
84
|
+
* before the redirect to `buildDeployUrl`. The site exists at this point but
|
|
85
|
+
* won't serve content until the build finishes.
|
|
86
|
+
*/
|
|
87
|
+
onBuildDeploy?: (build: DeployedBuild) => void;
|
|
30
88
|
/**
|
|
31
89
|
* Called when a deploy fails, with a humanized `message` (ready to show a
|
|
32
90
|
* user — the same copy the built-in overlay uses) and the raw `reason`. Pair
|
|
@@ -46,11 +104,22 @@ interface Props {
|
|
|
46
104
|
* properties. Stays provider-agnostic — wire it to Segment/Amplitude/GA in the
|
|
47
105
|
* consuming app, e.g. `onTrack={(name, props) => new Analytics().track(name, props)}`.
|
|
48
106
|
* Emitted events (all include `dropzone_id` when `analyticsId` is set):
|
|
49
|
-
* - `dropzone_files_dropped` — files dropped via drag ({ method: 'drag', file_count })
|
|
107
|
+
* - `dropzone_files_dropped` — files dropped via drag ({ method: 'drag', file_count, file_types })
|
|
50
108
|
* - `dropzone_browse_opened` — file picker opened ({ method: 'keyboard' | 'click' })
|
|
51
|
-
* - `dropzone_build_required` — drop needs a build
|
|
52
|
-
* - `dropzone_deploy_succeeded` — deploy went live
|
|
53
|
-
* - `
|
|
109
|
+
* - `dropzone_build_required` — drop needs a build (built here, or handed off) ({ method, reason, file_count, file_types })
|
|
110
|
+
* - `dropzone_deploy_succeeded` — static deploy went live ({ method, site_name, file_count, authenticated, auth_fallback?, file_types })
|
|
111
|
+
* - `dropzone_build_deploy_succeeded` — build enqueued for a logged-in visitor ({ method, reason, site_name, file_count, framework?, file_types })
|
|
112
|
+
* - `dropzone_deploy_failed` — deploy or build errored out ({ method, reason, file_count?, file_types })
|
|
113
|
+
*
|
|
114
|
+
* `authenticated` says whether the deploy landed in the visitor's account;
|
|
115
|
+
* `auth_fallback: true` is sent only when an authenticated attempt bounced
|
|
116
|
+
* (stale auth hint) and the drop completed anonymously — omitted otherwise.
|
|
117
|
+
* `file_types` is the sorted, de-duplicated list of MIME types in the
|
|
118
|
+
* selection, with `application/octet-stream` standing in wherever the browser
|
|
119
|
+
* reports none (a dragged folder, an `.exe`). It is omitted when the browser
|
|
120
|
+
* exposes no files at all. Note `dropzone_files_dropped` only fires for drag —
|
|
121
|
+
* a file-picker selection reports its types on the outcome events, as
|
|
122
|
+
* `dropzone_browse_opened` fires before any file exists.
|
|
54
123
|
*/
|
|
55
124
|
onTrack?: TrackFn;
|
|
56
125
|
/**
|
|
@@ -61,5 +130,5 @@ interface Props {
|
|
|
61
130
|
analyticsId?: string;
|
|
62
131
|
className?: string;
|
|
63
132
|
}
|
|
64
|
-
export default function DropZone({ children, apiBase, client, claimUrl, buildSignupUrl, onBuildRequired, onDeploy, onError, showStatus, onTrack, analyticsId, className, }: Props): import("preact").JSX.Element;
|
|
133
|
+
export default function DropZone({ children, apiBase, client, claimUrl, siteDashboardUrl, buildSignupUrl, getUploadToken, buildClient, authenticatedDropClient, proxyBase, accountSlug, buildDeployUrl, waitForBuild, onBuildRequired, onDeploy, onBuildDeploy, onError, showStatus, onTrack, analyticsId, className, }: Props): import("preact").JSX.Element;
|
|
65
134
|
export {};
|
|
@@ -1,154 +1,186 @@
|
|
|
1
1
|
import { u as e } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { A as
|
|
3
|
-
import { readFileList as
|
|
2
|
+
import { A as j, d as G, y as K } from "../../../chunks/hooks.module.DRcxknIz.js";
|
|
3
|
+
import { readFileList as L, readDataTransfer as Z } from "./drop-core/readFiles.js";
|
|
4
|
+
import { getFileTypes as D } from "./drop-core/fileTypes.js";
|
|
4
5
|
import "./drop-core/detectBuild.js";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
import "./drop-core/zip.js";
|
|
7
|
+
import { useDropDeploy as q } from "./useDropDeploy.js";
|
|
8
|
+
import { Fragment as w } from "preact";
|
|
9
|
+
import '../../../assets/DropZone.css';const H = 120, J = (r) => `https://app.netlify.com/drop/${r}`, Q = (r) => `https://app.netlify.com/projects/${r}`, W = "https://app.netlify.com/signup?next=/drop&utm_campaign=drop", X = ({ siteName: r }) => `https://app.netlify.com/projects/${r}`;
|
|
10
|
+
function ce({
|
|
11
|
+
children: r,
|
|
12
|
+
apiBase: a,
|
|
13
|
+
client: l,
|
|
14
|
+
claimUrl: c = J,
|
|
15
|
+
siteDashboardUrl: u = Q,
|
|
16
|
+
buildSignupUrl: A = W,
|
|
17
|
+
getUploadToken: T,
|
|
18
|
+
buildClient: C,
|
|
19
|
+
authenticatedDropClient: S,
|
|
20
|
+
proxyBase: _,
|
|
21
|
+
accountSlug: $,
|
|
22
|
+
buildDeployUrl: B = X,
|
|
23
|
+
waitForBuild: U,
|
|
24
|
+
onBuildRequired: P,
|
|
25
|
+
onDeploy: R,
|
|
26
|
+
onBuildDeploy: x,
|
|
27
|
+
onError: E,
|
|
17
28
|
showStatus: f = !0,
|
|
18
|
-
onTrack:
|
|
29
|
+
onTrack: d,
|
|
19
30
|
analyticsId: g,
|
|
20
|
-
className:
|
|
31
|
+
className: F
|
|
21
32
|
}) {
|
|
22
|
-
const
|
|
23
|
-
apiBase:
|
|
24
|
-
client:
|
|
25
|
-
claimUrl:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const y = (t, n = {}) => d == null ? void 0 : d(t, g ? { dropzone_id: g, ...n } : n), { status: s, warning: b, busy: i, deploy: m, reset: I } = q({
|
|
34
|
+
apiBase: a,
|
|
35
|
+
client: l,
|
|
36
|
+
claimUrl: c,
|
|
37
|
+
siteDashboardUrl: u,
|
|
38
|
+
buildSignupUrl: A,
|
|
39
|
+
getUploadToken: T,
|
|
40
|
+
buildClient: C,
|
|
41
|
+
authenticatedDropClient: S,
|
|
42
|
+
proxyBase: _,
|
|
43
|
+
accountSlug: $,
|
|
44
|
+
buildDeployUrl: B,
|
|
45
|
+
waitForBuild: U,
|
|
46
|
+
onBuildRequired: P,
|
|
47
|
+
onDeploy: R,
|
|
48
|
+
onBuildDeploy: x,
|
|
49
|
+
onError: E,
|
|
50
|
+
track: y
|
|
51
|
+
}), { active: p, keepActive: M, endDrag: N } = Y(), h = j(null), v = (t) => {
|
|
52
|
+
var n;
|
|
53
|
+
y("dropzone_browse_opened", { method: t }), (n = h.current) == null || n.click();
|
|
54
|
+
}, O = f && (p || i || s.kind === "error"), V = [
|
|
35
55
|
"n-dropzone",
|
|
36
56
|
p && "is-active",
|
|
37
|
-
|
|
57
|
+
i && "is-busy",
|
|
38
58
|
!f && "is-bare",
|
|
39
|
-
|
|
59
|
+
F
|
|
40
60
|
].filter(Boolean).join(" ");
|
|
41
61
|
return /* @__PURE__ */ e(
|
|
42
62
|
"div",
|
|
43
63
|
{
|
|
44
|
-
class:
|
|
45
|
-
"data-state":
|
|
64
|
+
class: V,
|
|
65
|
+
"data-state": s.kind,
|
|
46
66
|
role: "button",
|
|
47
|
-
tabIndex:
|
|
67
|
+
tabIndex: i ? -1 : 0,
|
|
48
68
|
"aria-label": "Drop a site folder or zip here to deploy it, or press Enter to browse for files",
|
|
49
|
-
"aria-busy":
|
|
50
|
-
onDragOver: (
|
|
51
|
-
|
|
69
|
+
"aria-busy": i,
|
|
70
|
+
onDragOver: (t) => {
|
|
71
|
+
i || (t.preventDefault(), M());
|
|
52
72
|
},
|
|
53
|
-
onDrop: (
|
|
54
|
-
if (
|
|
55
|
-
const
|
|
56
|
-
|
|
73
|
+
onDrop: (t) => {
|
|
74
|
+
if (t.preventDefault(), N(), i) return;
|
|
75
|
+
const n = t.dataTransfer;
|
|
76
|
+
n && m(() => Z(n), "drag", D(n.files));
|
|
57
77
|
},
|
|
58
|
-
onClick: (
|
|
59
|
-
!
|
|
78
|
+
onClick: (t) => {
|
|
79
|
+
!i && t.target === t.currentTarget && v("click");
|
|
60
80
|
},
|
|
61
|
-
onKeyDown: (
|
|
62
|
-
|
|
81
|
+
onKeyDown: (t) => {
|
|
82
|
+
i || (t.key === "Enter" || t.key === " ") && (t.preventDefault(), v("keyboard"));
|
|
63
83
|
},
|
|
64
84
|
children: [
|
|
65
|
-
/* @__PURE__ */ e("div", { class: "n-dropzone-content", children:
|
|
85
|
+
/* @__PURE__ */ e("div", { class: "n-dropzone-content", children: r }),
|
|
66
86
|
/* @__PURE__ */ e(
|
|
67
87
|
"input",
|
|
68
88
|
{
|
|
69
|
-
ref:
|
|
89
|
+
ref: h,
|
|
70
90
|
type: "file",
|
|
71
91
|
hidden: !0,
|
|
72
92
|
multiple: !0,
|
|
73
93
|
webkitdirectory: "",
|
|
74
94
|
directory: "",
|
|
75
|
-
onChange: (
|
|
76
|
-
var
|
|
77
|
-
const
|
|
78
|
-
(
|
|
95
|
+
onChange: (t) => {
|
|
96
|
+
var k;
|
|
97
|
+
const n = t.currentTarget;
|
|
98
|
+
if ((k = n.files) != null && k.length) {
|
|
99
|
+
const z = n.files;
|
|
100
|
+
m(() => L(z), "browse", D(z));
|
|
101
|
+
}
|
|
102
|
+
n.value = "";
|
|
79
103
|
}
|
|
80
104
|
}
|
|
81
105
|
),
|
|
82
|
-
|
|
106
|
+
O && /* @__PURE__ */ e(
|
|
83
107
|
"div",
|
|
84
108
|
{
|
|
85
109
|
class: "n-dropzone-overlay n-fadeIn",
|
|
86
110
|
children: [
|
|
87
|
-
/* @__PURE__ */ e(
|
|
88
|
-
|
|
111
|
+
/* @__PURE__ */ e(ee, { status: s, active: p, onReset: I }),
|
|
112
|
+
b && s.kind !== "error" && i && /* @__PURE__ */ e("p", { class: "n-dropzone-warning", role: "status", children: b })
|
|
89
113
|
]
|
|
90
114
|
},
|
|
91
|
-
|
|
115
|
+
s.kind === "idle" ? "active" : s.kind
|
|
92
116
|
)
|
|
93
117
|
]
|
|
94
118
|
}
|
|
95
119
|
);
|
|
96
120
|
}
|
|
97
|
-
function
|
|
98
|
-
const [
|
|
99
|
-
return
|
|
100
|
-
|
|
121
|
+
function Y() {
|
|
122
|
+
const [r, a] = G(!1), l = j();
|
|
123
|
+
return K(() => () => clearTimeout(l.current), []), { active: r, keepActive: () => {
|
|
124
|
+
a(!0), clearTimeout(l.current), l.current = setTimeout(() => a(!1), H);
|
|
101
125
|
}, endDrag: () => {
|
|
102
|
-
clearTimeout(
|
|
126
|
+
clearTimeout(l.current), a(!1);
|
|
103
127
|
} };
|
|
104
128
|
}
|
|
105
|
-
function
|
|
106
|
-
status:
|
|
107
|
-
active:
|
|
108
|
-
onReset:
|
|
129
|
+
function ee({
|
|
130
|
+
status: r,
|
|
131
|
+
active: a,
|
|
132
|
+
onReset: l
|
|
109
133
|
}) {
|
|
110
|
-
switch (
|
|
134
|
+
switch (r.kind) {
|
|
111
135
|
// Idle-but-active means a drag is hovering the zone.
|
|
112
136
|
case "idle":
|
|
113
|
-
return
|
|
137
|
+
return a ? /* @__PURE__ */ e("p", { class: "n-dropzone-hint", children: "Drop to deploy" }) : null;
|
|
114
138
|
case "reading":
|
|
115
|
-
return /* @__PURE__ */ e(
|
|
139
|
+
return /* @__PURE__ */ e(o, { label: "Reading files…" });
|
|
140
|
+
case "zipping":
|
|
141
|
+
return /* @__PURE__ */ e(o, { label: "Packaging your project…" });
|
|
116
142
|
case "creating":
|
|
117
|
-
return /* @__PURE__ */ e(
|
|
143
|
+
return /* @__PURE__ */ e(o, { label: "Creating deploy…" });
|
|
118
144
|
case "processing":
|
|
119
|
-
return /* @__PURE__ */ e(
|
|
145
|
+
return /* @__PURE__ */ e(o, { label: "Processing — almost live…" });
|
|
146
|
+
case "building":
|
|
147
|
+
return /* @__PURE__ */ e(o, { label: "Building your project…" });
|
|
120
148
|
case "redirecting":
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
149
|
+
switch (r.target) {
|
|
150
|
+
case "signup":
|
|
151
|
+
return /* @__PURE__ */ e(o, { label: "This project needs a build — taking you to Netlify…" });
|
|
152
|
+
case "build":
|
|
153
|
+
return /* @__PURE__ */ e(o, { label: "Build started — taking you to your new project…" });
|
|
154
|
+
case "claim":
|
|
155
|
+
return /* @__PURE__ */ e(o, { label: "Site’s live — taking you to claim it…" });
|
|
156
|
+
case "dashboard":
|
|
157
|
+
return /* @__PURE__ */ e(o, { label: "Site’s live — taking you to your new project…" });
|
|
158
|
+
}
|
|
127
159
|
case "uploading": {
|
|
128
|
-
const
|
|
129
|
-
return /* @__PURE__ */ e(
|
|
130
|
-
/* @__PURE__ */ e(
|
|
131
|
-
/* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow":
|
|
160
|
+
const c = r.total ? Math.round(r.uploaded / r.total * 100) : 0;
|
|
161
|
+
return /* @__PURE__ */ e(w, { children: [
|
|
162
|
+
/* @__PURE__ */ e(o, { label: `Uploading ${r.uploaded}/${r.total} files…` }),
|
|
163
|
+
/* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow": c, children: /* @__PURE__ */ e("div", { class: "n-dropzone-progress-bar", style: { width: `${c}%` } }) })
|
|
132
164
|
] });
|
|
133
165
|
}
|
|
134
166
|
case "error":
|
|
135
|
-
return /* @__PURE__ */ e(
|
|
167
|
+
return /* @__PURE__ */ e(w, { children: [
|
|
136
168
|
/* @__PURE__ */ e("p", { class: "n-dropzone-title n-dropzone-title--error", children: "Something went wrong" }),
|
|
137
|
-
/* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", role: "alert", children:
|
|
138
|
-
/* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick:
|
|
169
|
+
/* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", role: "alert", children: r.message }),
|
|
170
|
+
/* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick: l, children: "Try again" })
|
|
139
171
|
] });
|
|
140
172
|
}
|
|
141
173
|
}
|
|
142
|
-
function
|
|
174
|
+
function o({ label: r }) {
|
|
143
175
|
return /* @__PURE__ */ e("div", { class: "n-dropzone-loading", children: [
|
|
144
176
|
/* @__PURE__ */ e("span", { class: "n-dropzone-spinner", "aria-hidden": "true" }),
|
|
145
177
|
/* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", "aria-live": "polite", children: [
|
|
146
|
-
|
|
178
|
+
r,
|
|
147
179
|
" ",
|
|
148
180
|
/* @__PURE__ */ e("span", { class: "n-dropzone-nudge", children: "Please don’t refresh." })
|
|
149
181
|
] })
|
|
150
182
|
] });
|
|
151
183
|
}
|
|
152
184
|
export {
|
|
153
|
-
|
|
185
|
+
ce as default
|
|
154
186
|
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { DropClient } from './client';
|
|
2
|
+
import { Digest, DropResponse } from './types';
|
|
3
|
+
export interface AuthenticatedDropClientConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Base for JSON API calls, routed through the consumer's access-control
|
|
6
|
+
* rewrite so the session cookie authenticates them. On netlify.com that
|
|
7
|
+
* rewrite is `/access-control/*` → the app's access-control function, which
|
|
8
|
+
* makes `/access-control/bb-api/api/v1` the API root (the default here).
|
|
9
|
+
*/
|
|
10
|
+
proxyBase?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Direct API base for the per-file uploads. The proxy above runs in a Lambda
|
|
13
|
+
* with a ~6MB request body limit, so file PUTs go straight to
|
|
14
|
+
* `api.netlify.com` (whose `/api/*` CORS policy allows any origin).
|
|
15
|
+
*/
|
|
16
|
+
apiBase?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Mint a short-lived bearer token for those direct uploads. On netlify.com
|
|
19
|
+
* this is `GET /access-control/generate-access-control-token`, whose
|
|
20
|
+
* `accessControlToken` the API decrypts back into the user's access token.
|
|
21
|
+
* Resolving `null` means "no session" and surfaces as `NotAuthenticatedError`.
|
|
22
|
+
*/
|
|
23
|
+
getUploadToken: () => Promise<string | null>;
|
|
24
|
+
/** Create the site in this account. Omit to use the user's default account. */
|
|
25
|
+
accountSlug?: string;
|
|
26
|
+
/** How often to re-read the deploy while waiting. Default 1s. */
|
|
27
|
+
pollIntervalMs?: number;
|
|
28
|
+
/** How long to wait before giving up on the deploy. Default 10 minutes. */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Authenticated drop client for logged-in visitors. Unlike `AnonymousDropClient`
|
|
33
|
+
* — which creates an account-less site the visitor must later claim — this
|
|
34
|
+
* deploys straight into the visitor's account via the sites/deploys API,
|
|
35
|
+
* mirroring what app.netlify.com does for a logged-in drag-and-drop deploy.
|
|
36
|
+
* There is no claim step, so the caller should hand off to the site's dashboard
|
|
37
|
+
* page rather than the claim page.
|
|
38
|
+
*
|
|
39
|
+
* Requests split across two hosts by necessity: JSON calls go through the
|
|
40
|
+
* consumer's access-control proxy (cookie session, no token handling in the
|
|
41
|
+
* browser), while the per-file PUTs go direct to `api.netlify.com` with the
|
|
42
|
+
* short-lived bearer from `getUploadToken()` because the proxy can't carry
|
|
43
|
+
* large bodies.
|
|
44
|
+
*
|
|
45
|
+
* Error-mapping invariant: only pre-mutation failures — a null upload token, or
|
|
46
|
+
* a 401/403 creating the site — throw `NotAuthenticatedError`, which is the
|
|
47
|
+
* signal the drop flow may safely retry anonymously. Once the site exists, an
|
|
48
|
+
* auth failure throws a plain status-carrying error instead: falling back at
|
|
49
|
+
* that point would strand an empty site in the account *and* deploy a duplicate
|
|
50
|
+
* anonymously.
|
|
51
|
+
*/
|
|
52
|
+
export declare class AuthenticatedDropClient implements DropClient {
|
|
53
|
+
private proxyBase;
|
|
54
|
+
private apiBase;
|
|
55
|
+
private getUploadToken;
|
|
56
|
+
private accountSlug?;
|
|
57
|
+
private pollIntervalMs;
|
|
58
|
+
private timeoutMs;
|
|
59
|
+
constructor({ proxyBase, apiBase, getUploadToken, accountSlug, pollIntervalMs, timeoutMs, }: AuthenticatedDropClientConfig);
|
|
60
|
+
/**
|
|
61
|
+
* The token here is the upload bearer, not a drop token — it authorizes the
|
|
62
|
+
* direct-API file PUTs, while the proxied JSON calls ignore it and ride the
|
|
63
|
+
* session cookie. Minted once per deploy, before anything is created, so a
|
|
64
|
+
* missing session fails the whole attempt cleanly.
|
|
65
|
+
*/
|
|
66
|
+
getToken(): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Two proxied calls: create the site in the visitor's account, then the
|
|
69
|
+
* deploy on it. Mapped into the anonymous `DropResponse` shape so
|
|
70
|
+
* `deployFiles` runs unchanged over either client.
|
|
71
|
+
*/
|
|
72
|
+
createDeploy(files: Digest, _token: string): Promise<DropResponse>;
|
|
73
|
+
uploadFile(deployId: string, path: string, content: ArrayBuffer, token: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Poll the deploy through the proxy until it settles — the session cookie
|
|
76
|
+
* outlives the short-lived upload bearer, so a slow deploy can't expire its
|
|
77
|
+
* own poll. Resolve on `ready`, throw on `error`/`rejected`, throw on timeout.
|
|
78
|
+
*/
|
|
79
|
+
waitUntilReady(deploy: DropResponse, _token: string): Promise<void>;
|
|
80
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
var p = Object.defineProperty;
|
|
2
|
+
var h = (n, t, s) => t in n ? p(n, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : n[t] = s;
|
|
3
|
+
var r = (n, t, s) => h(n, typeof t != "symbol" ? t + "" : t, s);
|
|
4
|
+
import { apiError as d } from "./client.js";
|
|
5
|
+
import { NotAuthenticatedError as l, SiteCreateError as y } from "./errors.js";
|
|
6
|
+
const u = "/access-control/bb-api/api/v1", w = "https://api.netlify.com/api/v1", f = 1e3, m = 10 * 60 * 1e3, T = /* @__PURE__ */ new Set(["ready", "error", "rejected"]);
|
|
7
|
+
class g {
|
|
8
|
+
constructor({
|
|
9
|
+
proxyBase: t = u,
|
|
10
|
+
apiBase: s = w,
|
|
11
|
+
getUploadToken: i,
|
|
12
|
+
accountSlug: o,
|
|
13
|
+
pollIntervalMs: a = f,
|
|
14
|
+
timeoutMs: e = m
|
|
15
|
+
}) {
|
|
16
|
+
r(this, "proxyBase");
|
|
17
|
+
r(this, "apiBase");
|
|
18
|
+
r(this, "getUploadToken");
|
|
19
|
+
r(this, "accountSlug");
|
|
20
|
+
r(this, "pollIntervalMs");
|
|
21
|
+
r(this, "timeoutMs");
|
|
22
|
+
this.proxyBase = t, this.apiBase = s, this.getUploadToken = i, this.accountSlug = o, this.pollIntervalMs = a, this.timeoutMs = e;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The token here is the upload bearer, not a drop token — it authorizes the
|
|
26
|
+
* direct-API file PUTs, while the proxied JSON calls ignore it and ride the
|
|
27
|
+
* session cookie. Minted once per deploy, before anything is created, so a
|
|
28
|
+
* missing session fails the whole attempt cleanly.
|
|
29
|
+
*/
|
|
30
|
+
async getToken() {
|
|
31
|
+
const t = await this.getUploadToken();
|
|
32
|
+
if (!t) throw new l();
|
|
33
|
+
return t;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Two proxied calls: create the site in the visitor's account, then the
|
|
37
|
+
* deploy on it. Mapped into the anonymous `DropResponse` shape so
|
|
38
|
+
* `deployFiles` runs unchanged over either client.
|
|
39
|
+
*/
|
|
40
|
+
async createDeploy(t, s) {
|
|
41
|
+
const i = this.accountSlug ? `/${this.accountSlug}/sites` : "/sites", o = await fetch(`${this.proxyBase}${i}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
credentials: "include",
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
body: JSON.stringify({ created_via: "drop" })
|
|
46
|
+
});
|
|
47
|
+
if (o.status === 401 || o.status === 403) throw new l();
|
|
48
|
+
if (!o.ok) throw new y(o.status);
|
|
49
|
+
const a = await o.json(), e = await fetch(`${this.proxyBase}/sites/${a.id}/deploys`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
credentials: "include",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify({ files: t, deploy_source: "drop" })
|
|
54
|
+
});
|
|
55
|
+
if (!e.ok) throw d("deploy create", e.status);
|
|
56
|
+
const c = await e.json();
|
|
57
|
+
return {
|
|
58
|
+
id: a.id,
|
|
59
|
+
deploy_id: c.id,
|
|
60
|
+
subdomain: a.name,
|
|
61
|
+
required: c.required ?? []
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async uploadFile(t, s, i, o) {
|
|
65
|
+
const a = await fetch(`${this.apiBase}/deploys/${t}/files${s}`, {
|
|
66
|
+
method: "PUT",
|
|
67
|
+
headers: { "Content-Type": "application/octet-stream", Authorization: `Bearer ${o}` },
|
|
68
|
+
body: i
|
|
69
|
+
});
|
|
70
|
+
if (!a.ok) throw d(`upload ${s}`, a.status);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Poll the deploy through the proxy until it settles — the session cookie
|
|
74
|
+
* outlives the short-lived upload bearer, so a slow deploy can't expire its
|
|
75
|
+
* own poll. Resolve on `ready`, throw on `error`/`rejected`, throw on timeout.
|
|
76
|
+
*/
|
|
77
|
+
async waitUntilReady(t, s) {
|
|
78
|
+
const i = this.timeoutMs / this.pollIntervalMs;
|
|
79
|
+
for (let o = 0; o < i; o++) {
|
|
80
|
+
const a = await fetch(`${this.proxyBase}/deploys/${t.deploy_id}`, {
|
|
81
|
+
credentials: "include"
|
|
82
|
+
});
|
|
83
|
+
if (a.ok) {
|
|
84
|
+
const e = await a.json();
|
|
85
|
+
if (e.state && T.has(e.state)) {
|
|
86
|
+
if (e.state === "ready") return;
|
|
87
|
+
throw new Error(
|
|
88
|
+
e.error_message ? `deploy failed: ${e.error_message}` : "deploy failed"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
await new Promise((e) => setTimeout(e, this.pollIntervalMs));
|
|
93
|
+
}
|
|
94
|
+
throw new Error("Deploy did not become ready in time");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
g as AuthenticatedDropClient
|
|
99
|
+
};
|