@dev.fast/whiteboard 0.2.4 → 0.2.5-preview.20261013.109
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/{account-alias-_1_7vROx.js → account-alias-D0hF0sKk.js} +2 -3
- package/dist/{agent-cli-BrFqhnzM.js → agent-cli-BBPxwUOd.js} +6 -6
- package/dist/agent-cli-YSuhE5X8.js +2 -0
- package/dist/{agent-client-B_b1GtUc.js → agent-client-P3J4y8Zn.js} +3 -3
- package/dist/{authoring-tools-DvIO906l.js → authoring-tools-D8WXsm_g.js} +11 -10
- package/dist/build-info.json +1 -1
- package/dist/{cli-gRGxkwc0.js → cli-C0ziP6hg.js} +1 -1
- package/dist/{cli-runner-Cjl8h376.js → cli-runner-C1gY-HAI.js} +16 -17
- package/dist/cli.js +1 -1
- package/dist/{client-BFClfQLO.js → client-DzcSt6pV.js} +63 -13
- package/dist/{desktop-discovery-C-Qz54wO.js → desktop-discovery-Ba3dD5Cn.js} +1 -1
- package/dist/{headless-host-DcWaxx9P.js → headless-host-BHD_Vg5F.js} +4 -4
- package/dist/{local-data-Bm84Xdck.js → local-data-BlERtVm2.js} +281 -75
- package/dist/{mcp-BDy9Aybd.js → mcp-t7VN9R3k.js} +4 -4
- package/dist/{package-paths-B6-zxvIO.js → package-paths-B9PDoAl6.js} +1 -1
- package/dist/{process-error-telemetry-Dzh5a3s_.js → process-error-telemetry-C0swByfp.js} +158 -57
- package/dist/{profile-RDEioF8b.js → profile-BsYDBr7t.js} +2 -2
- package/dist/profile-j97aRTS7.js +2 -0
- package/dist/{review-agent-traces-DNJFYzc8.js → review-home-paths-Y9mYWkCI.js} +2600 -62
- package/dist/{review-telemetry-DBy3eVCo.js → review-telemetry-CmM6tCbj.js} +2 -2
- package/dist/server/desktop-host.js +35 -46
- package/dist/{server-discovery-Dbzn3w6Z.js → server-discovery-ZVi8Ay8J.js} +1 -1
- package/dist/sharing/index.d.ts +37 -49
- package/dist/sharing/index.js +1 -1
- package/dist/{src-CmdiBL20.js → src-DiHP11l3.js} +11 -1
- package/dist/{stored-document-migration-BxZWQQjv.js → stored-document-migration-u4L_1VZa.js} +15 -36
- package/dist/{tool-failure-DJmTieh5.js → tool-failure-CJHBCHMh.js} +2 -2
- package/instructions/scratchpad.md +1 -1
- package/package.json +5 -4
- package/src/ask/agents.ts +6 -0
- package/src/ask/thread-state.ts +17 -1
- package/src/ask/thread.ts +116 -22
- package/src/ask/threads.ts +8 -2
- package/src/error-telemetry.ts +13 -9
- package/src/fixtures/blocks/tutorial.json +3 -40
- package/src/review-api/README.md +10 -7
- package/src/review-api/ask-history.ts +37 -0
- package/src/review-api/authoring-tools.ts +8 -5
- package/src/review-api/blocks/database_lens.ts +5 -0
- package/src/review-api/blocks/tutorial.ts +2 -18
- package/src/review-api/comparison-coverage.ts +16 -9
- package/src/review-api/component-reference.ts +1 -1
- package/src/review-api/document.ts +24 -10
- package/src/review-api/http.ts +267 -189
- package/src/review-api/local-data.ts +126 -37
- package/src/review-api/store-schema.ts +25 -1
- package/src/review-api/store.ts +165 -33
- package/src/review-api/workspaces.ts +14 -14
- package/src/review-api/worktree-events.ts +46 -0
- package/src/review-app.ts +1 -1
- package/src/review-info.ts +1 -1
- package/src/review-stack.ts +2 -2
- package/src/server/review-server-core.ts +25 -1
- package/src/server/tutorial-service.ts +22 -46
- package/src/sharing/export.ts +1 -0
- package/src/sharing/import.ts +111 -26
- package/tutorial/document.json +27 -86
- package/tutorial/lenses.json +10 -0
- package/tutorial/runtime-manifest.json +2 -3
- package/tutorial/sample-service/src/database/drizzle-orm.d.ts +16 -0
- package/tutorial/sample-service/src/database/schema.ts +9 -10
- package/tutorial/sample-service/src/inventory/forklift-mood.ts +4 -0
- package/tutorial/sample-service/src/inventory/inventory-service.ts +18 -1
- package/tutorial/sample-service/src/inventory/warehouse-lore.ts +11 -0
- package/tutorial/sample-service/src/orders/order-service.ts +3 -2
- package/tutorial/sample-service/src/orders/order.ts +27 -5
- package/tutorial/sample-service/src/payments/fraud-vibes.ts +4 -0
- package/tutorial/sample-service/src/payments/payment-gateway.ts +19 -2
- package/tutorial/sample-service/src/payments/raccoon-ledger.ts +9 -0
- package/dist/agent-cli-BR2j-2n5.js +0 -2
- package/dist/input-error-OLgB_h31.js +0 -11
- package/dist/profile-BQGaX8aX.js +0 -2
- package/dist/review-home-paths-6zZH-1c9.js +0 -2560
- package/dist/tutorial-trace-DrBvkaeL.js +0 -43
- package/src/tutorial-conversation.ts +0 -18
- package/tutorial/software-map.json +0 -139
- package/tutorial/trace.json +0 -20
package/tutorial/document.json
CHANGED
|
@@ -11,25 +11,7 @@
|
|
|
11
11
|
"children": [
|
|
12
12
|
{
|
|
13
13
|
"type": "markdown",
|
|
14
|
-
"markdown": "A
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"type": "tutorial",
|
|
18
|
-
"kind": "conversation",
|
|
19
|
-
"conversation": {
|
|
20
|
-
"version": 1,
|
|
21
|
-
"title": "How this Review was made",
|
|
22
|
-
"messages": [
|
|
23
|
-
{
|
|
24
|
-
"role": "user",
|
|
25
|
-
"body": "Create a Review of the feature we just worked on."
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"role": "assistant",
|
|
29
|
-
"body": "Ok, I'm on it..."
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
}
|
|
14
|
+
"markdown": "A whiteboard is a guided, interactive explanation of a code change. Code,\ndiffs, and diagrams live in one document.\n"
|
|
33
15
|
},
|
|
34
16
|
{
|
|
35
17
|
"type": "markdown",
|
|
@@ -41,42 +23,42 @@
|
|
|
41
23
|
},
|
|
42
24
|
{
|
|
43
25
|
"type": "markdown",
|
|
44
|
-
"markdown": "###
|
|
26
|
+
"markdown": "### Read code like your editor\n\nThe editor below is live. Hover a symbol to see its type. **Go to\nDefinition** and **Find References** use the same keys as your editor.\n"
|
|
45
27
|
},
|
|
46
28
|
{
|
|
47
29
|
"type": "code_peek",
|
|
48
|
-
"source": "head/src/orders/order-service.ts#L13-
|
|
30
|
+
"source": "head/src/orders/order-service.ts#L13-L30",
|
|
49
31
|
"caption": "Order service creates the order"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"type": "markdown",
|
|
53
|
-
"markdown": "Prose in the review also supports [links to code](review-source:head/src/orders/order-service.ts#L13-L29).\n"
|
|
54
32
|
}
|
|
55
33
|
]
|
|
56
34
|
},
|
|
57
35
|
{
|
|
58
36
|
"type": "section",
|
|
59
|
-
"title": "
|
|
37
|
+
"title": "Diffs and lenses",
|
|
60
38
|
"children": [
|
|
61
39
|
{
|
|
62
40
|
"type": "markdown",
|
|
63
|
-
"markdown": "
|
|
41
|
+
"markdown": "The **Diff** tab shows the whole change between the pinned base and head.\ndiffr folds unchanged structure so you read only what moved; select a fold to\nexpand it.\n"
|
|
64
42
|
},
|
|
65
43
|
{
|
|
66
44
|
"type": "tutorial",
|
|
67
45
|
"kind": "view",
|
|
68
|
-
"view": "
|
|
69
|
-
"label": "
|
|
46
|
+
"view": "diff",
|
|
47
|
+
"label": "Open the diff"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "markdown",
|
|
51
|
+
"markdown": "**Lenses** split a change into the parts that matter. Select a lens to\nfilter the diff to just those lines. Mark lines viewed and the remaining\ncounts go down.\n\nAI summaries for folded code are opt-in under **Settings → Diff display and\nAI summaries**.\n"
|
|
70
52
|
}
|
|
71
53
|
]
|
|
72
54
|
},
|
|
73
55
|
{
|
|
74
56
|
"type": "section",
|
|
75
|
-
"title": "Interactive
|
|
57
|
+
"title": "Interactive diagrams",
|
|
76
58
|
"children": [
|
|
77
59
|
{
|
|
78
60
|
"type": "markdown",
|
|
79
|
-
"markdown": "The sequence diagram connects the checkout request to fulfillment. Select
|
|
61
|
+
"markdown": "The sequence diagram connects the checkout request to fulfillment. Select\n**Tour** to walk it fullscreen; each message opens its supporting code.\n"
|
|
80
62
|
},
|
|
81
63
|
{
|
|
82
64
|
"type": "sequence",
|
|
@@ -104,7 +86,7 @@
|
|
|
104
86
|
"to": "repository",
|
|
105
87
|
"label": "Save order",
|
|
106
88
|
"style": "call",
|
|
107
|
-
"source": "head/src/orders/order-service.ts#L13-
|
|
89
|
+
"source": "head/src/orders/order-service.ts#L13-L30"
|
|
108
90
|
},
|
|
109
91
|
{
|
|
110
92
|
"type": "step",
|
|
@@ -134,30 +116,33 @@
|
|
|
134
116
|
},
|
|
135
117
|
{
|
|
136
118
|
"type": "markdown",
|
|
137
|
-
"markdown": "The database view groups writes by use case. Its operations open
|
|
119
|
+
"markdown": "The database view groups reads and writes by use case. Its operations open\ncode too.\n"
|
|
138
120
|
},
|
|
139
121
|
{
|
|
140
122
|
"type": "database_lens",
|
|
141
123
|
"title": "Order storage",
|
|
142
124
|
"actors": {
|
|
143
125
|
"orderService": {
|
|
144
|
-
"label": "Order service"
|
|
145
|
-
"softwareMapPath": "orderService.application.orders"
|
|
126
|
+
"label": "Order service"
|
|
146
127
|
},
|
|
147
128
|
"worker": {
|
|
148
|
-
"label": "Fulfillment worker"
|
|
149
|
-
"softwareMapPath": "orderService.fulfillment.worker"
|
|
129
|
+
"label": "Fulfillment worker"
|
|
150
130
|
}
|
|
151
131
|
},
|
|
152
132
|
"stores": {
|
|
153
133
|
"orderDatabase": {
|
|
154
134
|
"label": "Order database",
|
|
155
135
|
"storage": "relational",
|
|
156
|
-
"softwareMapPath": "orderService.data.ordersDatabase",
|
|
157
136
|
"collections": {
|
|
158
137
|
"orders": {
|
|
159
138
|
"label": "orders",
|
|
160
139
|
"fields": {
|
|
140
|
+
"id": {
|
|
141
|
+
"label": "id",
|
|
142
|
+
"dataType": "text",
|
|
143
|
+
"primaryKey": true,
|
|
144
|
+
"example": "order-customer-42"
|
|
145
|
+
},
|
|
161
146
|
"customerId": {
|
|
162
147
|
"label": "customerId",
|
|
163
148
|
"dataType": "text",
|
|
@@ -178,7 +163,8 @@
|
|
|
178
163
|
"dataType": "timestamp",
|
|
179
164
|
"example": "2026-08-10T12:00:00Z"
|
|
180
165
|
}
|
|
181
|
-
}
|
|
166
|
+
},
|
|
167
|
+
"source": "head/src/database/schema.ts#L3-L9"
|
|
182
168
|
}
|
|
183
169
|
}
|
|
184
170
|
}
|
|
@@ -213,63 +199,18 @@
|
|
|
213
199
|
]
|
|
214
200
|
}
|
|
215
201
|
]
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"type": "tutorial",
|
|
219
|
-
"kind": "feature",
|
|
220
|
-
"feature": "softwareMap",
|
|
221
|
-
"children": [
|
|
222
|
-
{
|
|
223
|
-
"type": "markdown",
|
|
224
|
-
"markdown": "The experimental **Map** moves from the order system to its components and\ncode. Select a node to explore the sample service.\n"
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
"type": "tutorial",
|
|
228
|
-
"kind": "view",
|
|
229
|
-
"view": "map",
|
|
230
|
-
"label": "Open the software map"
|
|
231
|
-
}
|
|
232
|
-
]
|
|
233
|
-
}
|
|
234
|
-
]
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
"type": "section",
|
|
238
|
-
"title": "Agent traces",
|
|
239
|
-
"children": [
|
|
240
|
-
{
|
|
241
|
-
"type": "markdown",
|
|
242
|
-
"markdown": "Trace quotes connect a Review to the agent conversation behind a change.\nSelect this quote from an illustrative session to read it in context:\n"
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"type": "trace_quote",
|
|
246
|
-
"traceId": "tutorial-trace",
|
|
247
|
-
"eventId": "0",
|
|
248
|
-
"text": "we want to have one shared server / source of truth for all agent chats."
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
"type": "markdown",
|
|
252
|
-
"markdown": "To capture your own sessions, open **Preferences → Settings → Experimental\nFeatures → Trace capture**. Enter your S3/R2 bucket credentials and choose\n**Enable**. Have everyone on your team do this (with the same bucket credentials) to sync and review each other's traces.\n\nTrace capture is off by default; this sample works without setup.\n"
|
|
253
202
|
}
|
|
254
203
|
]
|
|
255
204
|
},
|
|
256
205
|
{
|
|
257
206
|
"type": "section",
|
|
258
|
-
"title": "
|
|
207
|
+
"title": "You're all done",
|
|
259
208
|
"children": [
|
|
260
209
|
{
|
|
261
210
|
"type": "markdown",
|
|
262
|
-
"markdown": "To connect Whiteboard to your agents, open **Preferences
|
|
211
|
+
"markdown": "To connect Whiteboard to your agents, open **Preferences → Settings**. To\nrevisit setup or take this tour again, open **Preferences → Getting Started**.\n"
|
|
263
212
|
}
|
|
264
213
|
]
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
"type": "software_map",
|
|
268
|
-
"mapVersionId": "tutorial-map-base"
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
"type": "software_map",
|
|
272
|
-
"mapVersionId": "tutorial-map-head"
|
|
273
214
|
}
|
|
274
215
|
]
|
|
275
216
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"reviewFiles": ["document.json", "
|
|
3
|
+
"reviewFiles": ["document.json", "lenses.json"],
|
|
4
4
|
"requiredPaths": [
|
|
5
5
|
"sample-service/package.json",
|
|
6
6
|
"document.json",
|
|
7
|
-
"
|
|
8
|
-
"software-map.json",
|
|
7
|
+
"lenses.json",
|
|
9
8
|
"pins.json",
|
|
10
9
|
"git-stub/HEAD"
|
|
11
10
|
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The sample has no dependencies; this declares the slice of drizzle-orm it uses.
|
|
2
|
+
declare module "drizzle-orm/pg-core" {
|
|
3
|
+
interface Column {
|
|
4
|
+
primaryKey(): Column;
|
|
5
|
+
notNull(): Column;
|
|
6
|
+
defaultNow(): Column;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function text(name: string): Column;
|
|
10
|
+
export function integer(name: string): Column;
|
|
11
|
+
export function timestamp(name: string): Column;
|
|
12
|
+
export function pgTable(
|
|
13
|
+
name: string,
|
|
14
|
+
columns: Record<string, Column>,
|
|
15
|
+
): Record<string, Column>;
|
|
16
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} as const;
|
|
1
|
+
import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
export const orders = pgTable("orders", {
|
|
4
|
+
id: text("id").primaryKey(),
|
|
5
|
+
customerId: text("customer_id").notNull(),
|
|
6
|
+
totalCents: integer("total_cents").notNull(),
|
|
7
|
+
status: text("status").notNull(),
|
|
8
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
9
|
+
});
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type { CheckoutItem } from "../orders/order.js";
|
|
1
|
+
import type { CheckoutItem, Sku } from "../orders/order.js";
|
|
2
|
+
import { FORKLIFT_MOOD } from "./forklift-mood.js";
|
|
3
|
+
import { blameTheGremlins, countShelvesTwice } from "./warehouse-lore.js";
|
|
2
4
|
|
|
3
5
|
export class InventoryService {
|
|
6
|
+
private readonly held = new Map<string, number>();
|
|
7
|
+
|
|
4
8
|
reserve(items: readonly CheckoutItem[]): void {
|
|
5
9
|
const unavailable = items.find((item) => item.quantity < 1);
|
|
6
10
|
|
|
@@ -8,4 +12,17 @@ export class InventoryService {
|
|
|
8
12
|
throw new Error(`Invalid quantity for ${unavailable.sku}`);
|
|
9
13
|
}
|
|
10
14
|
}
|
|
15
|
+
|
|
16
|
+
release(items: readonly CheckoutItem[]): void {
|
|
17
|
+
for (const item of items) {
|
|
18
|
+
this.held.delete(item.sku);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** How sure the warehouse is about a shelf, given the forklift's mood. */
|
|
23
|
+
audit(sku: Sku): string {
|
|
24
|
+
if (countShelvesTwice(sku) === 0) return blameTheGremlins(sku);
|
|
25
|
+
|
|
26
|
+
return `${sku} was counted while the forklift felt ${FORKLIFT_MOOD}`;
|
|
27
|
+
}
|
|
11
28
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Sku } from "../orders/order.js";
|
|
2
|
+
|
|
3
|
+
/** Every shelf is counted twice, because the first count is always wrong. */
|
|
4
|
+
export function countShelvesTwice(sku: Sku): number {
|
|
5
|
+
return sku.length * 2;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** When stock goes missing, it was them. */
|
|
9
|
+
export function blameTheGremlins(sku: Sku): string {
|
|
10
|
+
return `Gremlins took the last ${sku}`;
|
|
11
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InventoryService } from "../inventory/inventory-service.js";
|
|
2
2
|
import type { PaymentGateway } from "../payments/payment-gateway.js";
|
|
3
|
-
import type { CheckoutRequest, Order } from "./order.js";
|
|
3
|
+
import type { Cents, CheckoutRequest, Order } from "./order.js";
|
|
4
4
|
import type { OrdersRepository } from "./orders-repository.js";
|
|
5
5
|
|
|
6
6
|
export class OrderService {
|
|
@@ -10,8 +10,9 @@ export class OrderService {
|
|
|
10
10
|
private readonly orders: OrdersRepository,
|
|
11
11
|
) {}
|
|
12
12
|
|
|
13
|
+
/** Reserves the stock, charges the customer, and saves a pending order. */
|
|
13
14
|
placeOrder(request: CheckoutRequest): Order {
|
|
14
|
-
const totalCents = request.items.reduce(
|
|
15
|
+
const totalCents: Cents = request.items.reduce(
|
|
15
16
|
(sum, item) => sum + item.quantity * item.unitPriceCents,
|
|
16
17
|
0,
|
|
17
18
|
);
|
|
@@ -1,21 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
/** Where an order is in its short, eventful life. */
|
|
2
|
+
export type OrderStatus =
|
|
3
|
+
/** Charged, but still in the building. */
|
|
4
|
+
| "pending"
|
|
5
|
+
/** Waiting its turn on the fulfillment queue. */
|
|
6
|
+
| "queued"
|
|
7
|
+
/** Out the door. Regret is not a refund reason. */
|
|
8
|
+
| "fulfilled";
|
|
2
9
|
|
|
10
|
+
/** A stock-keeping unit, like `SKU-RUBBER-DUCK`. */
|
|
11
|
+
export type Sku = `SKU-${string}`;
|
|
12
|
+
|
|
13
|
+
/** Money in whole cents, because floats cannot be trusted with money. */
|
|
14
|
+
export type Cents = number;
|
|
15
|
+
|
|
16
|
+
/** One line of a cart. */
|
|
3
17
|
export interface CheckoutItem {
|
|
4
|
-
|
|
18
|
+
/** What the customer wants. */
|
|
19
|
+
sku: Sku;
|
|
20
|
+
/** How many they want. Zero is a cry for help. */
|
|
5
21
|
quantity: number;
|
|
6
|
-
|
|
22
|
+
/** The price of one unit, before the payment gateway takes its cut. */
|
|
23
|
+
unitPriceCents: Cents;
|
|
7
24
|
}
|
|
8
25
|
|
|
26
|
+
/** An order the service has accepted and charged for. */
|
|
9
27
|
export interface Order {
|
|
10
|
-
|
|
28
|
+
/** Derived from the customer, so each customer gets one order. Allegedly. */
|
|
29
|
+
id: `order-${string}`;
|
|
11
30
|
customerId: string;
|
|
12
31
|
items: readonly CheckoutItem[];
|
|
13
|
-
|
|
32
|
+
/** Every line's quantity times its unit price, in cents. */
|
|
33
|
+
totalCents: Cents;
|
|
14
34
|
status: OrderStatus;
|
|
15
35
|
}
|
|
16
36
|
|
|
37
|
+
/** What the checkout API hands the order service. */
|
|
17
38
|
export interface CheckoutRequest {
|
|
18
39
|
customerId: string;
|
|
19
40
|
items: readonly CheckoutItem[];
|
|
41
|
+
/** An opaque token from the payment provider. Never log it. */
|
|
20
42
|
paymentToken: string;
|
|
21
43
|
}
|
|
@@ -1,12 +1,29 @@
|
|
|
1
|
+
import type { Cents } from "../orders/order.js";
|
|
2
|
+
import { vibeCheck } from "./fraud-vibes.js";
|
|
3
|
+
import { RACCOON_ON_DUTY, nervouslyRound } from "./raccoon-ledger.js";
|
|
4
|
+
|
|
1
5
|
export interface PaymentReceipt {
|
|
2
6
|
chargeId: string;
|
|
3
|
-
amountCents:
|
|
7
|
+
amountCents: Cents;
|
|
8
|
+
/** Who signed off on the charge. */
|
|
9
|
+
approvedBy: typeof RACCOON_ON_DUTY;
|
|
4
10
|
}
|
|
5
11
|
|
|
6
12
|
export class PaymentGateway {
|
|
7
13
|
charge(paymentToken: string, amountCents: number): PaymentReceipt {
|
|
8
14
|
if (!paymentToken) throw new Error("A payment token is required");
|
|
9
15
|
|
|
10
|
-
return {
|
|
16
|
+
return {
|
|
17
|
+
chargeId: `charge-${amountCents}`,
|
|
18
|
+
amountCents,
|
|
19
|
+
approvedBy: RACCOON_ON_DUTY,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Refunds a receipt, provided the vibes allow it. */
|
|
24
|
+
refund(receipt: PaymentReceipt, paymentToken: string): Cents {
|
|
25
|
+
if (vibeCheck(paymentToken) > 0.5) return 0;
|
|
26
|
+
|
|
27
|
+
return nervouslyRound(receipt.amountCents);
|
|
11
28
|
}
|
|
12
29
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Cents } from "../orders/order.js";
|
|
2
|
+
|
|
3
|
+
/** The ledger is kept by a raccoon. It has never been audited. */
|
|
4
|
+
export const RACCOON_ON_DUTY = "Gerald";
|
|
5
|
+
|
|
6
|
+
/** Rounds to the nearest cent, then rounds again out of anxiety. */
|
|
7
|
+
export function nervouslyRound(cents: Cents): Cents {
|
|
8
|
+
return Math.round(Math.round(cents));
|
|
9
|
+
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//#region src/review-api/input-error.ts
|
|
2
|
-
/** Deliberately safe to show to API clients, unlike filesystem/provider errors. */
|
|
3
|
-
var ReviewInputError = class extends Error {
|
|
4
|
-
status;
|
|
5
|
-
constructor(message, status = 400) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.status = status;
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
//#endregion
|
|
11
|
-
export { ReviewInputError as t };
|
package/dist/profile-BQGaX8aX.js
DELETED