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