@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
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { useRef, useState } from 'preact/hooks';
|
|
2
2
|
import {
|
|
3
3
|
AnonymousDropClient,
|
|
4
|
+
AuthenticatedBuildClient,
|
|
5
|
+
AuthenticatedDropClient,
|
|
6
|
+
deployBuild,
|
|
4
7
|
deployFiles,
|
|
5
8
|
detectBuild,
|
|
6
9
|
getSingleNonIndexHtmlFileName,
|
|
7
10
|
hasMultipleHtmlFilesWithoutIndex,
|
|
8
11
|
humanizeDropError,
|
|
12
|
+
NotAuthenticatedError,
|
|
9
13
|
renameSingleNonIndexHtmlToIndex,
|
|
14
|
+
type BuildClient,
|
|
10
15
|
type BuildDetection,
|
|
11
16
|
type DeployProgress,
|
|
17
|
+
type DeployResult,
|
|
12
18
|
type DropClient,
|
|
19
|
+
type InferredBuildSettings,
|
|
13
20
|
type ProcessedFile,
|
|
14
21
|
} from './drop-core';
|
|
15
22
|
|
|
@@ -19,9 +26,15 @@ export type DeploySource = 'drag' | 'browse';
|
|
|
19
26
|
/** The live site handed back once a deploy succeeds. */
|
|
20
27
|
export interface DeployedSite {
|
|
21
28
|
url: string;
|
|
22
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Drop claim token — only present for anonymous deploys. An authenticated
|
|
31
|
+
* deploy lands directly in the visitor's account, so there is nothing to claim.
|
|
32
|
+
*/
|
|
33
|
+
token?: string;
|
|
23
34
|
siteName: string;
|
|
24
35
|
siteId: string;
|
|
36
|
+
/** True when the deploy landed directly in the visitor's account. */
|
|
37
|
+
authenticated: boolean;
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
/** A deploy failure, handed to `onError` so consumers can render their own error UI. */
|
|
@@ -32,16 +45,36 @@ export interface DeployError {
|
|
|
32
45
|
reason: string;
|
|
33
46
|
}
|
|
34
47
|
|
|
48
|
+
/** The build handed back once a build-required drop is enqueued. */
|
|
49
|
+
export interface DeployedBuild {
|
|
50
|
+
/** The site created for the build — live once the build finishes. */
|
|
51
|
+
url: string;
|
|
52
|
+
siteName: string;
|
|
53
|
+
siteId: string;
|
|
54
|
+
buildId: string;
|
|
55
|
+
/** The deploy the build produces, if the API has assigned one yet. */
|
|
56
|
+
deployId?: string;
|
|
57
|
+
/** Build settings synthesised into the uploaded `netlify.toml`, if any. */
|
|
58
|
+
buildSettings: InferredBuildSettings | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
35
61
|
/** Finite states of a single deploy attempt. */
|
|
36
62
|
export type DeployStatus =
|
|
37
63
|
| { kind: 'idle' }
|
|
38
64
|
| { kind: 'reading' }
|
|
65
|
+
// Build path only: packing the drop into the source archive buildbot builds.
|
|
66
|
+
| { kind: 'zipping' }
|
|
39
67
|
| { kind: 'creating' }
|
|
40
68
|
| { kind: 'uploading'; uploaded: number; total: number }
|
|
41
69
|
| { kind: 'processing' }
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
70
|
+
// Build path only: the archive is uploaded and buildbot is building it.
|
|
71
|
+
| { kind: 'building' }
|
|
72
|
+
// `claim` follows an anonymous static deploy (hand off to the claim page);
|
|
73
|
+
// `dashboard` follows an authenticated static deploy (hand off to the new
|
|
74
|
+
// site's project page); `build` follows an authenticated build (hand off to
|
|
75
|
+
// the app's project page while the build runs); `signup` follows a
|
|
76
|
+
// build-required drop with no session to build it with.
|
|
77
|
+
| { kind: 'redirecting'; target: 'claim' | 'dashboard' | 'signup' | 'build' }
|
|
45
78
|
| { kind: 'error'; message: string };
|
|
46
79
|
|
|
47
80
|
/** Provider-agnostic analytics sink. */
|
|
@@ -51,9 +84,18 @@ interface UseDropDeployOptions {
|
|
|
51
84
|
apiBase?: string;
|
|
52
85
|
client?: DropClient;
|
|
53
86
|
claimUrl: (siteName: string) => string;
|
|
87
|
+
siteDashboardUrl: (siteName: string) => string;
|
|
54
88
|
buildSignupUrl: string;
|
|
89
|
+
buildClient?: BuildClient;
|
|
90
|
+
authenticatedDropClient?: DropClient;
|
|
91
|
+
getUploadToken?: () => Promise<string | null>;
|
|
92
|
+
proxyBase?: string;
|
|
93
|
+
accountSlug?: string;
|
|
94
|
+
buildDeployUrl: (build: DeployedBuild) => string;
|
|
95
|
+
waitForBuild?: boolean;
|
|
55
96
|
onBuildRequired?: (info: BuildDetection) => void;
|
|
56
97
|
onDeploy?: (site: DeployedSite) => void;
|
|
98
|
+
onBuildDeploy?: (build: DeployedBuild) => void;
|
|
57
99
|
onError?: (error: DeployError) => void;
|
|
58
100
|
track: TrackFn;
|
|
59
101
|
}
|
|
@@ -61,10 +103,14 @@ interface UseDropDeployOptions {
|
|
|
61
103
|
/** Map a low-level deploy progress event onto our UI status. */
|
|
62
104
|
function progressToStatus(e: DeployProgress): DeployStatus {
|
|
63
105
|
switch (e.phase) {
|
|
106
|
+
case 'zipping':
|
|
107
|
+
return { kind: 'zipping' };
|
|
64
108
|
case 'creating':
|
|
65
109
|
return { kind: 'creating' };
|
|
66
110
|
case 'uploading':
|
|
67
111
|
return { kind: 'uploading', uploaded: e.uploaded ?? 0, total: e.total ?? 0 };
|
|
112
|
+
case 'building':
|
|
113
|
+
return { kind: 'building' };
|
|
68
114
|
case 'processing':
|
|
69
115
|
case 'ready':
|
|
70
116
|
return { kind: 'processing' };
|
|
@@ -91,9 +137,18 @@ export function useDropDeploy({
|
|
|
91
137
|
apiBase,
|
|
92
138
|
client,
|
|
93
139
|
claimUrl,
|
|
140
|
+
siteDashboardUrl,
|
|
94
141
|
buildSignupUrl,
|
|
142
|
+
buildClient,
|
|
143
|
+
authenticatedDropClient,
|
|
144
|
+
getUploadToken,
|
|
145
|
+
proxyBase,
|
|
146
|
+
accountSlug,
|
|
147
|
+
buildDeployUrl,
|
|
148
|
+
waitForBuild,
|
|
95
149
|
onBuildRequired,
|
|
96
150
|
onDeploy,
|
|
151
|
+
onBuildDeploy,
|
|
97
152
|
onError,
|
|
98
153
|
track,
|
|
99
154
|
}: UseDropDeployOptions) {
|
|
@@ -101,24 +156,88 @@ export function useDropDeploy({
|
|
|
101
156
|
const [warning, setWarning] = useState<string | null>(null);
|
|
102
157
|
const dropClient = useRef(client ?? new AnonymousDropClient(apiBase)).current;
|
|
103
158
|
|
|
159
|
+
// Building is opt-in: without an injected client or a way to mint an upload
|
|
160
|
+
// token there is no authenticated path, and build-required drops fall back to
|
|
161
|
+
// the signup hand-off. Built once and held so a re-render doesn't hand a
|
|
162
|
+
// fresh client (and a fresh token cache) to an in-flight deploy.
|
|
163
|
+
const authedBuildClient = useRef(
|
|
164
|
+
buildClient ??
|
|
165
|
+
(getUploadToken
|
|
166
|
+
? new AuthenticatedBuildClient({ proxyBase, getUploadToken, accountSlug })
|
|
167
|
+
: null)
|
|
168
|
+
).current;
|
|
169
|
+
|
|
170
|
+
// Same opt-in for static drops: with authenticated wiring present, deploy
|
|
171
|
+
// straight into the visitor's account and skip the claim step; without it,
|
|
172
|
+
// every static drop stays anonymous.
|
|
173
|
+
const authedDropClient = useRef(
|
|
174
|
+
authenticatedDropClient ??
|
|
175
|
+
(getUploadToken
|
|
176
|
+
? new AuthenticatedDropClient({ proxyBase, getUploadToken, accountSlug })
|
|
177
|
+
: null)
|
|
178
|
+
).current;
|
|
179
|
+
|
|
104
180
|
const busy = status.kind !== 'idle' && status.kind !== 'error';
|
|
105
181
|
|
|
106
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Zip the drop, create a site and enqueue a build. Returns `null` when the
|
|
184
|
+
* visitor turns out not to be logged in — nothing is created in that case, so
|
|
185
|
+
* the caller can still fall back to the signup hand-off. Every other failure
|
|
186
|
+
* throws and is reported by the caller's `catch`.
|
|
187
|
+
*/
|
|
188
|
+
async function buildProject(
|
|
189
|
+
client: BuildClient,
|
|
190
|
+
files: ProcessedFile[]
|
|
191
|
+
): Promise<DeployedBuild | null> {
|
|
192
|
+
try {
|
|
193
|
+
const { site, build, buildSettings, url } = await deployBuild(client, files, {
|
|
194
|
+
onProgress: e => setStatus(progressToStatus(e)),
|
|
195
|
+
waitForBuild,
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
url,
|
|
199
|
+
siteName: site.name,
|
|
200
|
+
siteId: site.id,
|
|
201
|
+
buildId: build.id,
|
|
202
|
+
deployId: build.deploy_id,
|
|
203
|
+
buildSettings,
|
|
204
|
+
};
|
|
205
|
+
} catch (err) {
|
|
206
|
+
if (err instanceof NotAuthenticatedError) return null;
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* `fileTypes` is the MIME types of the selection, read at the drop boundary
|
|
213
|
+
* (see `getFileTypes`) and passed in rather than derived here — it has to be
|
|
214
|
+
* captured before `read()` runs so it survives a read that throws. Omitted
|
|
215
|
+
* from events when empty rather than sent as `[]`.
|
|
216
|
+
*/
|
|
217
|
+
async function deploy(
|
|
218
|
+
read: () => Promise<ProcessedFile[]>,
|
|
219
|
+
source: DeploySource,
|
|
220
|
+
fileTypes: string[]
|
|
221
|
+
) {
|
|
107
222
|
setWarning(null);
|
|
108
223
|
setStatus({ kind: 'reading' });
|
|
109
224
|
|
|
225
|
+
const typeProps = fileTypes.length ? { file_types: fileTypes } : {};
|
|
226
|
+
|
|
110
227
|
// Surface a failure: move to the error state and emit the matching
|
|
111
228
|
// analytics event. Centralised so every failure path (empty selection, a
|
|
112
229
|
// read/deploy throw) reports uniformly — the mirror of the
|
|
113
230
|
// `dropzone_deploy_succeeded` event on the happy path. `file_count` is only
|
|
114
|
-
// included where the file set is known (it isn't if `read()` itself threw)
|
|
231
|
+
// included where the file set is known (it isn't if `read()` itself threw);
|
|
232
|
+
// `file_types` rides along on every failure precisely because it *is* known
|
|
233
|
+
// in that case — a rejected single file is the main thing we want to see.
|
|
115
234
|
// `reason` goes to analytics as-is (raw, e.g. "drop failed: 429"); `message`
|
|
116
235
|
// is what the user sees, which for a caught error is humanized separately.
|
|
117
236
|
// `onError` gets both so a consumer (e.g. with `showStatus={false}`) can show
|
|
118
237
|
// the humanized message while keeping the raw reason for their own logging.
|
|
119
238
|
const fail = (message: string, reason: string, extra?: Record<string, unknown>) => {
|
|
120
239
|
setStatus({ kind: 'error', message });
|
|
121
|
-
track('dropzone_deploy_failed', { method: source, reason, ...extra });
|
|
240
|
+
track('dropzone_deploy_failed', { method: source, reason, ...typeProps, ...extra });
|
|
122
241
|
onError?.({ message, reason });
|
|
123
242
|
};
|
|
124
243
|
|
|
@@ -141,20 +260,26 @@ export function useDropDeploy({
|
|
|
141
260
|
// A drop is the "user provided files" signal; the browse path is already
|
|
142
261
|
// tracked when the picker opens.
|
|
143
262
|
if (source === 'drag') {
|
|
144
|
-
track('dropzone_files_dropped', {
|
|
263
|
+
track('dropzone_files_dropped', {
|
|
264
|
+
method: source,
|
|
265
|
+
file_count: files.length,
|
|
266
|
+
...typeProps,
|
|
267
|
+
});
|
|
145
268
|
}
|
|
146
269
|
|
|
147
270
|
// Build-required projects can't deploy through the anonymous drop API —
|
|
148
271
|
// it only performs static deploys, so building one this way yields a
|
|
149
|
-
// broken site. Detect them up front and
|
|
150
|
-
//
|
|
151
|
-
//
|
|
272
|
+
// broken site. Detect them up front and route them to the build path
|
|
273
|
+
// (which needs a logged-in user) or, failing that, hand off to the
|
|
274
|
+
// authenticated Drop page via signup. Consumers can override the hand-off
|
|
275
|
+
// entirely with `onBuildRequired`.
|
|
152
276
|
const build = detectBuild(files);
|
|
153
277
|
if (build.buildRequired) {
|
|
154
278
|
track('dropzone_build_required', {
|
|
155
279
|
method: source,
|
|
156
280
|
reason: build.reason,
|
|
157
281
|
file_count: files.length,
|
|
282
|
+
...typeProps,
|
|
158
283
|
});
|
|
159
284
|
if (onBuildRequired) {
|
|
160
285
|
// The consumer owns the hand-off now; drop back to idle so the zone
|
|
@@ -163,6 +288,26 @@ export function useDropDeploy({
|
|
|
163
288
|
onBuildRequired(build);
|
|
164
289
|
return;
|
|
165
290
|
}
|
|
291
|
+
if (authedBuildClient) {
|
|
292
|
+
const built = await buildProject(authedBuildClient, files);
|
|
293
|
+
// No session after all (the auth hint cookie can outlive the session).
|
|
294
|
+
// Nothing was created, so fall through to the signup hand-off rather
|
|
295
|
+
// than dead-ending on an error the visitor can't act on from here.
|
|
296
|
+
if (built) {
|
|
297
|
+
setStatus({ kind: 'redirecting', target: 'build' });
|
|
298
|
+
track('dropzone_build_deploy_succeeded', {
|
|
299
|
+
method: source,
|
|
300
|
+
reason: build.reason,
|
|
301
|
+
site_name: built.siteName,
|
|
302
|
+
file_count: files.length,
|
|
303
|
+
...(built.buildSettings ? { framework: built.buildSettings.framework } : {}),
|
|
304
|
+
...typeProps,
|
|
305
|
+
});
|
|
306
|
+
onBuildDeploy?.(built);
|
|
307
|
+
window.location.assign(buildDeployUrl(built));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
166
311
|
setStatus({ kind: 'redirecting', target: 'signup' });
|
|
167
312
|
window.location.assign(buildSignupUrl);
|
|
168
313
|
return;
|
|
@@ -170,40 +315,80 @@ export function useDropDeploy({
|
|
|
170
315
|
|
|
171
316
|
setWarning(indexHtmlWarning(files));
|
|
172
317
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
318
|
+
// Deploy into the visitor's account when we can. NotAuthenticatedError is
|
|
319
|
+
// the one failure that falls back to the anonymous flow — it's thrown
|
|
320
|
+
// before anything is created (the auth hint cookie can outlive the
|
|
321
|
+
// session), so retrying anonymously can't strand a half-made site. Any
|
|
322
|
+
// later failure is real and surfaces as an error instead: falling back
|
|
323
|
+
// then would leave an empty site in the account and deploy a duplicate.
|
|
324
|
+
let deployed: DeployResult | null = null;
|
|
325
|
+
let authenticated = false;
|
|
326
|
+
let authFallback = false;
|
|
327
|
+
if (authedDropClient) {
|
|
328
|
+
try {
|
|
329
|
+
deployed = await deployFiles(authedDropClient, files, {
|
|
330
|
+
onProgress: e => setStatus(progressToStatus(e)),
|
|
331
|
+
});
|
|
332
|
+
authenticated = true;
|
|
333
|
+
} catch (err) {
|
|
334
|
+
if (!(err instanceof NotAuthenticatedError)) throw err;
|
|
335
|
+
authFallback = true;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (!deployed) {
|
|
339
|
+
deployed = await deployFiles(dropClient, files, {
|
|
340
|
+
onProgress: e => setStatus(progressToStatus(e)),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const { url, token, deploy: result } = deployed;
|
|
180
344
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
345
|
+
if (!authenticated) {
|
|
346
|
+
// Best-effort local persistence. Note this does NOT reach the dashboard:
|
|
347
|
+
// localStorage is per-origin, so a token written here (e.g. www.netlify.com)
|
|
348
|
+
// is invisible to app.netlify.com. The cross-origin handoff is the URL
|
|
349
|
+
// fragment below; this only helps if the drop and claim share an origin.
|
|
350
|
+
// Authenticated deploys skip this entirely — there is no claim token,
|
|
351
|
+
// and the upload bearer must never be persisted.
|
|
352
|
+
try {
|
|
353
|
+
localStorage.setItem('drop-token', token);
|
|
354
|
+
localStorage.setItem('dropSiteName', result.subdomain);
|
|
355
|
+
} catch {
|
|
356
|
+
/* private mode / storage disabled — non-fatal */
|
|
357
|
+
}
|
|
190
358
|
}
|
|
191
359
|
|
|
192
|
-
setStatus({ kind: 'redirecting', target: 'claim' });
|
|
360
|
+
setStatus({ kind: 'redirecting', target: authenticated ? 'dashboard' : 'claim' });
|
|
193
361
|
// Fired before the redirect below. Note: the navigation can cut a
|
|
194
362
|
// fire-and-forget analytics request short — see the docs for delivery
|
|
195
|
-
// hardening (sendBeacon / deferring the redirect).
|
|
363
|
+
// hardening (sendBeacon / deferring the redirect). `auth_fallback` is only
|
|
364
|
+
// sent when an authenticated attempt bounced (stale auth hint) — omitted
|
|
365
|
+
// otherwise, like `file_types`.
|
|
196
366
|
track('dropzone_deploy_succeeded', {
|
|
197
367
|
method: source,
|
|
198
368
|
site_name: result.subdomain,
|
|
199
369
|
file_count: files.length,
|
|
370
|
+
authenticated,
|
|
371
|
+
...(authFallback ? { auth_fallback: true } : {}),
|
|
372
|
+
...typeProps,
|
|
373
|
+
});
|
|
374
|
+
onDeploy?.({
|
|
375
|
+
url,
|
|
376
|
+
...(authenticated ? {} : { token }),
|
|
377
|
+
siteName: result.subdomain,
|
|
378
|
+
siteId: result.id,
|
|
379
|
+
authenticated,
|
|
200
380
|
});
|
|
201
|
-
onDeploy?.({ url, token, siteName: result.subdomain, siteId: result.id });
|
|
202
381
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
382
|
+
if (authenticated) {
|
|
383
|
+
// The site already lives in the visitor's account — send them straight
|
|
384
|
+
// to its dashboard page. No claim step, no token in the URL.
|
|
385
|
+
window.location.assign(siteDashboardUrl(result.subdomain));
|
|
386
|
+
} else {
|
|
387
|
+
// Hand the drop token to the dashboard via the URL fragment — localStorage
|
|
388
|
+
// does not cross origins. The dashboard's /drop/:name page reads
|
|
389
|
+
// `#drop_token=` and persists it for the claim + post-signup steps.
|
|
390
|
+
window.location.assign(`${claimUrl(result.subdomain)}#drop_token=${token}`);
|
|
391
|
+
}
|
|
207
392
|
} catch (err) {
|
|
208
393
|
failFromError(err);
|
|
209
394
|
}
|
|
@@ -6,6 +6,7 @@ export { default as SearchHeading } from './SearchModal/components/SearchHeading
|
|
|
6
6
|
export { default as SearchToggle } from './SearchModal/components/SearchToggle/SearchToggle';
|
|
7
7
|
export { default as AskNetlify } from './AskNetlify/AskNetlify';
|
|
8
8
|
export { SearchModal } from './SearchModal';
|
|
9
|
-
export { DropZone } from './DropZone';
|
|
9
|
+
export { DropZone, AuthenticatedBuildClient, AuthenticatedDropClient } from './DropZone';
|
|
10
|
+
export type { BuildClient, DeployedBuild, DeployedSite, DropClient } from './DropZone';
|
|
10
11
|
|
|
11
12
|
export { type IconName } from './Icon';
|