@bordrless/shared 0.8.0 → 0.9.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.
@@ -0,0 +1,352 @@
1
+ /**
2
+ * The Workshop (2026-10-12): hooks and companions anyone writes with the SDK and their own agent.
3
+ * The builder submits the source; Bordrless does the rest on its own machines (docs/workshop.md):
4
+ *
5
+ * 1. **Checks**, automatic, on Bordrless's backend and its sandboxed builder: the template's static
6
+ * rules, a security review by AI (two independent runs, the worse kept) looking for anything
7
+ * malicious, the build, the trading test (a hook), and the AI's plain reading (what it does, the
8
+ * most it takes, a description).
9
+ * 2. **Approval** by Bordrless.
10
+ * 3. **Deploy**: the builder pays what deploying it costs (its rent, the fees and Bordrless's fee,
11
+ * quoted first; Bordrless's fee goes to the revenue wallet) and Bordrless deploys it with
12
+ * Bordrless's upgrade key. The builder never holds the upgrade authority.
13
+ * 4. **Credit**: a hook's builder makes its launch config, listed, and earns `AUTHOR_SHARE_BPS` (half)
14
+ * of the creator fee of every launch someone else makes with it, fixed on chain. A companion's
15
+ * builder is paid the same half by the companion program.
16
+ *
17
+ * Built on Studio's backend pipeline (studio_projects: review, build, trading test, deploy,
18
+ * config); Studio's own pages are gone. Companions wait in a queue until the companion program's
19
+ * script upgrade and the builder's script template are live (`queued`).
20
+ *
21
+ * **Pairs** (the owner, 2026-10-12: a hook and its companion are not separate anywhere a builder or
22
+ * a launcher sees them). A `pair` is a trade hook plus the companion script that runs with it (the
23
+ * hook keeps the score in the holdings, the script holds the pot and pays), submitted as one item
24
+ * with both sources (`files`, `scriptFiles`), checked as two Studio projects, approved once (both
25
+ * builds bound), deployed with one payment, and listed as one config that requires its companion:
26
+ * `ConfigInspection.requiredCompanion` says so, and a launch of the config without the pair's
27
+ * script, or of the script from another config, is refused (`companion_required`,
28
+ * `config_required`). A pair's `program` is its hook's; `scriptProgram` its script's.
29
+ *
30
+ * **The reading lane** (the owner, 2026-10-12; docs/workshop.md "The reading lane"). A builder who
31
+ * deployed their own hook or companion (the self-serve lane: immutable or not, never under
32
+ * Bordrless's key) submits the source with the program's address (`WorkshopSubmitRequest.program`).
33
+ * The item is `lane: 'reading'`: the same fee, the same checks, and then the build's executable hash
34
+ * is compared with the code on chain. Equal, the item is `matched` and Bordrless's reading and
35
+ * verdict show wherever the program appears (the launch page's config readout, the token page),
36
+ * while the code on chain stays that build. Nothing is deployed, no key of Bordrless's is involved,
37
+ * no author share, nothing on the Workshop's shelves; the item's page is public once matched.
38
+ */
39
+ import type { Address, PreparedTx } from './api.ts';
40
+ import type { StudioFile } from './studio.ts';
41
+ export type WorkshopKind = 'hook' | 'companion' | 'pair';
42
+ export declare const WORKSHOP_KINDS: readonly WorkshopKind[];
43
+ /**
44
+ * Which lane an item is in: `workshop` (Bordrless checks, approves and deploys it under its own key)
45
+ * or `reading` (the builder deployed it themselves; Bordrless reads and checks the source and, when
46
+ * the build matches the program on chain, its words show wherever the program is used). Absent from
47
+ * older servers: read as `workshop`.
48
+ */
49
+ export type WorkshopLane = 'workshop' | 'reading';
50
+ export declare const WORKSHOP_LANES: readonly WorkshopLane[];
51
+ /**
52
+ * Where a submission stands: `unpaid` (taken; nothing runs until its builder pays the submission
53
+ * fee, `WorkshopFee`), `checking` (the automatic checks are running), `queued` (a companion, until
54
+ * the script upgrade is live), `pending` (passed, waiting for Bordrless's approval), `approved` (its
55
+ * builder can pay to deploy it), `rejected` (by the checks or by Bordrless, with the reason),
56
+ * `revoked` (taken down after approval), `matched` (a reading-lane item: the checks passed and the
57
+ * build equals the code on chain, so its reading is attached; terminal). A reading-lane item is
58
+ * never `pending` or `approved`: there is nothing to approve or deploy.
59
+ */
60
+ export type WorkshopStatus = 'unpaid' | 'checking' | 'queued' | 'pending' | 'approved' | 'rejected' | 'revoked' | 'matched';
61
+ /**
62
+ * The submission fee (the owner, 2026-10-12): every submission costs a fixed amount of SOL, paid by
63
+ * its builder to Bordrless's treasury before its checks run (the API's `WORKSHOP_SUBMIT_LAMPORTS`,
64
+ * 0.1 SOL unless set; 0 makes submissions free). It pays for the review by AI, the build and the
65
+ * trading test, and for the programs Bordrless deploys and keeps. It is not refunded, approved or
66
+ * not. Fixes to a submission that is not approved yet cost nothing more.
67
+ */
68
+ export interface WorkshopFee {
69
+ /** Lamports, as a decimal string: what this submission was quoted when it was taken. */
70
+ lamports: string;
71
+ /** Bordrless's treasury. */
72
+ payTo: Address;
73
+ /** The memo the payment carries, which makes it this submission's. */
74
+ memo: string;
75
+ /** The payment's transaction signature once Bordrless saw it on chain; null while unpaid. */
76
+ paid: string | null;
77
+ }
78
+ /** `GET /v1/workshop/fee`: what a submission costs now, for the pages that say so before anything is sent. */
79
+ export interface WorkshopFeeResponse {
80
+ lamports: string;
81
+ payTo: Address;
82
+ }
83
+ /** `POST /v1/workshop/:id/fee/quote`, as its builder: the fee and the one payment to sign (it lives about a minute). */
84
+ export interface WorkshopFeeQuote extends WorkshopFeeResponse {
85
+ memo: string;
86
+ transactions: PreparedTx[];
87
+ /** Unix seconds. */
88
+ expiresAt: number;
89
+ }
90
+ /** `POST /v1/workshop/:id/pay`: the fee's payment, checked on chain; the checks start. */
91
+ export interface WorkshopPayRequest {
92
+ paymentSignature: string;
93
+ }
94
+ /** What a submission may hold: the Rust sources of Bordrless's template (its Cargo.toml and crates are Bordrless's). */
95
+ export declare const WORKSHOP_LIMITS: {
96
+ /** Source files, and their bytes in all (the builder's limits). */
97
+ readonly files: 8;
98
+ readonly bytes: 120000;
99
+ /** The name, in characters. */
100
+ readonly name: 32;
101
+ /** The builder's own words. */
102
+ readonly notes: 600;
103
+ /** Submissions one wallet may make in a day. */
104
+ readonly perDay: 6;
105
+ };
106
+ /** A submission's file path: a Rust source under src/, lower-case names (the builder's rule). */
107
+ export declare const WORKSHOP_PATH: RegExp;
108
+ export declare const workshopPathOk: (path: string) => boolean;
109
+ /** The longest each part of the AI's reading may be. */
110
+ export declare const WORKSHOP_READING_LIMITS: {
111
+ readonly title: 48;
112
+ readonly does: 160;
113
+ readonly totalText: 80;
114
+ readonly description: 600;
115
+ readonly watch: 5;
116
+ readonly watchText: 140;
117
+ };
118
+ export type WorkshopWatchSeverity = 'high' | 'medium' | 'low';
119
+ /**
120
+ * What Bordrless's AI wrote about a submission from its source: a title, what it does in one
121
+ * sentence, the most it takes (`total`: for a hook, the largest cut of one trade in basis points of
122
+ * its amount, null when the code reads it from an account it doesn't bound; for a companion, the most
123
+ * of its pot one step spends), a plain description, and what a launcher should watch for. Read by
124
+ * AI from the code, not an audit.
125
+ */
126
+ export interface WorkshopReading {
127
+ title: string;
128
+ does: string;
129
+ total: {
130
+ bps: number | null;
131
+ text: string;
132
+ };
133
+ description: string;
134
+ watch: {
135
+ severity: WorkshopWatchSeverity;
136
+ text: string;
137
+ }[];
138
+ /** Unix seconds. */
139
+ at: number;
140
+ }
141
+ /** One automatic check, as the item's page shows it. */
142
+ export interface WorkshopCheck {
143
+ id: 'rules' | 'review' | 'build' | 'test' | 'reading';
144
+ label: string;
145
+ state: 'waiting' | 'running' | 'passed' | 'warned' | 'failed' | 'skipped';
146
+ /** One plain sentence: what it found, or why it failed. */
147
+ detail: string | null;
148
+ }
149
+ /** A finding of the security review. */
150
+ export interface WorkshopFinding {
151
+ severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
152
+ title: string;
153
+ detail: string;
154
+ }
155
+ /** Where its deploy stands: Studio's deploy states, or null before it is paid for. */
156
+ export type WorkshopDeployState = 'awaiting_payment' | 'paid' | 'writing' | 'deploying' | 'handing_over' | 'deployed' | 'failed' | 'refunded';
157
+ /** A Workshop item as a card shows it. */
158
+ export interface WorkshopItem {
159
+ /** Its id (a uuid): its page is /workshop/<id>. */
160
+ id: string;
161
+ kind: WorkshopKind;
162
+ name: string;
163
+ author: Address;
164
+ status: WorkshopStatus;
165
+ reading: WorkshopReading | null;
166
+ readingState: 'waiting' | 'done' | 'failed';
167
+ /** Its program: reserved once built, live once deployed (`deployed`). A pair's is its hook's. */
168
+ program: Address | null;
169
+ /** Live on chain: for a pair, both halves. */
170
+ deployed: boolean;
171
+ /**
172
+ * The script half's program: a pair's companion script (reserved once built, live once
173
+ * `scriptDeployed`), a companion's own (`program` again); null for a hook. Absent from older servers.
174
+ */
175
+ scriptProgram?: Address | null;
176
+ /** Whether the script half is deployed (a pair's script; a companion's own program); false for a hook. Absent from older servers. */
177
+ scriptDeployed?: boolean;
178
+ /** A hook's listed launch config, once its builder made it (what the launch page launches from). */
179
+ config: Address | null;
180
+ /** The largest cut of one transfer the trading test measured (a hook), basis points. */
181
+ measuredCutBps: number | null;
182
+ launches: number;
183
+ /** Unix seconds. */
184
+ submittedAt: number;
185
+ approvedAt: number | null;
186
+ /**
187
+ * A companion, or a pair's script (docs/scripts.md): whether the companion program's on-chain
188
+ * approval of its deployed code holds now (`pnpm admin workshop approve-script`), which a launch
189
+ * with it needs; false until it is written, or once the code changed or the approval was revoked.
190
+ * Null for a hook; absent from older servers.
191
+ */
192
+ scriptApproved?: boolean | null;
193
+ /** Its lane (`WorkshopLane`); absent from older servers: `workshop`. A reading-lane item's `program` is the builder's own, from the start. */
194
+ lane?: WorkshopLane;
195
+ /**
196
+ * A reading-lane item: whether its build's executable hash equals the code on chain (true:
197
+ * `matched`; false: `rejected` with the mismatch in `reviewNote`); null until its checks finish.
198
+ * Null for a Workshop-lane item; absent from older servers.
199
+ */
200
+ matched?: boolean | null;
201
+ }
202
+ /** What a reading-lane item's match compared, and who can change the program (`WorkshopDetail.match`). */
203
+ export interface WorkshopMatch {
204
+ /** The executable hash of the code on chain (hex): the one compared once the checks finished, else as read now; null when the program could not be read. */
205
+ chainHash: string | null;
206
+ /** The executable hash of Bordrless's build of the source; null before it is built. */
207
+ buildHash: string | null;
208
+ /** The program's upgrade authority; null when it has none (immutable), or when it could not be read (`immutable` tells which). */
209
+ upgradeAuthority: Address | null;
210
+ /** True: nobody can change its code. False: `upgradeAuthority` can. Null: not read. */
211
+ immutable: boolean | null;
212
+ }
213
+ /** A half's security review, as the item's page shows it. */
214
+ export interface WorkshopReviewSummary {
215
+ verdict: 'pass' | 'warn' | 'fail';
216
+ summary: string;
217
+ findings: WorkshopFinding[];
218
+ }
219
+ /** A half's build: the executable hash Bordrless approves and deploys, its size, the template commit. */
220
+ export interface WorkshopBuildSummary {
221
+ hash: string;
222
+ bytes: number;
223
+ templateCommit: string | null;
224
+ }
225
+ /** Where a half's deploy stands. */
226
+ export interface WorkshopDeploySummary {
227
+ state: WorkshopDeployState;
228
+ upgradeAuthority: Address | null;
229
+ error: string | null;
230
+ }
231
+ /** One item in full. */
232
+ export interface WorkshopDetail extends WorkshopItem {
233
+ /** The executable hash of the build Bordrless approved (what its deploy and, for a companion, its on-chain approval are bound to; a pair's hook's); null before approval. Absent from older servers. */
234
+ approvedHash?: string | null;
235
+ /** A pair: the executable hash of the companion script's build Bordrless approved (what its deploy and its on-chain approval are bound to); null before approval, and for a hook or a companion. Absent from older servers. */
236
+ approvedScriptHash?: string | null;
237
+ notes: string;
238
+ /** Its source: a hook's, a companion's, or a pair's hook's. */
239
+ files: StudioFile[];
240
+ /** A pair's companion script source; empty for a hook or a companion. Absent from older servers. */
241
+ scriptFiles?: StudioFile[];
242
+ /** A hook's callbacks (`TOKEN_HOOK_FLAGS`), read from its source (a pair's hook's); 0 for a companion. */
243
+ hookFlags: number;
244
+ /** The checks: a hook's or a companion's, or a pair's hook half's (its rules, review, build, trading test) with the reading, which is one for the item. */
245
+ checks: WorkshopCheck[];
246
+ /** A pair's companion script half: its rules, review and build (no trading test; the reading is in `checks`). Empty for a hook or a companion. Absent from older servers. */
247
+ scriptChecks?: WorkshopCheck[];
248
+ review: WorkshopReviewSummary | null;
249
+ /** A pair's companion script review. Absent from older servers. */
250
+ scriptReview?: WorkshopReviewSummary | null;
251
+ test: {
252
+ pass: boolean;
253
+ reasons: string[];
254
+ cutMaxBps: number | null;
255
+ notes: string[];
256
+ } | null;
257
+ build: WorkshopBuildSummary | null;
258
+ /** A pair's companion script build. Absent from older servers. */
259
+ scriptBuild?: WorkshopBuildSummary | null;
260
+ deploy: WorkshopDeploySummary | null;
261
+ /** A pair's companion script deploy. Absent from older servers. */
262
+ scriptDeploy?: WorkshopDeploySummary | null;
263
+ /** A listed config's creator fee, once made. */
264
+ creatorFeeBps: number | null;
265
+ /** Bordrless's note on a rejection or a revocation, or why the checks stopped it. */
266
+ reviewNote: string | null;
267
+ /** The submission fee it was quoted and whether it is paid; null when it was taken free. Absent from older servers. */
268
+ fee?: WorkshopFee | null;
269
+ /** Who approved it: the checks ('auto', a clean pass) or the operator; null before approval. Absent from older servers. */
270
+ approvedBy?: 'auto' | 'operator' | null;
271
+ /** A reading-lane item: the hashes compared and who can change the program; null for a Workshop-lane item. Absent from older servers. */
272
+ match?: WorkshopMatch | null;
273
+ }
274
+ export interface WorkshopListResponse {
275
+ items: WorkshopItem[];
276
+ total: number;
277
+ }
278
+ /**
279
+ * `POST /v1/workshop/submit`, as the signed-in wallet (the Studio session header). A pair sends both
280
+ * halves: `files` (the hook's `src/**`) and `scriptFiles` (the companion script's), each within
281
+ * `WORKSHOP_LIMITS`; both are refused if either breaks its template's path rules. A pair's hook may
282
+ * be a game hook (its state starts with `GameHeader`: the pair's script reads the score); a lone
283
+ * hook may not (`game_hook`).
284
+ *
285
+ * With `program`, the submission is a reading-lane one (`WorkshopLane`): the builder deployed that
286
+ * program themselves, and Bordrless reads and checks the source and compares its build with the
287
+ * code on chain. A hook or a companion only: a pair is refused (`reading_lane_pairs`, 400). The
288
+ * program must be deployed through the upgradeable loader (`program_not_deployed`, 400); one with a
289
+ * submission already is refused (`program_taken`, 409: send a fix to that one).
290
+ */
291
+ export interface WorkshopSubmitRequest {
292
+ kind: WorkshopKind;
293
+ name: string;
294
+ notes: string;
295
+ files: StudioFile[];
296
+ /** A pair's companion script source; ignored for a hook or a companion. */
297
+ scriptFiles?: StudioFile[];
298
+ /** The program's address when the builder deployed it themselves (the reading lane). */
299
+ program?: Address;
300
+ }
301
+ /**
302
+ * `POST /v1/workshop/:id/files`: a fix of a submission not approved yet (its checks run again). A
303
+ * hook or a companion sends `files`; a pair sends `files` (its hook), `scriptFiles` (its companion
304
+ * script), or both.
305
+ */
306
+ export interface WorkshopFilesRequest {
307
+ files?: StudioFile[];
308
+ scriptFiles?: StudioFile[];
309
+ }
310
+ /** One program's deploy cost, lamports as decimal strings: rent (the binary with room to upgrade), the transaction fees, Bordrless's fee, the total. */
311
+ export interface WorkshopDeployCost {
312
+ rent: string;
313
+ fees: string;
314
+ service: string;
315
+ total: string;
316
+ }
317
+ /**
318
+ * `POST /v1/workshop/:id/deploy/quote`: what deploying it costs, and the payment to sign. A pair's
319
+ * quote covers both programs: `rent`, `fees`, `service` and `total` are the sums, `parts` each
320
+ * half's, and the one transaction pays both (two transfers to the deployer and two memos, one per
321
+ * program); `WorkshopDeployRequest` then carries its one signature.
322
+ */
323
+ export interface WorkshopDeployQuote extends WorkshopDeployCost {
324
+ payTo: Address;
325
+ transactions: PreparedTx[];
326
+ /** Unix seconds. */
327
+ expiresAt: number;
328
+ /** A pair: each half's cost; null for a hook or a companion. Absent from older servers. */
329
+ parts?: {
330
+ hook: WorkshopDeployCost;
331
+ script: WorkshopDeployCost;
332
+ } | null;
333
+ }
334
+ /** `POST /v1/workshop/:id/deploy`: the confirmed payment. */
335
+ export interface WorkshopDeployRequest {
336
+ paymentSignature: string;
337
+ }
338
+ /** The creator fees a hook's builder may list its config with (they earn `AUTHOR_SHARE_BPS` of it). */
339
+ export declare const WORKSHOP_CONFIG_FEES_BPS: readonly number[];
340
+ /** `POST /v1/workshop/:id/config/prepare`: the builder's listed launch config on their deployed hook (a pair's: on its hook, requiring its script). */
341
+ export interface WorkshopConfigPrepareRequest {
342
+ creatorFeeBps: number;
343
+ /** The address of a keypair the browser made; it signs after the wallet. */
344
+ config: Address;
345
+ }
346
+ export interface WorkshopConfigPrepareResponse {
347
+ config: Address;
348
+ transactions: PreparedTx[];
349
+ }
350
+ export interface WorkshopConfigConfirmRequest {
351
+ config: Address;
352
+ }
@@ -0,0 +1,21 @@
1
+ export const WORKSHOP_KINDS = ['hook', 'companion', 'pair'];
2
+ export const WORKSHOP_LANES = ['workshop', 'reading'];
3
+ /** What a submission may hold: the Rust sources of Bordrless's template (its Cargo.toml and crates are Bordrless's). */
4
+ export const WORKSHOP_LIMITS = {
5
+ /** Source files, and their bytes in all (the builder's limits). */
6
+ files: 8,
7
+ bytes: 120_000,
8
+ /** The name, in characters. */
9
+ name: 32,
10
+ /** The builder's own words. */
11
+ notes: 600,
12
+ /** Submissions one wallet may make in a day. */
13
+ perDay: 6,
14
+ };
15
+ /** A submission's file path: a Rust source under src/, lower-case names (the builder's rule). */
16
+ export const WORKSHOP_PATH = /^src\/[a-z0-9_]+(\/[a-z0-9_]+)*\.rs$/;
17
+ export const workshopPathOk = (path) => WORKSHOP_PATH.test(path);
18
+ /** The longest each part of the AI's reading may be. */
19
+ export const WORKSHOP_READING_LIMITS = { title: 48, does: 160, totalText: 80, description: 600, watch: 5, watchText: 140 };
20
+ /** The creator fees a hook's builder may list its config with (they earn `AUTHOR_SHARE_BPS` of it). */
21
+ export const WORKSHOP_CONFIG_FEES_BPS = [50, 100, 200];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bordrless/shared",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Bordrless policy (the same math as crates/bordrless-core), program addresses and the API types shared by the server and the site. No Solana dependencies.",
6
6
  "license": "Apache-2.0",