@shipstatic/types 2.5.0-beta.21 → 2.5.0-beta.23
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/index.d.ts +134 -113
- package/dist/index.js +118 -92
- package/package.json +1 -1
- package/src/index.ts +146 -118
package/dist/index.d.ts
CHANGED
|
@@ -79,97 +79,6 @@ export interface DeploymentCreateResponse extends Deployment {
|
|
|
79
79
|
/** Claim URL for public deployments. Present when deployed without credentials. */
|
|
80
80
|
readonly claim?: string;
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Every path the public API answers on, declared once.
|
|
84
|
-
*
|
|
85
|
-
* The URL surface was written out in four places — the API's mounts, the
|
|
86
|
-
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
87
|
-
* rename meant finding all four. The first three now read this table.
|
|
88
|
-
*
|
|
89
|
-
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
90
|
-
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
91
|
-
* design, and splitting one list between a registry and literals reads worse
|
|
92
|
-
* than keeping it uniform.
|
|
93
|
-
*
|
|
94
|
-
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
95
|
-
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
96
|
-
* consumed by clients, but the API spells them relative to their mount
|
|
97
|
-
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
98
|
-
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
99
|
-
* any entry names a path no route answers. Some entries have no client yet
|
|
100
|
-
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
101
|
-
* deliberately does not reach); the fence is what keeps those honest rather
|
|
102
|
-
* than merely asserted.
|
|
103
|
-
*
|
|
104
|
-
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
105
|
-
* to `web/my`, for the same reason its row types do: this package is
|
|
106
|
-
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
107
|
-
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
108
|
-
* promise to one dashboard.
|
|
109
|
-
*
|
|
110
|
-
* Item paths are functions rather than templates so the key is interpolated
|
|
111
|
-
* in one place, encoded the same way by every caller.
|
|
112
|
-
*/
|
|
113
|
-
export declare const API_PATHS: {
|
|
114
|
-
readonly DEPLOYMENTS: "/deployments";
|
|
115
|
-
readonly DEPLOYMENT: (deployment: string) => string;
|
|
116
|
-
readonly DEPLOYMENT_CONFIG: (deployment: string) => string;
|
|
117
|
-
readonly DOMAINS: "/domains";
|
|
118
|
-
readonly DOMAIN: (domain: string) => string;
|
|
119
|
-
readonly DOMAIN_VERIFY: (domain: string) => string;
|
|
120
|
-
readonly DOMAIN_DNS: (domain: string) => string;
|
|
121
|
-
readonly DOMAIN_RECORDS: (domain: string) => string;
|
|
122
|
-
readonly DOMAIN_SHARE: (domain: string) => string;
|
|
123
|
-
readonly DOMAIN_PROPAGATION: (domain: string) => string;
|
|
124
|
-
readonly DOMAINS_VALIDATE: "/domains/validate";
|
|
125
|
-
readonly TOKENS: "/tokens";
|
|
126
|
-
readonly TOKEN: (token: string) => string;
|
|
127
|
-
readonly ACCOUNT: "/account";
|
|
128
|
-
readonly ACCOUNT_KEY: "/account/key";
|
|
129
|
-
readonly ACCOUNT_CLAIM: "/account/claim";
|
|
130
|
-
readonly ACTIVITIES: "/activities";
|
|
131
|
-
readonly LABELS: "/labels";
|
|
132
|
-
readonly LIMITS: "/limits";
|
|
133
|
-
readonly PING: "/ping";
|
|
134
|
-
readonly SETUP: "/setup";
|
|
135
|
-
readonly SPA_CHECK: "/spa-check";
|
|
136
|
-
readonly UPLOAD: "/upload";
|
|
137
|
-
};
|
|
138
|
-
/**
|
|
139
|
-
* The deploy request's multipart field names — the other half of the wire
|
|
140
|
-
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
141
|
-
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
142
|
-
*
|
|
143
|
-
* Declared once because the body has three independent WRITERS — the SDK's
|
|
144
|
-
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
145
|
-
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
146
|
-
* and fences its restated copy instead) — and until this export every writer
|
|
147
|
-
* restated the strings the API parses, with nothing comparing them.
|
|
148
|
-
*
|
|
149
|
-
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
150
|
-
* other field is single. The `@internal` flags are serialized as the literal
|
|
151
|
-
* string `'true'` and belong to first-party surfaces only.
|
|
152
|
-
*/
|
|
153
|
-
export declare const DEPLOY_FIELDS: {
|
|
154
|
-
/** One entry per file — read with `getAll`. */
|
|
155
|
-
readonly FILES: "files[]";
|
|
156
|
-
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
157
|
-
readonly CHECKSUMS: "checksums";
|
|
158
|
-
/** JSON array of label strings. */
|
|
159
|
-
readonly LABELS: "labels";
|
|
160
|
-
/** The deploying surface's {@link DeploymentVia} member. */
|
|
161
|
-
readonly VIA: "via";
|
|
162
|
-
/** Plaintext password — the API hashes it server-side. */
|
|
163
|
-
readonly PASSWORD: "password";
|
|
164
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
165
|
-
readonly BUILD: "build";
|
|
166
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
167
|
-
readonly PRERENDER: "prerender";
|
|
168
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
169
|
-
readonly SPA: "spa";
|
|
170
|
-
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
171
|
-
readonly CAPTCHA: "captcha";
|
|
172
|
-
};
|
|
173
82
|
/**
|
|
174
83
|
* The half of a list response that is identical on every list.
|
|
175
84
|
*
|
|
@@ -188,6 +97,28 @@ export interface ListResponse {
|
|
|
188
97
|
/** Opaque cursor from this page; `null` on the last page. */
|
|
189
98
|
cursor: string | null;
|
|
190
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Pagination options for every list endpoint. The response's `cursor` feeds
|
|
102
|
+
* the next request; a `null` cursor means the last page. Omitting both
|
|
103
|
+
* returns the server's default first page.
|
|
104
|
+
*
|
|
105
|
+
* A list answers `{ <collection>, cursor }` and nothing else — `cursor`
|
|
106
|
+
* carries the entire has-more signal, so no redundant boolean, and no
|
|
107
|
+
* `total`. **A count is an aggregate over a collection, not a property of a
|
|
108
|
+
* page:** including one makes every read pay for a full scan it did not ask
|
|
109
|
+
* for, which is precisely the cost keyset pagination exists to avoid.
|
|
110
|
+
*
|
|
111
|
+
* Counts therefore live on the summary resource that owns them —
|
|
112
|
+
* `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
|
|
113
|
+
* platform-wide ones. Ask for a count when you want a count; ask for a page
|
|
114
|
+
* when you want a page.
|
|
115
|
+
*/
|
|
116
|
+
export interface ListOptions {
|
|
117
|
+
/** Maximum number of items to return in one page. */
|
|
118
|
+
limit?: number;
|
|
119
|
+
/** Opaque cursor from the previous page's response. */
|
|
120
|
+
cursor?: string;
|
|
121
|
+
}
|
|
191
122
|
/**
|
|
192
123
|
* Response for listing deployments
|
|
193
124
|
*/
|
|
@@ -658,6 +589,97 @@ export interface AccountOverrides {
|
|
|
658
589
|
/** Override for maximum total deployment size in bytes */
|
|
659
590
|
totalSize?: number;
|
|
660
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Every path the public API answers on, declared once.
|
|
594
|
+
*
|
|
595
|
+
* The URL surface was written out in four places — the API's mounts, the
|
|
596
|
+
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
597
|
+
* rename meant finding all four. The first three now read this table.
|
|
598
|
+
*
|
|
599
|
+
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
600
|
+
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
601
|
+
* design, and splitting one list between a registry and literals reads worse
|
|
602
|
+
* than keeping it uniform.
|
|
603
|
+
*
|
|
604
|
+
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
605
|
+
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
606
|
+
* consumed by clients, but the API spells them relative to their mount
|
|
607
|
+
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
608
|
+
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
609
|
+
* any entry names a path no route answers. Some entries have no client yet
|
|
610
|
+
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
611
|
+
* deliberately does not reach); the fence is what keeps those honest rather
|
|
612
|
+
* than merely asserted.
|
|
613
|
+
*
|
|
614
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
615
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
616
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
617
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
618
|
+
* promise to one dashboard.
|
|
619
|
+
*
|
|
620
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
621
|
+
* in one place, encoded the same way by every caller.
|
|
622
|
+
*/
|
|
623
|
+
export declare const API_PATHS: {
|
|
624
|
+
readonly DEPLOYMENTS: "/deployments";
|
|
625
|
+
readonly DEPLOYMENT: (deployment: string) => string;
|
|
626
|
+
readonly DEPLOYMENT_CONFIG: (deployment: string) => string;
|
|
627
|
+
readonly DOMAINS: "/domains";
|
|
628
|
+
readonly DOMAIN: (domain: string) => string;
|
|
629
|
+
readonly DOMAIN_VERIFY: (domain: string) => string;
|
|
630
|
+
readonly DOMAIN_DNS: (domain: string) => string;
|
|
631
|
+
readonly DOMAIN_RECORDS: (domain: string) => string;
|
|
632
|
+
readonly DOMAIN_SHARE: (domain: string) => string;
|
|
633
|
+
readonly DOMAIN_PROPAGATION: (domain: string) => string;
|
|
634
|
+
readonly DOMAINS_VALIDATE: "/domains/validate";
|
|
635
|
+
readonly TOKENS: "/tokens";
|
|
636
|
+
readonly TOKEN: (token: string) => string;
|
|
637
|
+
readonly ACCOUNT: "/account";
|
|
638
|
+
readonly ACCOUNT_KEY: "/account/key";
|
|
639
|
+
readonly ACCOUNT_CLAIM: "/account/claim";
|
|
640
|
+
readonly ACTIVITIES: "/activities";
|
|
641
|
+
readonly LABELS: "/labels";
|
|
642
|
+
readonly LIMITS: "/limits";
|
|
643
|
+
readonly PING: "/ping";
|
|
644
|
+
readonly SETUP: "/setup";
|
|
645
|
+
readonly SPA_CHECK: "/spa-check";
|
|
646
|
+
readonly UPLOAD: "/upload";
|
|
647
|
+
};
|
|
648
|
+
/**
|
|
649
|
+
* The deploy request's multipart field names — the other half of the wire
|
|
650
|
+
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
651
|
+
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
652
|
+
*
|
|
653
|
+
* Declared once because the body has three independent WRITERS — the SDK's
|
|
654
|
+
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
655
|
+
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
656
|
+
* and fences its restated copy instead) — and until this export every writer
|
|
657
|
+
* restated the strings the API parses, with nothing comparing them.
|
|
658
|
+
*
|
|
659
|
+
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
660
|
+
* other field is single. The `@internal` flags are serialized as the literal
|
|
661
|
+
* string `'true'` and belong to first-party surfaces only.
|
|
662
|
+
*/
|
|
663
|
+
export declare const DEPLOY_FIELDS: {
|
|
664
|
+
/** One entry per file — read with `getAll`. */
|
|
665
|
+
readonly FILES: "files[]";
|
|
666
|
+
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
667
|
+
readonly CHECKSUMS: "checksums";
|
|
668
|
+
/** JSON array of label strings. */
|
|
669
|
+
readonly LABELS: "labels";
|
|
670
|
+
/** The deploying surface's {@link DeploymentVia} member. */
|
|
671
|
+
readonly VIA: "via";
|
|
672
|
+
/** Plaintext password — the API hashes it server-side. */
|
|
673
|
+
readonly PASSWORD: "password";
|
|
674
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
675
|
+
readonly BUILD: "build";
|
|
676
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
677
|
+
readonly PRERENDER: "prerender";
|
|
678
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
679
|
+
readonly SPA: "spa";
|
|
680
|
+
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
681
|
+
readonly CAPTCHA: "captcha";
|
|
682
|
+
};
|
|
661
683
|
/**
|
|
662
684
|
* All possible error types in the ShipStatic platform.
|
|
663
685
|
*
|
|
@@ -690,6 +712,17 @@ export declare const ErrorType: {
|
|
|
690
712
|
readonly Business: "business_logic_error";
|
|
691
713
|
/** API server error (500). Generic server-side fault. */
|
|
692
714
|
readonly Api: "internal_server_error";
|
|
715
|
+
/**
|
|
716
|
+
* The platform is closed for maintenance (503). A deliberate operator
|
|
717
|
+
* state, not a fault — nothing errored; the API is refusing work on
|
|
718
|
+
* purpose, and deployed sites keep serving throughout.
|
|
719
|
+
*
|
|
720
|
+
* Distinct from `Api` at 503, which the platform already uses for a
|
|
721
|
+
* dependency that failed (moderation unavailable). A consumer has to tell
|
|
722
|
+
* "we closed the door" from "something broke": the two get opposite words
|
|
723
|
+
* and opposite retry behaviour.
|
|
724
|
+
*/
|
|
725
|
+
readonly Maintenance: "maintenance";
|
|
693
726
|
/** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
|
|
694
727
|
readonly Network: "network_error";
|
|
695
728
|
/** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
|
|
@@ -790,6 +823,16 @@ export declare class ShipError extends Error {
|
|
|
790
823
|
static file(message: string, details?: unknown): ShipError;
|
|
791
824
|
static config(message: string, details?: unknown): ShipError;
|
|
792
825
|
static api(message: string, status?: number, details?: unknown): ShipError;
|
|
826
|
+
/**
|
|
827
|
+
* The platform is closed for maintenance (503).
|
|
828
|
+
*
|
|
829
|
+
* `message` is REQUIRED and has no default here. The API is the only
|
|
830
|
+
* producer of that sentence, and a default in this file would be a second
|
|
831
|
+
* owner of one fact — see CLAUDE.md, "The Constellation Law" (stopping
|
|
832
|
+
* rule). It is also the one factory whose status is fixed rather than
|
|
833
|
+
* defaulted: a maintenance refusal is 503 or it is not this error.
|
|
834
|
+
*/
|
|
835
|
+
static maintenance(message: string, details?: unknown): ShipError;
|
|
793
836
|
/**
|
|
794
837
|
* The caller is at fault — by HTTP's own definition of a 4xx, or by a type
|
|
795
838
|
* that is client-attributable without ever having a status (`Config`,
|
|
@@ -1309,28 +1352,6 @@ export interface DeploymentUploadOptions {
|
|
|
1309
1352
|
*/
|
|
1310
1353
|
idempotencyKey?: string;
|
|
1311
1354
|
}
|
|
1312
|
-
/**
|
|
1313
|
-
* Pagination options for every list endpoint. The response's `cursor` feeds
|
|
1314
|
-
* the next request; a `null` cursor means the last page. Omitting both
|
|
1315
|
-
* returns the server's default first page.
|
|
1316
|
-
*
|
|
1317
|
-
* A list answers `{ <collection>, cursor }` and nothing else — `cursor`
|
|
1318
|
-
* carries the entire has-more signal, so no redundant boolean, and no
|
|
1319
|
-
* `total`. **A count is an aggregate over a collection, not a property of a
|
|
1320
|
-
* page:** including one makes every read pay for a full scan it did not ask
|
|
1321
|
-
* for, which is precisely the cost keyset pagination exists to avoid.
|
|
1322
|
-
*
|
|
1323
|
-
* Counts therefore live on the summary resource that owns them —
|
|
1324
|
-
* `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
|
|
1325
|
-
* platform-wide ones. Ask for a count when you want a count; ask for a page
|
|
1326
|
-
* when you want a page.
|
|
1327
|
-
*/
|
|
1328
|
-
export interface ListOptions {
|
|
1329
|
-
/** Maximum number of items to return in one page. */
|
|
1330
|
-
limit?: number;
|
|
1331
|
-
/** Opaque cursor from the previous page's response. */
|
|
1332
|
-
cursor?: string;
|
|
1333
|
-
}
|
|
1334
1355
|
/**
|
|
1335
1356
|
* What a caller may change on an existing deployment.
|
|
1336
1357
|
*
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This package is the single source of truth for all shared data structures.
|
|
4
4
|
*/
|
|
5
5
|
// =============================================================================
|
|
6
|
-
//
|
|
6
|
+
// DEPLOYMENT TYPES
|
|
7
7
|
// =============================================================================
|
|
8
8
|
/**
|
|
9
9
|
* Deployment status constants
|
|
@@ -35,97 +35,6 @@ export const DeploymentVia = {
|
|
|
35
35
|
GPT: 'gpt',
|
|
36
36
|
VSC: 'vsc',
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Every path the public API answers on, declared once.
|
|
40
|
-
*
|
|
41
|
-
* The URL surface was written out in four places — the API's mounts, the
|
|
42
|
-
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
43
|
-
* rename meant finding all four. The first three now read this table.
|
|
44
|
-
*
|
|
45
|
-
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
46
|
-
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
47
|
-
* design, and splitting one list between a registry and literals reads worse
|
|
48
|
-
* than keeping it uniform.
|
|
49
|
-
*
|
|
50
|
-
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
51
|
-
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
52
|
-
* consumed by clients, but the API spells them relative to their mount
|
|
53
|
-
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
54
|
-
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
55
|
-
* any entry names a path no route answers. Some entries have no client yet
|
|
56
|
-
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
57
|
-
* deliberately does not reach); the fence is what keeps those honest rather
|
|
58
|
-
* than merely asserted.
|
|
59
|
-
*
|
|
60
|
-
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
61
|
-
* to `web/my`, for the same reason its row types do: this package is
|
|
62
|
-
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
63
|
-
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
64
|
-
* promise to one dashboard.
|
|
65
|
-
*
|
|
66
|
-
* Item paths are functions rather than templates so the key is interpolated
|
|
67
|
-
* in one place, encoded the same way by every caller.
|
|
68
|
-
*/
|
|
69
|
-
export const API_PATHS = {
|
|
70
|
-
DEPLOYMENTS: '/deployments',
|
|
71
|
-
DEPLOYMENT: (deployment) => `/deployments/${deployment}`,
|
|
72
|
-
DEPLOYMENT_CONFIG: (deployment) => `/deployments/${deployment}/config`,
|
|
73
|
-
DOMAINS: '/domains',
|
|
74
|
-
DOMAIN: (domain) => `/domains/${domain}`,
|
|
75
|
-
DOMAIN_VERIFY: (domain) => `/domains/${domain}/verify`,
|
|
76
|
-
DOMAIN_DNS: (domain) => `/domains/${domain}/dns`,
|
|
77
|
-
DOMAIN_RECORDS: (domain) => `/domains/${domain}/records`,
|
|
78
|
-
DOMAIN_SHARE: (domain) => `/domains/${domain}/share`,
|
|
79
|
-
DOMAIN_PROPAGATION: (domain) => `/domains/${domain}/propagation`,
|
|
80
|
-
DOMAINS_VALIDATE: '/domains/validate',
|
|
81
|
-
TOKENS: '/tokens',
|
|
82
|
-
TOKEN: (token) => `/tokens/${token}`,
|
|
83
|
-
ACCOUNT: '/account',
|
|
84
|
-
ACCOUNT_KEY: '/account/key',
|
|
85
|
-
ACCOUNT_CLAIM: '/account/claim',
|
|
86
|
-
ACTIVITIES: '/activities',
|
|
87
|
-
LABELS: '/labels',
|
|
88
|
-
LIMITS: '/limits',
|
|
89
|
-
PING: '/ping',
|
|
90
|
-
SETUP: '/setup',
|
|
91
|
-
SPA_CHECK: '/spa-check',
|
|
92
|
-
UPLOAD: '/upload',
|
|
93
|
-
};
|
|
94
|
-
/**
|
|
95
|
-
* The deploy request's multipart field names — the other half of the wire
|
|
96
|
-
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
97
|
-
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
98
|
-
*
|
|
99
|
-
* Declared once because the body has three independent WRITERS — the SDK's
|
|
100
|
-
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
101
|
-
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
102
|
-
* and fences its restated copy instead) — and until this export every writer
|
|
103
|
-
* restated the strings the API parses, with nothing comparing them.
|
|
104
|
-
*
|
|
105
|
-
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
106
|
-
* other field is single. The `@internal` flags are serialized as the literal
|
|
107
|
-
* string `'true'` and belong to first-party surfaces only.
|
|
108
|
-
*/
|
|
109
|
-
export const DEPLOY_FIELDS = {
|
|
110
|
-
/** One entry per file — read with `getAll`. */
|
|
111
|
-
FILES: 'files[]',
|
|
112
|
-
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
113
|
-
CHECKSUMS: 'checksums',
|
|
114
|
-
/** JSON array of label strings. */
|
|
115
|
-
LABELS: 'labels',
|
|
116
|
-
/** The deploying surface's {@link DeploymentVia} member. */
|
|
117
|
-
VIA: 'via',
|
|
118
|
-
/** Plaintext password — the API hashes it server-side. */
|
|
119
|
-
PASSWORD: 'password',
|
|
120
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
121
|
-
BUILD: 'build',
|
|
122
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
123
|
-
PRERENDER: 'prerender',
|
|
124
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
125
|
-
SPA: 'spa',
|
|
126
|
-
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
127
|
-
CAPTCHA: 'captcha',
|
|
128
|
-
};
|
|
129
38
|
// =============================================================================
|
|
130
39
|
// DOMAIN TYPES
|
|
131
40
|
// =============================================================================
|
|
@@ -221,6 +130,100 @@ export const AccountPlan = {
|
|
|
221
130
|
TERMINATED: 'terminated',
|
|
222
131
|
};
|
|
223
132
|
// =============================================================================
|
|
133
|
+
// WIRE SURFACE
|
|
134
|
+
// =============================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Every path the public API answers on, declared once.
|
|
137
|
+
*
|
|
138
|
+
* The URL surface was written out in four places — the API's mounts, the
|
|
139
|
+
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
140
|
+
* rename meant finding all four. The first three now read this table.
|
|
141
|
+
*
|
|
142
|
+
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
143
|
+
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
144
|
+
* design, and splitting one list between a registry and literals reads worse
|
|
145
|
+
* than keeping it uniform.
|
|
146
|
+
*
|
|
147
|
+
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
148
|
+
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
149
|
+
* consumed by clients, but the API spells them relative to their mount
|
|
150
|
+
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
151
|
+
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
152
|
+
* any entry names a path no route answers. Some entries have no client yet
|
|
153
|
+
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
154
|
+
* deliberately does not reach); the fence is what keeps those honest rather
|
|
155
|
+
* than merely asserted.
|
|
156
|
+
*
|
|
157
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
158
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
159
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
160
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
161
|
+
* promise to one dashboard.
|
|
162
|
+
*
|
|
163
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
164
|
+
* in one place, encoded the same way by every caller.
|
|
165
|
+
*/
|
|
166
|
+
export const API_PATHS = {
|
|
167
|
+
DEPLOYMENTS: '/deployments',
|
|
168
|
+
DEPLOYMENT: (deployment) => `/deployments/${deployment}`,
|
|
169
|
+
DEPLOYMENT_CONFIG: (deployment) => `/deployments/${deployment}/config`,
|
|
170
|
+
DOMAINS: '/domains',
|
|
171
|
+
DOMAIN: (domain) => `/domains/${domain}`,
|
|
172
|
+
DOMAIN_VERIFY: (domain) => `/domains/${domain}/verify`,
|
|
173
|
+
DOMAIN_DNS: (domain) => `/domains/${domain}/dns`,
|
|
174
|
+
DOMAIN_RECORDS: (domain) => `/domains/${domain}/records`,
|
|
175
|
+
DOMAIN_SHARE: (domain) => `/domains/${domain}/share`,
|
|
176
|
+
DOMAIN_PROPAGATION: (domain) => `/domains/${domain}/propagation`,
|
|
177
|
+
DOMAINS_VALIDATE: '/domains/validate',
|
|
178
|
+
TOKENS: '/tokens',
|
|
179
|
+
TOKEN: (token) => `/tokens/${token}`,
|
|
180
|
+
ACCOUNT: '/account',
|
|
181
|
+
ACCOUNT_KEY: '/account/key',
|
|
182
|
+
ACCOUNT_CLAIM: '/account/claim',
|
|
183
|
+
ACTIVITIES: '/activities',
|
|
184
|
+
LABELS: '/labels',
|
|
185
|
+
LIMITS: '/limits',
|
|
186
|
+
PING: '/ping',
|
|
187
|
+
SETUP: '/setup',
|
|
188
|
+
SPA_CHECK: '/spa-check',
|
|
189
|
+
UPLOAD: '/upload',
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* The deploy request's multipart field names — the other half of the wire
|
|
193
|
+
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
194
|
+
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
195
|
+
*
|
|
196
|
+
* Declared once because the body has three independent WRITERS — the SDK's
|
|
197
|
+
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
198
|
+
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
199
|
+
* and fences its restated copy instead) — and until this export every writer
|
|
200
|
+
* restated the strings the API parses, with nothing comparing them.
|
|
201
|
+
*
|
|
202
|
+
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
203
|
+
* other field is single. The `@internal` flags are serialized as the literal
|
|
204
|
+
* string `'true'` and belong to first-party surfaces only.
|
|
205
|
+
*/
|
|
206
|
+
export const DEPLOY_FIELDS = {
|
|
207
|
+
/** One entry per file — read with `getAll`. */
|
|
208
|
+
FILES: 'files[]',
|
|
209
|
+
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
210
|
+
CHECKSUMS: 'checksums',
|
|
211
|
+
/** JSON array of label strings. */
|
|
212
|
+
LABELS: 'labels',
|
|
213
|
+
/** The deploying surface's {@link DeploymentVia} member. */
|
|
214
|
+
VIA: 'via',
|
|
215
|
+
/** Plaintext password — the API hashes it server-side. */
|
|
216
|
+
PASSWORD: 'password',
|
|
217
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
218
|
+
BUILD: 'build',
|
|
219
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
220
|
+
PRERENDER: 'prerender',
|
|
221
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
222
|
+
SPA: 'spa',
|
|
223
|
+
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
224
|
+
CAPTCHA: 'captcha',
|
|
225
|
+
};
|
|
226
|
+
// =============================================================================
|
|
224
227
|
// ERROR SYSTEM
|
|
225
228
|
// =============================================================================
|
|
226
229
|
/**
|
|
@@ -255,6 +258,17 @@ export const ErrorType = {
|
|
|
255
258
|
Business: 'business_logic_error',
|
|
256
259
|
/** API server error (500). Generic server-side fault. */
|
|
257
260
|
Api: 'internal_server_error',
|
|
261
|
+
/**
|
|
262
|
+
* The platform is closed for maintenance (503). A deliberate operator
|
|
263
|
+
* state, not a fault — nothing errored; the API is refusing work on
|
|
264
|
+
* purpose, and deployed sites keep serving throughout.
|
|
265
|
+
*
|
|
266
|
+
* Distinct from `Api` at 503, which the platform already uses for a
|
|
267
|
+
* dependency that failed (moderation unavailable). A consumer has to tell
|
|
268
|
+
* "we closed the door" from "something broke": the two get opposite words
|
|
269
|
+
* and opposite retry behaviour.
|
|
270
|
+
*/
|
|
271
|
+
Maintenance: 'maintenance',
|
|
258
272
|
/** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
|
|
259
273
|
Network: 'network_error',
|
|
260
274
|
/** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
|
|
@@ -559,6 +573,18 @@ export class ShipError extends Error {
|
|
|
559
573
|
static api(message, status = 500, details) {
|
|
560
574
|
return new ShipError(ErrorType.Api, message, status, details);
|
|
561
575
|
}
|
|
576
|
+
/**
|
|
577
|
+
* The platform is closed for maintenance (503).
|
|
578
|
+
*
|
|
579
|
+
* `message` is REQUIRED and has no default here. The API is the only
|
|
580
|
+
* producer of that sentence, and a default in this file would be a second
|
|
581
|
+
* owner of one fact — see CLAUDE.md, "The Constellation Law" (stopping
|
|
582
|
+
* rule). It is also the one factory whose status is fixed rather than
|
|
583
|
+
* defaulted: a maintenance refusal is 503 or it is not this error.
|
|
584
|
+
*/
|
|
585
|
+
static maintenance(message, details) {
|
|
586
|
+
return new ShipError(ErrorType.Maintenance, message, 503, details);
|
|
587
|
+
}
|
|
562
588
|
// Semantic-category guards. For specific-type checks, use
|
|
563
589
|
// `error.type === ErrorType.X` directly or the generic `isType(t)`.
|
|
564
590
|
/**
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// =============================================================================
|
|
7
|
-
//
|
|
7
|
+
// DEPLOYMENT TYPES
|
|
8
8
|
// =============================================================================
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -90,99 +90,6 @@ export interface DeploymentCreateResponse extends Deployment {
|
|
|
90
90
|
readonly claim?: string;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
/**
|
|
94
|
-
* Every path the public API answers on, declared once.
|
|
95
|
-
*
|
|
96
|
-
* The URL surface was written out in four places — the API's mounts, the
|
|
97
|
-
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
98
|
-
* rename meant finding all four. The first three now read this table.
|
|
99
|
-
*
|
|
100
|
-
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
101
|
-
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
102
|
-
* design, and splitting one list between a registry and literals reads worse
|
|
103
|
-
* than keeping it uniform.
|
|
104
|
-
*
|
|
105
|
-
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
106
|
-
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
107
|
-
* consumed by clients, but the API spells them relative to their mount
|
|
108
|
-
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
109
|
-
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
110
|
-
* any entry names a path no route answers. Some entries have no client yet
|
|
111
|
-
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
112
|
-
* deliberately does not reach); the fence is what keeps those honest rather
|
|
113
|
-
* than merely asserted.
|
|
114
|
-
*
|
|
115
|
-
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
116
|
-
* to `web/my`, for the same reason its row types do: this package is
|
|
117
|
-
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
118
|
-
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
119
|
-
* promise to one dashboard.
|
|
120
|
-
*
|
|
121
|
-
* Item paths are functions rather than templates so the key is interpolated
|
|
122
|
-
* in one place, encoded the same way by every caller.
|
|
123
|
-
*/
|
|
124
|
-
export const API_PATHS = {
|
|
125
|
-
DEPLOYMENTS: '/deployments',
|
|
126
|
-
DEPLOYMENT: (deployment: string) => `/deployments/${deployment}`,
|
|
127
|
-
DEPLOYMENT_CONFIG: (deployment: string) => `/deployments/${deployment}/config`,
|
|
128
|
-
DOMAINS: '/domains',
|
|
129
|
-
DOMAIN: (domain: string) => `/domains/${domain}`,
|
|
130
|
-
DOMAIN_VERIFY: (domain: string) => `/domains/${domain}/verify`,
|
|
131
|
-
DOMAIN_DNS: (domain: string) => `/domains/${domain}/dns`,
|
|
132
|
-
DOMAIN_RECORDS: (domain: string) => `/domains/${domain}/records`,
|
|
133
|
-
DOMAIN_SHARE: (domain: string) => `/domains/${domain}/share`,
|
|
134
|
-
DOMAIN_PROPAGATION: (domain: string) => `/domains/${domain}/propagation`,
|
|
135
|
-
DOMAINS_VALIDATE: '/domains/validate',
|
|
136
|
-
TOKENS: '/tokens',
|
|
137
|
-
TOKEN: (token: string) => `/tokens/${token}`,
|
|
138
|
-
ACCOUNT: '/account',
|
|
139
|
-
ACCOUNT_KEY: '/account/key',
|
|
140
|
-
ACCOUNT_CLAIM: '/account/claim',
|
|
141
|
-
ACTIVITIES: '/activities',
|
|
142
|
-
LABELS: '/labels',
|
|
143
|
-
LIMITS: '/limits',
|
|
144
|
-
PING: '/ping',
|
|
145
|
-
SETUP: '/setup',
|
|
146
|
-
SPA_CHECK: '/spa-check',
|
|
147
|
-
UPLOAD: '/upload',
|
|
148
|
-
} as const;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* The deploy request's multipart field names — the other half of the wire
|
|
152
|
-
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
153
|
-
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
154
|
-
*
|
|
155
|
-
* Declared once because the body has three independent WRITERS — the SDK's
|
|
156
|
-
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
157
|
-
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
158
|
-
* and fences its restated copy instead) — and until this export every writer
|
|
159
|
-
* restated the strings the API parses, with nothing comparing them.
|
|
160
|
-
*
|
|
161
|
-
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
162
|
-
* other field is single. The `@internal` flags are serialized as the literal
|
|
163
|
-
* string `'true'` and belong to first-party surfaces only.
|
|
164
|
-
*/
|
|
165
|
-
export const DEPLOY_FIELDS = {
|
|
166
|
-
/** One entry per file — read with `getAll`. */
|
|
167
|
-
FILES: 'files[]',
|
|
168
|
-
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
169
|
-
CHECKSUMS: 'checksums',
|
|
170
|
-
/** JSON array of label strings. */
|
|
171
|
-
LABELS: 'labels',
|
|
172
|
-
/** The deploying surface's {@link DeploymentVia} member. */
|
|
173
|
-
VIA: 'via',
|
|
174
|
-
/** Plaintext password — the API hashes it server-side. */
|
|
175
|
-
PASSWORD: 'password',
|
|
176
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
177
|
-
BUILD: 'build',
|
|
178
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
179
|
-
PRERENDER: 'prerender',
|
|
180
|
-
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
181
|
-
SPA: 'spa',
|
|
182
|
-
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
183
|
-
CAPTCHA: 'captcha',
|
|
184
|
-
} as const;
|
|
185
|
-
|
|
186
93
|
/**
|
|
187
94
|
* The half of a list response that is identical on every list.
|
|
188
95
|
*
|
|
@@ -202,6 +109,29 @@ export interface ListResponse {
|
|
|
202
109
|
cursor: string | null;
|
|
203
110
|
}
|
|
204
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Pagination options for every list endpoint. The response's `cursor` feeds
|
|
114
|
+
* the next request; a `null` cursor means the last page. Omitting both
|
|
115
|
+
* returns the server's default first page.
|
|
116
|
+
*
|
|
117
|
+
* A list answers `{ <collection>, cursor }` and nothing else — `cursor`
|
|
118
|
+
* carries the entire has-more signal, so no redundant boolean, and no
|
|
119
|
+
* `total`. **A count is an aggregate over a collection, not a property of a
|
|
120
|
+
* page:** including one makes every read pay for a full scan it did not ask
|
|
121
|
+
* for, which is precisely the cost keyset pagination exists to avoid.
|
|
122
|
+
*
|
|
123
|
+
* Counts therefore live on the summary resource that owns them —
|
|
124
|
+
* `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
|
|
125
|
+
* platform-wide ones. Ask for a count when you want a count; ask for a page
|
|
126
|
+
* when you want a page.
|
|
127
|
+
*/
|
|
128
|
+
export interface ListOptions {
|
|
129
|
+
/** Maximum number of items to return in one page. */
|
|
130
|
+
limit?: number;
|
|
131
|
+
/** Opaque cursor from the previous page's response. */
|
|
132
|
+
cursor?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
205
135
|
/**
|
|
206
136
|
* Response for listing deployments
|
|
207
137
|
*/
|
|
@@ -739,6 +669,103 @@ export interface AccountOverrides {
|
|
|
739
669
|
totalSize?: number;
|
|
740
670
|
}
|
|
741
671
|
|
|
672
|
+
// =============================================================================
|
|
673
|
+
// WIRE SURFACE
|
|
674
|
+
// =============================================================================
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Every path the public API answers on, declared once.
|
|
678
|
+
*
|
|
679
|
+
* The URL surface was written out in four places — the API's mounts, the
|
|
680
|
+
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
681
|
+
* rename meant finding all four. The first three now read this table.
|
|
682
|
+
*
|
|
683
|
+
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
684
|
+
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
685
|
+
* design, and splitting one list between a registry and literals reads worse
|
|
686
|
+
* than keeping it uniform.
|
|
687
|
+
*
|
|
688
|
+
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
689
|
+
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
690
|
+
* consumed by clients, but the API spells them relative to their mount
|
|
691
|
+
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
692
|
+
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
693
|
+
* any entry names a path no route answers. Some entries have no client yet
|
|
694
|
+
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
695
|
+
* deliberately does not reach); the fence is what keeps those honest rather
|
|
696
|
+
* than merely asserted.
|
|
697
|
+
*
|
|
698
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
699
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
700
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
701
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
702
|
+
* promise to one dashboard.
|
|
703
|
+
*
|
|
704
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
705
|
+
* in one place, encoded the same way by every caller.
|
|
706
|
+
*/
|
|
707
|
+
export const API_PATHS = {
|
|
708
|
+
DEPLOYMENTS: '/deployments',
|
|
709
|
+
DEPLOYMENT: (deployment: string) => `/deployments/${deployment}`,
|
|
710
|
+
DEPLOYMENT_CONFIG: (deployment: string) => `/deployments/${deployment}/config`,
|
|
711
|
+
DOMAINS: '/domains',
|
|
712
|
+
DOMAIN: (domain: string) => `/domains/${domain}`,
|
|
713
|
+
DOMAIN_VERIFY: (domain: string) => `/domains/${domain}/verify`,
|
|
714
|
+
DOMAIN_DNS: (domain: string) => `/domains/${domain}/dns`,
|
|
715
|
+
DOMAIN_RECORDS: (domain: string) => `/domains/${domain}/records`,
|
|
716
|
+
DOMAIN_SHARE: (domain: string) => `/domains/${domain}/share`,
|
|
717
|
+
DOMAIN_PROPAGATION: (domain: string) => `/domains/${domain}/propagation`,
|
|
718
|
+
DOMAINS_VALIDATE: '/domains/validate',
|
|
719
|
+
TOKENS: '/tokens',
|
|
720
|
+
TOKEN: (token: string) => `/tokens/${token}`,
|
|
721
|
+
ACCOUNT: '/account',
|
|
722
|
+
ACCOUNT_KEY: '/account/key',
|
|
723
|
+
ACCOUNT_CLAIM: '/account/claim',
|
|
724
|
+
ACTIVITIES: '/activities',
|
|
725
|
+
LABELS: '/labels',
|
|
726
|
+
LIMITS: '/limits',
|
|
727
|
+
PING: '/ping',
|
|
728
|
+
SETUP: '/setup',
|
|
729
|
+
SPA_CHECK: '/spa-check',
|
|
730
|
+
UPLOAD: '/upload',
|
|
731
|
+
} as const;
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* The deploy request's multipart field names — the other half of the wire
|
|
735
|
+
* surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
|
|
736
|
+
* `/upload`) is multipart/form-data, and these are the names the API reads.
|
|
737
|
+
*
|
|
738
|
+
* Declared once because the body has three independent WRITERS — the SDK's
|
|
739
|
+
* Node and browser body builders, and the n8n community node's hand-rolled
|
|
740
|
+
* client (which cannot import this under n8n Cloud's zero-dependency rule,
|
|
741
|
+
* and fences its restated copy instead) — and until this export every writer
|
|
742
|
+
* restated the strings the API parses, with nothing comparing them.
|
|
743
|
+
*
|
|
744
|
+
* `FILES` carries one entry per file (the API reads it with `getAll`); every
|
|
745
|
+
* other field is single. The `@internal` flags are serialized as the literal
|
|
746
|
+
* string `'true'` and belong to first-party surfaces only.
|
|
747
|
+
*/
|
|
748
|
+
export const DEPLOY_FIELDS = {
|
|
749
|
+
/** One entry per file — read with `getAll`. */
|
|
750
|
+
FILES: 'files[]',
|
|
751
|
+
/** JSON array of MD5 hex digests, index-aligned with `FILES`. */
|
|
752
|
+
CHECKSUMS: 'checksums',
|
|
753
|
+
/** JSON array of label strings. */
|
|
754
|
+
LABELS: 'labels',
|
|
755
|
+
/** The deploying surface's {@link DeploymentVia} member. */
|
|
756
|
+
VIA: 'via',
|
|
757
|
+
/** Plaintext password — the API hashes it server-side. */
|
|
758
|
+
PASSWORD: 'password',
|
|
759
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
760
|
+
BUILD: 'build',
|
|
761
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
762
|
+
PRERENDER: 'prerender',
|
|
763
|
+
/** @internal Server-processing flag — first-party `/upload` only. */
|
|
764
|
+
SPA: 'spa',
|
|
765
|
+
/** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
|
|
766
|
+
CAPTCHA: 'captcha',
|
|
767
|
+
} as const;
|
|
768
|
+
|
|
742
769
|
// =============================================================================
|
|
743
770
|
// ERROR SYSTEM
|
|
744
771
|
// =============================================================================
|
|
@@ -775,6 +802,17 @@ export const ErrorType = {
|
|
|
775
802
|
Business: 'business_logic_error',
|
|
776
803
|
/** API server error (500). Generic server-side fault. */
|
|
777
804
|
Api: 'internal_server_error',
|
|
805
|
+
/**
|
|
806
|
+
* The platform is closed for maintenance (503). A deliberate operator
|
|
807
|
+
* state, not a fault — nothing errored; the API is refusing work on
|
|
808
|
+
* purpose, and deployed sites keep serving throughout.
|
|
809
|
+
*
|
|
810
|
+
* Distinct from `Api` at 503, which the platform already uses for a
|
|
811
|
+
* dependency that failed (moderation unavailable). A consumer has to tell
|
|
812
|
+
* "we closed the door" from "something broke": the two get opposite words
|
|
813
|
+
* and opposite retry behaviour.
|
|
814
|
+
*/
|
|
815
|
+
Maintenance: 'maintenance',
|
|
778
816
|
/** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
|
|
779
817
|
Network: 'network_error',
|
|
780
818
|
/** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
|
|
@@ -1124,6 +1162,19 @@ export class ShipError extends Error {
|
|
|
1124
1162
|
return new ShipError(ErrorType.Api, message, status, details);
|
|
1125
1163
|
}
|
|
1126
1164
|
|
|
1165
|
+
/**
|
|
1166
|
+
* The platform is closed for maintenance (503).
|
|
1167
|
+
*
|
|
1168
|
+
* `message` is REQUIRED and has no default here. The API is the only
|
|
1169
|
+
* producer of that sentence, and a default in this file would be a second
|
|
1170
|
+
* owner of one fact — see CLAUDE.md, "The Constellation Law" (stopping
|
|
1171
|
+
* rule). It is also the one factory whose status is fixed rather than
|
|
1172
|
+
* defaulted: a maintenance refusal is 503 or it is not this error.
|
|
1173
|
+
*/
|
|
1174
|
+
static maintenance(message: string, details?: unknown): ShipError {
|
|
1175
|
+
return new ShipError(ErrorType.Maintenance, message, 503, details);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1127
1178
|
// Semantic-category guards. For specific-type checks, use
|
|
1128
1179
|
// `error.type === ErrorType.X` directly or the generic `isType(t)`.
|
|
1129
1180
|
|
|
@@ -1179,7 +1230,7 @@ export function isShipError(error: unknown): error is ShipError {
|
|
|
1179
1230
|
}
|
|
1180
1231
|
|
|
1181
1232
|
// =============================================================================
|
|
1182
|
-
//
|
|
1233
|
+
// PLATFORM LIMITS
|
|
1183
1234
|
// =============================================================================
|
|
1184
1235
|
|
|
1185
1236
|
/**
|
|
@@ -2007,29 +2058,6 @@ export interface DeploymentUploadOptions {
|
|
|
2007
2058
|
idempotencyKey?: string;
|
|
2008
2059
|
}
|
|
2009
2060
|
|
|
2010
|
-
/**
|
|
2011
|
-
* Pagination options for every list endpoint. The response's `cursor` feeds
|
|
2012
|
-
* the next request; a `null` cursor means the last page. Omitting both
|
|
2013
|
-
* returns the server's default first page.
|
|
2014
|
-
*
|
|
2015
|
-
* A list answers `{ <collection>, cursor }` and nothing else — `cursor`
|
|
2016
|
-
* carries the entire has-more signal, so no redundant boolean, and no
|
|
2017
|
-
* `total`. **A count is an aggregate over a collection, not a property of a
|
|
2018
|
-
* page:** including one makes every read pay for a full scan it did not ask
|
|
2019
|
-
* for, which is precisely the cost keyset pagination exists to avoid.
|
|
2020
|
-
*
|
|
2021
|
-
* Counts therefore live on the summary resource that owns them —
|
|
2022
|
-
* `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
|
|
2023
|
-
* platform-wide ones. Ask for a count when you want a count; ask for a page
|
|
2024
|
-
* when you want a page.
|
|
2025
|
-
*/
|
|
2026
|
-
export interface ListOptions {
|
|
2027
|
-
/** Maximum number of items to return in one page. */
|
|
2028
|
-
limit?: number;
|
|
2029
|
-
/** Opaque cursor from the previous page's response. */
|
|
2030
|
-
cursor?: string;
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
2061
|
/**
|
|
2034
2062
|
* What a caller may change on an existing deployment.
|
|
2035
2063
|
*
|