@netlify/spark-ui 1.31.0-alpha.2 → 1.31.0-alpha.4
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/dist/components/index.d.ts +2 -2
- package/dist/components/preact/DropZone/DropZone.d.ts +28 -2
- package/dist/components/preact/DropZone/DropZone.js +58 -51
- package/dist/components/preact/DropZone/DropZone.test.d.ts +1 -0
- package/dist/components/preact/DropZone/index.d.ts +3 -3
- package/dist/components/preact/DropZone/index.js +25 -23
- package/dist/components/preact/DropZone/useDropDeploy.d.ts +11 -6
- package/dist/components/preact/DropZone/useDropDeploy.js +183 -129
- package/dist/components/preact/DropZone/useDropDeploy.test.d.ts +1 -0
- package/dist/components/preact/index.d.ts +2 -2
- package/dist/components/preact/index.js +25 -19
- package/dist/drop-core/analytics.d.ts +107 -0
- package/dist/drop-core/analytics.js +21 -0
- package/dist/drop-core/analytics.test.d.ts +1 -0
- package/dist/drop-core/authedApi.d.ts +55 -0
- package/dist/drop-core/authedApi.js +35 -0
- package/dist/drop-core/authedApi.test.d.ts +1 -0
- package/dist/drop-core/authedDropClient.d.ts +100 -0
- package/dist/drop-core/authedDropClient.js +109 -0
- package/dist/drop-core/authedDropClient.test.d.ts +1 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/buildClient.d.ts +32 -26
- package/dist/drop-core/buildClient.js +84 -0
- package/dist/drop-core/buildClient.test.d.ts +1 -0
- package/dist/drop-core/buildStash.d.ts +37 -0
- package/dist/drop-core/buildStash.js +84 -0
- package/dist/drop-core/buildStash.test.d.ts +0 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/deploy.d.ts +7 -0
- package/dist/drop-core/deploy.js +53 -0
- package/dist/drop-core/deploy.test.d.ts +1 -0
- package/dist/drop-core/detectBuild.test.d.ts +1 -0
- package/dist/drop-core/digest.test.d.ts +1 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/errors.js +1 -1
- package/dist/drop-core/errors.test.d.ts +1 -0
- package/dist/drop-core/fileTypes.test.d.ts +1 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/index.d.ts +3 -0
- package/dist/drop-core/index.js +51 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/readFiles.js +2 -2
- package/dist/drop-core/readFiles.test.d.ts +1 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/types.d.ts +10 -0
- package/dist/{components/preact/DropZone/drop-core → drop-core}/zip.js +1 -1
- package/dist/drop-core/zip.test.d.ts +1 -0
- package/package.json +4 -1
- package/packages/components/index.ts +19 -0
- package/packages/components/preact/DropZone/DropZone.test.ts +71 -0
- package/packages/components/preact/DropZone/DropZone.tsx +32 -2
- package/packages/components/preact/DropZone/index.tsx +14 -3
- package/packages/components/preact/DropZone/useDropDeploy.test.ts +376 -0
- package/packages/components/preact/DropZone/useDropDeploy.ts +305 -134
- package/packages/components/preact/index.ts +19 -2
- package/packages/drop-core/analytics.test.ts +17 -0
- package/packages/drop-core/analytics.ts +122 -0
- package/packages/drop-core/authedApi.test.ts +100 -0
- package/packages/drop-core/authedApi.ts +94 -0
- package/packages/drop-core/authedDropClient.test.ts +196 -0
- package/packages/drop-core/authedDropClient.ts +210 -0
- package/packages/drop-core/buildClient.test.ts +112 -0
- package/packages/{components/preact/DropZone/drop-core → drop-core}/buildClient.ts +55 -70
- package/packages/drop-core/buildStash.test.ts +85 -0
- package/packages/drop-core/buildStash.ts +185 -0
- package/packages/drop-core/deploy.test.ts +135 -0
- package/packages/{components/preact/DropZone/drop-core → drop-core}/deploy.ts +18 -4
- package/packages/drop-core/detectBuild.test.ts +139 -0
- package/packages/drop-core/digest.test.ts +24 -0
- package/packages/drop-core/errors.test.ts +69 -0
- package/packages/{components/preact/DropZone/drop-core → drop-core}/errors.ts +1 -1
- package/packages/drop-core/fileTypes.test.ts +37 -0
- package/packages/{components/preact/DropZone/drop-core → drop-core}/index.ts +3 -0
- package/packages/drop-core/readFiles.test.ts +125 -0
- package/packages/{components/preact/DropZone/drop-core → drop-core}/types.ts +12 -6
- package/packages/drop-core/zip.test.ts +92 -0
- package/dist/components/preact/DropZone/drop-core/authedDropClient.d.ts +0 -77
- package/dist/components/preact/DropZone/drop-core/authedDropClient.js +0 -97
- package/dist/components/preact/DropZone/drop-core/buildClient.js +0 -92
- package/dist/components/preact/DropZone/drop-core/deploy.js +0 -48
- package/dist/components/preact/DropZone/drop-core/index.js +0 -36
- package/packages/components/preact/DropZone/drop-core/authedDropClient.ts +0 -185
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/client.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/client.js +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/detectBuild.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/detectBuild.js +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/digest.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/digest.js +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/errors.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/fileTypes.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/fileTypes.js +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/readFiles.d.ts +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/types.js +0 -0
- /package/dist/{components/preact/DropZone/drop-core → drop-core}/zip.d.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/client.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/detectBuild.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/digest.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/fileTypes.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/readFiles.ts +0 -0
- /package/packages/{components/preact/DropZone/drop-core → drop-core}/zip.ts +0 -0
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { apiError, type DropClient } from './client';
|
|
2
|
-
import type { BuildSite } from './buildClient';
|
|
3
|
-
import type { Digest, DropResponse } from './types';
|
|
4
|
-
import { NotAuthenticatedError, SiteCreateError } from './errors';
|
|
5
|
-
|
|
6
|
-
export interface AuthenticatedDropClientConfig {
|
|
7
|
-
/**
|
|
8
|
-
* API base for every call. Requests go straight to `api.netlify.com`, whose
|
|
9
|
-
* `/api/*` CORS policy allows any origin, rather than through a consumer's
|
|
10
|
-
* access-control rewrite — that proxy allowlists paths per origin, and site
|
|
11
|
-
* and deploy creation are not on the list for netlify.com (they 400 with
|
|
12
|
-
* `x-debug: request origin not allowed to call endpoint`).
|
|
13
|
-
*/
|
|
14
|
-
apiBase?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Mint a short-lived bearer token authorizing the calls. On netlify.com this
|
|
17
|
-
* is `GET /access-control/generate-access-control-token`, whose
|
|
18
|
-
* `accessControlToken` the API decrypts back into the user's access token.
|
|
19
|
-
* Resolving `null` means "no session" and surfaces as `NotAuthenticatedError`.
|
|
20
|
-
*/
|
|
21
|
-
getUploadToken: () => Promise<string | null>;
|
|
22
|
-
/** Create the site in this account. Omit to use the user's default account. */
|
|
23
|
-
accountSlug?: string;
|
|
24
|
-
/** How often to re-read the deploy while waiting. Default 1s. */
|
|
25
|
-
pollIntervalMs?: number;
|
|
26
|
-
/** How long to wait before giving up on the deploy. Default 10 minutes. */
|
|
27
|
-
timeoutMs?: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Same defaults as AuthenticatedBuildClient — the ~15 lines shared with it
|
|
31
|
-
// (constants + site create) are deliberately duplicated rather than extracted,
|
|
32
|
-
// to avoid churn on the in-review build-client branch. Worth unifying once both
|
|
33
|
-
// have landed.
|
|
34
|
-
const API_BASE = 'https://api.netlify.com/api/v1';
|
|
35
|
-
const POLL_INTERVAL_MS = 1000;
|
|
36
|
-
const TIMEOUT_MS = 10 * 60 * 1000;
|
|
37
|
-
|
|
38
|
-
/** Deploy states that end the wait — `ready` succeeds, the rest are failures. */
|
|
39
|
-
const TERMINAL_STATES = new Set(['ready', 'error', 'rejected']);
|
|
40
|
-
|
|
41
|
-
interface DeployState {
|
|
42
|
-
state?: string;
|
|
43
|
-
error_message?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Response body of `POST /sites/{id}/deploys` — the slice the drop flow needs. */
|
|
47
|
-
interface SiteDeployResponse {
|
|
48
|
-
/** deploy id (BSON) */
|
|
49
|
-
id: string;
|
|
50
|
-
/** SHAs the backend does NOT yet have — only these get uploaded */
|
|
51
|
-
required?: string[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Authenticated drop client for logged-in visitors. Unlike `AnonymousDropClient`
|
|
56
|
-
* — which creates an account-less site the visitor must later claim — this
|
|
57
|
-
* deploys straight into the visitor's account via the sites/deploys API,
|
|
58
|
-
* mirroring what app.netlify.com does for a logged-in drag-and-drop deploy.
|
|
59
|
-
* There is no claim step, so the caller should hand off to the site's dashboard
|
|
60
|
-
* page rather than the claim page.
|
|
61
|
-
*
|
|
62
|
-
* Every request goes direct to `api.netlify.com` with the short-lived bearer
|
|
63
|
-
* from `getUploadToken()`. Routing the JSON calls through a consumer's
|
|
64
|
-
* access-control rewrite instead (cookie session, no token in the browser)
|
|
65
|
-
* would be the tighter design, but that proxy allowlists paths per origin and
|
|
66
|
-
* site/deploy creation isn't allowed from netlify.com — it 400s before
|
|
67
|
-
* reaching the API. Revisit if that allowlist gains these paths.
|
|
68
|
-
*
|
|
69
|
-
* Error-mapping invariant: only pre-mutation failures — a null upload token, or
|
|
70
|
-
* a 401/403 creating the site — throw `NotAuthenticatedError`, which is the
|
|
71
|
-
* signal the drop flow may safely retry anonymously. Once the site exists, an
|
|
72
|
-
* auth failure throws a plain status-carrying error instead: falling back at
|
|
73
|
-
* that point would strand an empty site in the account *and* deploy a duplicate
|
|
74
|
-
* anonymously.
|
|
75
|
-
*/
|
|
76
|
-
export class AuthenticatedDropClient implements DropClient {
|
|
77
|
-
private apiBase: string;
|
|
78
|
-
private getUploadToken: () => Promise<string | null>;
|
|
79
|
-
private accountSlug?: string;
|
|
80
|
-
private pollIntervalMs: number;
|
|
81
|
-
private timeoutMs: number;
|
|
82
|
-
|
|
83
|
-
constructor({
|
|
84
|
-
apiBase = API_BASE,
|
|
85
|
-
getUploadToken,
|
|
86
|
-
accountSlug,
|
|
87
|
-
pollIntervalMs = POLL_INTERVAL_MS,
|
|
88
|
-
timeoutMs = TIMEOUT_MS,
|
|
89
|
-
}: AuthenticatedDropClientConfig) {
|
|
90
|
-
this.apiBase = apiBase;
|
|
91
|
-
this.getUploadToken = getUploadToken;
|
|
92
|
-
this.accountSlug = accountSlug;
|
|
93
|
-
this.pollIntervalMs = pollIntervalMs;
|
|
94
|
-
this.timeoutMs = timeoutMs;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The token here is the upload bearer, not a drop token — it authorizes every
|
|
99
|
-
* call this client makes. Minted once per deploy, before anything is created,
|
|
100
|
-
* so a missing session fails the whole attempt cleanly.
|
|
101
|
-
*/
|
|
102
|
-
async getToken(): Promise<string> {
|
|
103
|
-
const token = await this.getUploadToken();
|
|
104
|
-
if (!token) throw new NotAuthenticatedError();
|
|
105
|
-
return token;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Two calls: create the site in the visitor's account, then the deploy on it.
|
|
110
|
-
* Mapped into the anonymous `DropResponse` shape so `deployFiles` runs
|
|
111
|
-
* unchanged over either client.
|
|
112
|
-
*/
|
|
113
|
-
async createDeploy(files: Digest, token: string): Promise<DropResponse> {
|
|
114
|
-
const path = this.accountSlug ? `/${this.accountSlug}/sites` : '/sites';
|
|
115
|
-
const siteRes = await fetch(`${this.apiBase}${path}`, {
|
|
116
|
-
method: 'POST',
|
|
117
|
-
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
118
|
-
body: JSON.stringify({ created_via: 'drop' }),
|
|
119
|
-
});
|
|
120
|
-
// A logged-out visitor 401s here, before anything is created — the one
|
|
121
|
-
// point an anonymous fallback is still safe (see the class doc).
|
|
122
|
-
if (siteRes.status === 401 || siteRes.status === 403) throw new NotAuthenticatedError();
|
|
123
|
-
if (!siteRes.ok) throw new SiteCreateError(siteRes.status);
|
|
124
|
-
const site: BuildSite = await siteRes.json();
|
|
125
|
-
|
|
126
|
-
const deployRes = await fetch(`${this.apiBase}/sites/${site.id}/deploys`, {
|
|
127
|
-
method: 'POST',
|
|
128
|
-
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
129
|
-
body: JSON.stringify({ files, deploy_source: 'drop' }),
|
|
130
|
-
});
|
|
131
|
-
if (!deployRes.ok) throw apiError('deploy create', deployRes.status);
|
|
132
|
-
const deploy: SiteDeployResponse = await deployRes.json();
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
id: site.id,
|
|
136
|
-
deploy_id: deploy.id,
|
|
137
|
-
subdomain: site.name,
|
|
138
|
-
required: deploy.required ?? [],
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async uploadFile(
|
|
143
|
-
deployId: string,
|
|
144
|
-
path: string,
|
|
145
|
-
content: ArrayBuffer,
|
|
146
|
-
token: string
|
|
147
|
-
): Promise<void> {
|
|
148
|
-
// PUT (not POST) so paths with "&" etc. work.
|
|
149
|
-
const res = await fetch(`${this.apiBase}/deploys/${deployId}/files${path}`, {
|
|
150
|
-
method: 'PUT',
|
|
151
|
-
headers: { 'Content-Type': 'application/octet-stream', Authorization: `Bearer ${token}` },
|
|
152
|
-
body: content,
|
|
153
|
-
});
|
|
154
|
-
if (!res.ok) throw apiError(`upload ${path}`, res.status);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Poll until the deploy settles: resolve on `ready`, throw on
|
|
159
|
-
* `error`/`rejected`, throw on timeout. Reuses the bearer minted at the start
|
|
160
|
-
* of the deploy, so a deploy that outlives the token's TTL will start seeing
|
|
161
|
-
* 401s here — those are ignored like any other non-ok read and the loop runs
|
|
162
|
-
* to its timeout rather than failing fast. Acceptable while static deploys
|
|
163
|
-
* finish in seconds; re-mint per poll if that stops being true.
|
|
164
|
-
*/
|
|
165
|
-
async waitUntilReady(deploy: DropResponse, token: string): Promise<void> {
|
|
166
|
-
const deadline = this.timeoutMs / this.pollIntervalMs;
|
|
167
|
-
for (let i = 0; i < deadline; i++) {
|
|
168
|
-
const res = await fetch(`${this.apiBase}/deploys/${deploy.deploy_id}`, {
|
|
169
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
170
|
-
});
|
|
171
|
-
if (res.ok) {
|
|
172
|
-
const state: DeployState = await res.json();
|
|
173
|
-
if (state.state && TERMINAL_STATES.has(state.state)) {
|
|
174
|
-
if (state.state === 'ready') return;
|
|
175
|
-
throw new Error(
|
|
176
|
-
state.error_message ? `deploy failed: ${state.error_message}` : 'deploy failed'
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
await new Promise(r => setTimeout(r, this.pollIntervalMs));
|
|
181
|
-
}
|
|
182
|
-
// Same message the anonymous client uses, so humanizeDropError maps it.
|
|
183
|
-
throw new Error('Deploy did not become ready in time');
|
|
184
|
-
}
|
|
185
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|