@forgedevv/shared 0.1.0 → 0.3.0
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/CHANGELOG.md +14 -0
- package/dist/api.d.ts +39 -4
- package/dist/api.js +48 -5
- package/dist/constants.d.ts +5 -2
- package/dist/constants.js +5 -2
- package/dist/db.d.ts +27 -0
- package/dist/db.js +39 -0
- package/dist/web-client.d.ts +35 -1
- package/dist/web-client.js +15 -0
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog — @forge/shared
|
|
2
|
+
|
|
3
|
+
All notable changes to `@forge/shared`, published on npm as `@forgedevv/shared` together with
|
|
4
|
+
`@forgedevv/core` (same version). Versions follow semantic versioning. Changes before 0.3.0 are
|
|
5
|
+
listed in the `@forge/core` changelog.
|
|
6
|
+
|
|
7
|
+
## 0.3.0 — 2026-10-17
|
|
8
|
+
|
|
9
|
+
### Changed (Jupiter fixes)
|
|
10
|
+
|
|
11
|
+
- `FEES.jupiterIntegratorFeeBps` is 50 bps, was 30. It is the Jupiter Plugin `referralFee` after
|
|
12
|
+
graduation; Jupiter Ultra refuses any value outside 50..255 bps (checked by `@forge/core`
|
|
13
|
+
`assertJupiterReferralFeeBps`), and keeps 20% of it. `FEES.platformFeeBps` (30 bps, FORGE's own
|
|
14
|
+
buy button) is unchanged.
|
package/dist/api.d.ts
CHANGED
|
@@ -97,6 +97,10 @@ export declare const WEB_API_ROUTES: {
|
|
|
97
97
|
readonly method: "POST";
|
|
98
98
|
readonly path: "/api/launchpads/:id/reactivate";
|
|
99
99
|
};
|
|
100
|
+
readonly launchpadRetry: {
|
|
101
|
+
readonly method: "POST";
|
|
102
|
+
readonly path: "/api/launchpads/:id/retry";
|
|
103
|
+
};
|
|
100
104
|
readonly rpc: {
|
|
101
105
|
readonly method: "POST";
|
|
102
106
|
readonly path: "/api/rpc";
|
|
@@ -145,6 +149,7 @@ export declare const GatingResponse: z.ZodObject<{
|
|
|
145
149
|
required: z.ZodString;
|
|
146
150
|
balance: z.ZodString;
|
|
147
151
|
enabled: z.ZodBoolean;
|
|
152
|
+
decimals: z.ZodOptional<z.ZodNumber>;
|
|
148
153
|
}, z.core.$strip>;
|
|
149
154
|
export type GatingResponse = z.infer<typeof GatingResponse>;
|
|
150
155
|
export declare const FlagsResponse: z.ZodObject<{
|
|
@@ -206,6 +211,10 @@ export declare const LaunchpadModificationResponse: z.ZodObject<{
|
|
|
206
211
|
jobId: z.ZodUUID;
|
|
207
212
|
}, z.core.$strip>;
|
|
208
213
|
export type LaunchpadModificationResponse = z.infer<typeof LaunchpadModificationResponse>;
|
|
214
|
+
export declare const LaunchpadRetryResponse: z.ZodObject<{
|
|
215
|
+
jobId: z.ZodUUID;
|
|
216
|
+
}, z.core.$strip>;
|
|
217
|
+
export type LaunchpadRetryResponse = z.infer<typeof LaunchpadRetryResponse>;
|
|
209
218
|
export declare const PaymentsQuoteRequest: z.ZodObject<{
|
|
210
219
|
jobId: z.ZodUUID;
|
|
211
220
|
kind: z.ZodEnum<{
|
|
@@ -368,17 +377,43 @@ export declare const RpcResponse: z.ZodObject<{
|
|
|
368
377
|
}, z.core.$strip>>;
|
|
369
378
|
}, z.core.$strip>;
|
|
370
379
|
export type RpcResponse = z.infer<typeof RpcResponse>;
|
|
371
|
-
/**
|
|
380
|
+
/** Lowercase hex HMAC-SHA256 computed with SIGNER_HMAC_SECRET over `signerSignedPayload(...)`. */
|
|
372
381
|
export declare const SIGNER_SIGNATURE_HEADER = "X-Forge-Signature";
|
|
373
382
|
/** Unix time in seconds, as a decimal string. */
|
|
374
383
|
export declare const SIGNER_TIMESTAMP_HEADER = "X-Forge-Timestamp";
|
|
384
|
+
/**
|
|
385
|
+
* 16 random bytes as 32 lowercase hex characters, fresh for every request (and every retry). The
|
|
386
|
+
* signer accepts a nonce once within the clock-skew window.
|
|
387
|
+
*/
|
|
388
|
+
export declare const SIGNER_NONCE_HEADER = "X-Forge-Nonce";
|
|
375
389
|
/** Requests whose timestamp differs from the signer clock by more than this are rejected. */
|
|
376
390
|
export declare const SIGNER_MAX_CLOCK_SKEW_SECONDS = 60;
|
|
391
|
+
/** First line of the signed string. Any change to its layout gets a new tag. */
|
|
392
|
+
export declare const SIGNER_SIGNATURE_VERSION = "forge-signer-v2";
|
|
393
|
+
/** The request fields covered by the signer HMAC. */
|
|
394
|
+
export interface SignerSignedFields {
|
|
395
|
+
/** HTTP method, uppercase (`POST`). */
|
|
396
|
+
method: string;
|
|
397
|
+
/** Request target exactly as sent: the path plus the query string (`/v1/configs?a=1`). */
|
|
398
|
+
path: string;
|
|
399
|
+
/** Same value as the timestamp header. */
|
|
400
|
+
timestamp: string;
|
|
401
|
+
/** Same value as the nonce header. */
|
|
402
|
+
nonce: string;
|
|
403
|
+
/** Lowercase hex SHA-256 of the raw body bytes (an empty body hashes zero bytes). */
|
|
404
|
+
bodySha256: string;
|
|
405
|
+
}
|
|
377
406
|
/**
|
|
378
|
-
* Exact string fed to HMAC-SHA256
|
|
379
|
-
*
|
|
407
|
+
* Exact string fed to HMAC-SHA256, one field per line, in this order:
|
|
408
|
+
*
|
|
409
|
+
* forge-signer-v2\n<METHOD>\n<path?query>\n<timestamp>\n<nonce>\n<body sha256>
|
|
410
|
+
*
|
|
411
|
+
* Every field has a strict format that excludes the line feed, and the field count is fixed, so
|
|
412
|
+
* the string decodes to exactly one tuple: a signature made for one method, route, query, time,
|
|
413
|
+
* nonce or body is worth nothing for any other. Throws on a field outside its format, so neither
|
|
414
|
+
* side can sign or check an ambiguous string.
|
|
380
415
|
*/
|
|
381
|
-
export declare function signerSignedPayload(
|
|
416
|
+
export declare function signerSignedPayload(fields: SignerSignedFields): string;
|
|
382
417
|
export declare const SIGNER_ROUTES: {
|
|
383
418
|
readonly configs: {
|
|
384
419
|
readonly method: "POST";
|
package/dist/api.js
CHANGED
|
@@ -51,6 +51,7 @@ export const WEB_API_ROUTES = {
|
|
|
51
51
|
launchpadGet: { method: 'GET', path: '/api/launchpads/:id' },
|
|
52
52
|
claimTransaction: { method: 'GET', path: '/api/launchpads/:id/claim-transaction' },
|
|
53
53
|
launchpadReactivate: { method: 'POST', path: '/api/launchpads/:id/reactivate' },
|
|
54
|
+
launchpadRetry: { method: 'POST', path: '/api/launchpads/:id/retry' },
|
|
54
55
|
rpc: { method: 'POST', path: '/api/rpc' },
|
|
55
56
|
};
|
|
56
57
|
// POST /api/auth/nonce
|
|
@@ -90,6 +91,8 @@ export const GatingResponse = z.object({
|
|
|
90
91
|
/** Wallet raw balance (smallest units). */
|
|
91
92
|
balance: RawTokenAmount,
|
|
92
93
|
enabled: z.boolean(),
|
|
94
|
+
/** Decimals of the $FORGE mint, read on-chain with the balance; absent when nothing was read. */
|
|
95
|
+
decimals: z.number().int().min(0).max(18).optional(),
|
|
93
96
|
});
|
|
94
97
|
// GET /api/flags — public kill-switch state needed by the UI
|
|
95
98
|
export const FlagsResponse = z.object({ signupsPaused: z.boolean() });
|
|
@@ -112,6 +115,12 @@ export const LaunchpadModificationRequest = z.strictObject({
|
|
|
112
115
|
request: z.string().min(1),
|
|
113
116
|
});
|
|
114
117
|
export const LaunchpadModificationResponse = z.object({ jobId: Uuid });
|
|
118
|
+
/*
|
|
119
|
+
* POST /api/launchpads/:id/retry (no body) — "start again": a draft whose creation was refunded
|
|
120
|
+
* gets a new `create_launchpad` job in `spec_ready`, built from the launchpad's stored spec (same
|
|
121
|
+
* name and subdomain). Idempotent: while that job awaits payment, the same job id is returned.
|
|
122
|
+
*/
|
|
123
|
+
export const LaunchpadRetryResponse = z.object({ jobId: Uuid });
|
|
115
124
|
// POST /api/payments/quote
|
|
116
125
|
export const PaymentsQuoteRequest = z.strictObject({ jobId: Uuid, kind: PaymentKind });
|
|
117
126
|
/** Quote as seen by the UI (docs/frontend/CONTRACT.md). */
|
|
@@ -219,18 +228,52 @@ export const RpcResponse = z.object({
|
|
|
219
228
|
// ---------------------------------------------------------------------------
|
|
220
229
|
// Internal builder -> signer API (§7)
|
|
221
230
|
// ---------------------------------------------------------------------------
|
|
222
|
-
/**
|
|
231
|
+
/** Lowercase hex HMAC-SHA256 computed with SIGNER_HMAC_SECRET over `signerSignedPayload(...)`. */
|
|
223
232
|
export const SIGNER_SIGNATURE_HEADER = 'X-Forge-Signature';
|
|
224
233
|
/** Unix time in seconds, as a decimal string. */
|
|
225
234
|
export const SIGNER_TIMESTAMP_HEADER = 'X-Forge-Timestamp';
|
|
235
|
+
/**
|
|
236
|
+
* 16 random bytes as 32 lowercase hex characters, fresh for every request (and every retry). The
|
|
237
|
+
* signer accepts a nonce once within the clock-skew window.
|
|
238
|
+
*/
|
|
239
|
+
export const SIGNER_NONCE_HEADER = 'X-Forge-Nonce';
|
|
226
240
|
/** Requests whose timestamp differs from the signer clock by more than this are rejected. */
|
|
227
241
|
export const SIGNER_MAX_CLOCK_SKEW_SECONDS = 60;
|
|
242
|
+
/** First line of the signed string. Any change to its layout gets a new tag. */
|
|
243
|
+
export const SIGNER_SIGNATURE_VERSION = 'forge-signer-v2';
|
|
244
|
+
const SIGNED_FIELD_FORMATS = {
|
|
245
|
+
method: /^[A-Z]{1,16}$/,
|
|
246
|
+
// Origin-form target: printable ASCII, no space, no control character.
|
|
247
|
+
path: /^\/[\x21-\x7e]{0,2047}$/,
|
|
248
|
+
timestamp: /^[0-9]{1,12}$/,
|
|
249
|
+
nonce: /^[0-9a-f]{32}$/,
|
|
250
|
+
bodySha256: /^[0-9a-f]{64}$/,
|
|
251
|
+
};
|
|
228
252
|
/**
|
|
229
|
-
* Exact string fed to HMAC-SHA256
|
|
230
|
-
*
|
|
253
|
+
* Exact string fed to HMAC-SHA256, one field per line, in this order:
|
|
254
|
+
*
|
|
255
|
+
* forge-signer-v2\n<METHOD>\n<path?query>\n<timestamp>\n<nonce>\n<body sha256>
|
|
256
|
+
*
|
|
257
|
+
* Every field has a strict format that excludes the line feed, and the field count is fixed, so
|
|
258
|
+
* the string decodes to exactly one tuple: a signature made for one method, route, query, time,
|
|
259
|
+
* nonce or body is worth nothing for any other. Throws on a field outside its format, so neither
|
|
260
|
+
* side can sign or check an ambiguous string.
|
|
231
261
|
*/
|
|
232
|
-
export function signerSignedPayload(
|
|
233
|
-
|
|
262
|
+
export function signerSignedPayload(fields) {
|
|
263
|
+
for (const key of Object.keys(SIGNED_FIELD_FORMATS)) {
|
|
264
|
+
const value = fields[key];
|
|
265
|
+
if (typeof value !== 'string' || !SIGNED_FIELD_FORMATS[key].test(value)) {
|
|
266
|
+
throw new TypeError(`signer signed payload: invalid ${key}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return [
|
|
270
|
+
SIGNER_SIGNATURE_VERSION,
|
|
271
|
+
fields.method,
|
|
272
|
+
fields.path,
|
|
273
|
+
fields.timestamp,
|
|
274
|
+
fields.nonce,
|
|
275
|
+
fields.bodySha256,
|
|
276
|
+
].join('\n');
|
|
234
277
|
}
|
|
235
278
|
export const SIGNER_ROUTES = {
|
|
236
279
|
configs: { method: 'POST', path: '/v1/configs' },
|
package/dist/constants.d.ts
CHANGED
|
@@ -12,8 +12,11 @@ export declare const PRICING: {
|
|
|
12
12
|
export declare const FEES: {
|
|
13
13
|
/** Our fee on our own buy button (before graduation). */
|
|
14
14
|
readonly platformFeeBps: 30;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Jupiter Plugin referral fee (`referralFee`), after graduation only; Jupiter keeps 20 % of it.
|
|
17
|
+
* Jupiter Ultra accepts 50 to 255 bps (checked by @forge/core `assertJupiterReferralFeeBps`).
|
|
18
|
+
*/
|
|
19
|
+
readonly jupiterIntegratorFeeBps: 50;
|
|
17
20
|
/** FORGE creator share on the coin of every launchpad. */
|
|
18
21
|
readonly forgeCreatorSharePct: 25;
|
|
19
22
|
};
|
package/dist/constants.js
CHANGED
|
@@ -12,8 +12,11 @@ export const PRICING = {
|
|
|
12
12
|
export const FEES = {
|
|
13
13
|
/** Our fee on our own buy button (before graduation). */
|
|
14
14
|
platformFeeBps: 30,
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Jupiter Plugin referral fee (`referralFee`), after graduation only; Jupiter keeps 20 % of it.
|
|
17
|
+
* Jupiter Ultra accepts 50 to 255 bps (checked by @forge/core `assertJupiterReferralFeeBps`).
|
|
18
|
+
*/
|
|
19
|
+
jupiterIntegratorFeeBps: 50,
|
|
17
20
|
/** FORGE creator share on the coin of every launchpad. */
|
|
18
21
|
forgeCreatorSharePct: 25,
|
|
19
22
|
};
|
package/dist/db.d.ts
CHANGED
|
@@ -13,6 +13,23 @@ export declare const LaunchpadStatus: z.ZodEnum<{
|
|
|
13
13
|
disabled: "disabled";
|
|
14
14
|
}>;
|
|
15
15
|
export type LaunchpadStatus = z.infer<typeof LaunchpadStatus>;
|
|
16
|
+
/**
|
|
17
|
+
* Shape of `launchpads.site_host` (migration 0011 holds the same CHECK): a lowercase DNS name
|
|
18
|
+
* without scheme, port, path or trailing dot. Under `vercel.app` (Vercel's production aliases),
|
|
19
|
+
* exactly one label; `vercel.app` itself is never a site host.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isSiteHost(value: unknown): value is string;
|
|
22
|
+
/** A site host on `vercel.app` (`<one label>.vercel.app`). */
|
|
23
|
+
export declare function isVercelAppHost(value: unknown): value is string;
|
|
24
|
+
/**
|
|
25
|
+
* The recorded `site_host` of the launchpad `slug`, when a reader may trust it (relay origins,
|
|
26
|
+
* upload `auth.host`, links to the site): exactly `<one label>.vercel.app` (an alias of the
|
|
27
|
+
* launchpad's own Vercel project, checked by the builder before it records one), or exactly
|
|
28
|
+
* `<slug>.<clientsDomain>`. Any other host, however well formed (another domain, the subdomain of
|
|
29
|
+
* another launchpad), is ignored: null. `clientsDomain` is lowercase (readClientsDomain).
|
|
30
|
+
*/
|
|
31
|
+
export declare function trustedSiteHost(siteHost: unknown, slug: string, clientsDomain: string | null): string | null;
|
|
32
|
+
export declare const SiteHost: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
16
33
|
export declare const PaymentStatus: z.ZodEnum<{
|
|
17
34
|
refunded: "refunded";
|
|
18
35
|
quoted: "quoted";
|
|
@@ -39,6 +56,9 @@ export declare const FlagKey: z.ZodEnum<{
|
|
|
39
56
|
claims_paused: "claims_paused";
|
|
40
57
|
cashbox_sweep_paused: "cashbox_sweep_paused";
|
|
41
58
|
refunds_paused: "refunds_paused";
|
|
59
|
+
jupiter_claims_paused: "jupiter_claims_paused";
|
|
60
|
+
convert_paused: "convert_paused";
|
|
61
|
+
revenue_paused: "revenue_paused";
|
|
42
62
|
}>;
|
|
43
63
|
export type FlagKey = z.infer<typeof FlagKey>;
|
|
44
64
|
/** ISO 8601 timestamp as returned by PostgREST for `timestamptz`. */
|
|
@@ -70,6 +90,13 @@ export interface LaunchpadRow {
|
|
|
70
90
|
status: LaunchpadStatus;
|
|
71
91
|
last_trade_at: Timestamptz | null;
|
|
72
92
|
created_at: Timestamptz | null;
|
|
93
|
+
/**
|
|
94
|
+
* Exact production host of the client site (`SiteHost`), recorded by the builder from the Vercel
|
|
95
|
+
* API when the site goes live: the verified `<slug>.<CLIENTS_DOMAIN>`, else a `*.vercel.app`
|
|
96
|
+
* alias of the launchpad's own Vercel project. Trusted by exact match only (RPC relay origins,
|
|
97
|
+
* coin uploads, site links). Null until recorded (migration 0011).
|
|
98
|
+
*/
|
|
99
|
+
site_host: string | null;
|
|
73
100
|
}
|
|
74
101
|
/**
|
|
75
102
|
* `jobs.owner_tx_details` (jsonb): the public accounts of the launch transaction stored in
|
package/dist/db.js
CHANGED
|
@@ -6,6 +6,42 @@ import { SolanaAddress } from './spec.js';
|
|
|
6
6
|
* it has a default.
|
|
7
7
|
*/
|
|
8
8
|
export const LaunchpadStatus = z.enum(['draft', 'live', 'sleeping', 'disabled']);
|
|
9
|
+
/** One DNS label: lowercase letters, digits and inner dashes, 1 to 63 characters. */
|
|
10
|
+
const HOST_LABEL = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?';
|
|
11
|
+
const HOST_NAME_RE = new RegExp(`^(?=.{4,253}$)(?:${HOST_LABEL}\\.)+[a-z]{2,63}$`);
|
|
12
|
+
const VERCEL_APP_HOST_RE = new RegExp(`^${HOST_LABEL}\\.vercel\\.app$`);
|
|
13
|
+
/**
|
|
14
|
+
* Shape of `launchpads.site_host` (migration 0011 holds the same CHECK): a lowercase DNS name
|
|
15
|
+
* without scheme, port, path or trailing dot. Under `vercel.app` (Vercel's production aliases),
|
|
16
|
+
* exactly one label; `vercel.app` itself is never a site host.
|
|
17
|
+
*/
|
|
18
|
+
export function isSiteHost(value) {
|
|
19
|
+
if (typeof value !== 'string' || value === 'vercel.app' || !HOST_NAME_RE.test(value)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return !value.endsWith('.vercel.app') || VERCEL_APP_HOST_RE.test(value);
|
|
23
|
+
}
|
|
24
|
+
/** A site host on `vercel.app` (`<one label>.vercel.app`). */
|
|
25
|
+
export function isVercelAppHost(value) {
|
|
26
|
+
return isSiteHost(value) && value.endsWith('.vercel.app');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The recorded `site_host` of the launchpad `slug`, when a reader may trust it (relay origins,
|
|
30
|
+
* upload `auth.host`, links to the site): exactly `<one label>.vercel.app` (an alias of the
|
|
31
|
+
* launchpad's own Vercel project, checked by the builder before it records one), or exactly
|
|
32
|
+
* `<slug>.<clientsDomain>`. Any other host, however well formed (another domain, the subdomain of
|
|
33
|
+
* another launchpad), is ignored: null. `clientsDomain` is lowercase (readClientsDomain).
|
|
34
|
+
*/
|
|
35
|
+
export function trustedSiteHost(siteHost, slug, clientsDomain) {
|
|
36
|
+
if (!isSiteHost(siteHost))
|
|
37
|
+
return null;
|
|
38
|
+
if (isVercelAppHost(siteHost))
|
|
39
|
+
return siteHost;
|
|
40
|
+
return clientsDomain !== null && siteHost === `${slug}.${clientsDomain}` ? siteHost : null;
|
|
41
|
+
}
|
|
42
|
+
export const SiteHost = z.string().refine(isSiteHost, {
|
|
43
|
+
error: 'Must be a lowercase host name (one label under vercel.app)',
|
|
44
|
+
});
|
|
9
45
|
export const PaymentStatus = z.enum(['quoted', 'confirmed', 'expired', 'refunded']);
|
|
10
46
|
export const PaymentKind = z.enum(['creation', 'modification']);
|
|
11
47
|
export const ChatRole = z.enum(['user', 'assistant', 'system']);
|
|
@@ -17,6 +53,9 @@ export const FlagKey = z.enum([
|
|
|
17
53
|
'claims_paused',
|
|
18
54
|
'cashbox_sweep_paused',
|
|
19
55
|
'refunds_paused',
|
|
56
|
+
'jupiter_claims_paused',
|
|
57
|
+
'convert_paused',
|
|
58
|
+
'revenue_paused',
|
|
20
59
|
]);
|
|
21
60
|
/**
|
|
22
61
|
* `jobs.owner_tx_details` (jsonb): the public accounts of the launch transaction stored in
|
package/dist/web-client.d.ts
CHANGED
|
@@ -33,6 +33,11 @@ export interface LaunchpadSummary {
|
|
|
33
33
|
id: string;
|
|
34
34
|
name: string;
|
|
35
35
|
slug: string;
|
|
36
|
+
/**
|
|
37
|
+
* Where the live site is: `https://<site_host>` when the builder recorded its exact host
|
|
38
|
+
* (`launchpads.site_host`), else `https://<slug>.<CLIENTS_DOMAIN>`. Null unless the launchpad is
|
|
39
|
+
* live or sleeping (or when neither is known).
|
|
40
|
+
*/
|
|
36
41
|
siteUrl: string | null;
|
|
37
42
|
status: LaunchpadStatus;
|
|
38
43
|
coin: {
|
|
@@ -45,7 +50,32 @@ export interface LaunchpadSummary {
|
|
|
45
50
|
claimablePartnerFeesLamports: Lamports;
|
|
46
51
|
includedModificationsLeft: number;
|
|
47
52
|
activeJobId: string | null;
|
|
48
|
-
|
|
53
|
+
/** Status of `activeJobId` (null without one). Absent from older servers. */
|
|
54
|
+
activeJobStatus?: JobStatus | null;
|
|
55
|
+
/**
|
|
56
|
+
* A draft whose creation was refunded, with nothing in progress: `retryLaunchpad` can start it
|
|
57
|
+
* again with the same blueprint. The server re-checks everything (payments, refunds, kill
|
|
58
|
+
* switches, access) when asked. Absent from older servers: then treated as false.
|
|
59
|
+
*/
|
|
60
|
+
canStartAgain?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* A draft whose creation jobs were all refunded but that cannot be started again yet, and why
|
|
63
|
+
* (null otherwise, and whenever a job is open: its tracker explains). The same rules as the
|
|
64
|
+
* route, so "start again" is never offered and then refused. Absent from older servers.
|
|
65
|
+
*/
|
|
66
|
+
startAgainBlocked?: StartAgainBlockedReason | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Why "start again" is not available for a refunded draft:
|
|
70
|
+
* - `refund_pending`: money of an earlier attempt is still owed back (refund not recorded, or a
|
|
71
|
+
* payment anomaly waiting for its manual refund);
|
|
72
|
+
* - `payment_pending`: a payment for an earlier attempt may still land or be confirmed;
|
|
73
|
+
* - `needs_support`: the team has to look at it first (on-chain setup recorded, or the limit of
|
|
74
|
+
* refunded creations reached);
|
|
75
|
+
* - `invalid_spec`: the stored blueprint no longer passes the checks (design it again).
|
|
76
|
+
*/
|
|
77
|
+
export declare const START_AGAIN_BLOCKED_REASONS: readonly ["refund_pending", "payment_pending", "needs_support", "invalid_spec"];
|
|
78
|
+
export type StartAgainBlockedReason = (typeof START_AGAIN_BLOCKED_REASONS)[number];
|
|
49
79
|
export interface LaunchpadDetail extends LaunchpadSummary {
|
|
50
80
|
/** Complete spec. */
|
|
51
81
|
spec: LaunchpadSpecDraft;
|
|
@@ -167,6 +197,10 @@ export interface WebClient {
|
|
|
167
197
|
useLaunchpad(id: string): UseLaunchpadResult;
|
|
168
198
|
claimPartnerFees(launchpadId: string, onPhase: OnTxPhase): Promise<TxResult>;
|
|
169
199
|
reactivateLaunchpad(launchpadId: string): Promise<void>;
|
|
200
|
+
/** "Start again" on a refunded draft: the new (or still unpaid) creation job, to pay next. */
|
|
201
|
+
retryLaunchpad(launchpadId: string): Promise<{
|
|
202
|
+
jobId: string;
|
|
203
|
+
}>;
|
|
170
204
|
formatSol(lamports: Lamports, opts?: FormatSolOptions): string;
|
|
171
205
|
formatUsd(n: number): string;
|
|
172
206
|
shortAddress(a: string): string;
|
package/dist/web-client.js
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why "start again" is not available for a refunded draft:
|
|
3
|
+
* - `refund_pending`: money of an earlier attempt is still owed back (refund not recorded, or a
|
|
4
|
+
* payment anomaly waiting for its manual refund);
|
|
5
|
+
* - `payment_pending`: a payment for an earlier attempt may still land or be confirmed;
|
|
6
|
+
* - `needs_support`: the team has to look at it first (on-chain setup recorded, or the limit of
|
|
7
|
+
* refunded creations reached);
|
|
8
|
+
* - `invalid_spec`: the stored blueprint no longer passes the checks (design it again).
|
|
9
|
+
*/
|
|
10
|
+
export const START_AGAIN_BLOCKED_REASONS = [
|
|
11
|
+
'refund_pending',
|
|
12
|
+
'payment_pending',
|
|
13
|
+
'needs_support',
|
|
14
|
+
'invalid_spec',
|
|
15
|
+
];
|
|
1
16
|
export const CLIENT_ERROR_CODES = [
|
|
2
17
|
'RATE_LIMITED',
|
|
3
18
|
'UNAUTHORIZED',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgedevv/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Shared contracts (constants, zod schemas, types) between all FORGE apps. Published on npm as @forgedevv/shared.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"dist/**/*.js",
|
|
31
31
|
"dist/**/*.d.ts",
|
|
32
|
-
"!dist/**/*.test.*"
|
|
32
|
+
"!dist/**/*.test.*",
|
|
33
|
+
"CHANGELOG.md"
|
|
33
34
|
],
|
|
34
35
|
"publishConfig": {
|
|
35
36
|
"access": "public",
|