1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 | ;; shadow-cljs builds for the banca client (ROOMS stack in CLJS — chat
;; (sueta) is the canon this scaffold mirrors; dev/docs/CLJS.md is the law).
;;
;; NONE of the ardegazu kits are in this repo, and none of them is consumed as
;; a dist: rooms-kit, id-kit, social-kit and wallet-kit all put their `src` on
;; the classpath (client/deps.edn holds the rule and the reasoning; the sha pins
;; in package.json decide which sha sits there). shadow compiles their
;; namespaces exactly like your own, so they land in the modules below by the
;; same lowest-common-ancestor rule — which is the whole point, and why the
;; :social boundary below is real rather than notional. Nothing here has to name
;; a kit.
;;
;; :app — the browser build. An APP bundles its npm deps rather than leaving
;; them external: the libp2p/helia/@orbitdb family is plain ESM in node_modules,
;; which shadow's default :browser bundling consumes.
;;
;; :optimizations :simple, NOT :advanced — the safe default for a fresh app, and
;; where board still is. Almost every line below the app boundary is interop
;; with untyped ESM (@orbitdb/core ships no type declarations, and helia/libp2p
;; types never reach the CLJS side); :simple removes the externs risk class
;; entirely. (game1's live stack is :advanced because its surface is small and
;; typed; this one is neither.)
;;
;; chat has since moved this same stack to :advanced and measured main.js
;; 236 KB gz -> 91 KB gz, on the observation that Closure never renames a
;; string-keyed property access, so the whole untyped-ESM surface is
;; renaming-IMMUNE. If you follow it, read chat's shadow-cljs.edn header and its
;; externs.js FIRST: what breaks under :advanced is not the libraries but our
;; own prototype installs (`(unchecked-set proto "handleFrames" …)` called by
;; dot-access), and the failure is a runtime TypeError at room boot, not a build
;; error.
;; NOTE :optimizations must live INSIDE :compiler-options — a top-level one is
;; silently ignored and the target default is used instead.
;;
;; Three modules keep the TS build's two dynamic boundaries REAL, and
;; scripts/build.mjs gates all three:
;; :main the lobby + i18n + config + room crypto — first paint
;; :room the whole p2p stack (libp2p v2, Helia, @orbitdb/core, the mailbox,
;; the room UI), loaded via shadow.lazy only when entering a room
;; :social banca.social AND the social kit's agent, loaded once a room is live
;;
;; THE THIRD BOUNDARY IS REAL AGAIN, and it is worth knowing why it stopped
;; being: while social-kit was consumed as a DIST, `ardegazu-wallet-kit`'s dist
;; imported it (it signs over social-kit's canonical JSON), lib/fold imports
;; wallet-kit, and the fold is the app — so the whole kit was a dependency of
;; :room and shadow placed it in the lowest common ancestor of :room and
;; :social, which is :room. That was a property of DIST LINKING, not of banca:
;; a dist is a bundle taken whole, so needing `canon` meant taking friends,
;; presence, invites and selfsync too. As source, the fold's dependency is
;; exactly `ardegazu.social.canon`, and everything else the agent needs follows
;; banca.social down into :social (room.js −28 KB gz at the change).
;;
;; So all three boundaries now cost a user something and scripts/build.mjs gates
;; all three. :main carries neither the social agent nor the wallet stack —
;; which is why app/rooms.cljs (the lobby) must never require lib/view or
;; lib/wallet — and the one piece of the social kit it DOES carry is
;; `ardegazu.social.join`'s hub chip, whose only dependency is
;; `ardegazu.social.text`.
;;
;; :asset-path is RELATIVE — one build must serve at https://banca.ardegazu.ro/ and
;; /ipfs/<cid>/ alike.
;;
;; :js-options :resolve maps the bare `events` specifier onto the npm package's
;; browser entry. @orbitdb/core (+ lru, abstract-level) import `node:events`,
;; and the browser needs the real EventEmitter, not an empty shim. The
;; `@libp2p/config` entry aliases away a package this app must never pull in —
;; see src/js/libp2p-config-shim.mjs. scripts/build.mjs greps the emitted
;; bundle for both, because a wrong resolution here fails at RUNTIME inside
;; OrbitDB, not at build time.
;;
;; Expect :infer-warning lines from the app and kit namespaces: every one is a
;; `(.method ^js (unchecked-get self "_field") …)` call, where the hint is lost
;; because it sits on a macro form (dev/docs/CLJS.md). They are inert under
;; :simple — nothing is renamed — and they are exactly the list you would have
;; to pin in an externs.js before switching to :advanced. Do not "fix" them by
;; moving the hints onto the calls: that suppresses inference silently.
;;
;; :parallel-build false — many namespaces plus a :simple build is exactly the
;; combination CLJS.md says the gensym normalizer cannot repair. Serial
;; compilation is the only fix; only cold builds pay the time.
;;
;; `npm test` runs `cljfmt check`, then `shadow-cljs release testlib`, then
;; `node --test test/*.test.mjs`. The :testlib build below is what the golden
;; vectors are asserted against — never `src/`, because a vector that reads the
;; source pins the source rather than what ships.
{:deps {:aliases [:dev]}
;; BOTH dev ports serve public/ + dist-dev/ — the WATCH's own output tree,
;; never dist/. dist/ belongs to `ardz build` alone: it holds a RELEASE build
;; (goog.DEBUG=false → the PRODUCTION relay, and a service worker), and the
;; old `4173 {:roots ["dist"]}` arm served exactly that to a dev tab whenever
;; the watcher had not overwritten it yet (or the browser had cached it) —
;; two tabs of one dev session then sat on DIFFERENT relays and never met.
;; scripts/dev.mjs redirects the watch to dist-dev/assets via --config-merge;
;; smoke a release build with a standalone static server over dist/, never
;; through these ports.
:dev-http {5173 {:roots ["public" "dist-dev"] :use-index-files true :push-state/index "index.html"}
4173 {:roots ["public" "dist-dev"] :use-index-files true :push-state/index "index.html"}}
:builds
{:app
{:target :browser
:output-dir "dist/assets"
:asset-path "./assets"
:compiler-options {:optimizations :simple
:source-map false
:parallel-build false}
:js-options {:resolve {"events" {:target :npm :require "events/events.js"}
;; an npm package this app must never pull in — see
;; the shim's own comment
"@libp2p/config" {:target :file
:file "src/js/libp2p-config-shim.mjs"}}}
:module-loader true
:modules
{:main {:init-fn banca.main/init}
:room {:entries [banca.room]
:depends-on #{:main}}
:social {:entries [banca.social]
:depends-on #{:room}}}}
;; :testlib — the pure logic compiled to node-consumable ESM for the black-box
;; suite in test/*.test.mjs. Golden vectors run against THIS, never against
;; src/: a vector that reads the source pins the source, not what ships.
;;
;; :js-provider :import leaves any FOREIGN npm specifier as a real ESM import
;; for node to resolve at run time, instead of bundling it. It no longer has
;; any of our kits to leave alone: id-kit, social-kit and wallet-kit are
;; compiled in from source like every other namespace, so this module emits
;; ZERO imports today — one `Identity` class in the process by construction
;; rather than by hoping npm hoisted one copy. It stays because the moment a
;; tested namespace reaches a foreign package (`@noble/curves`, say, via
;; ardegazu.id.xkey) node must resolve it rather than shadow inline it.
:testlib
{:target :esm
:output-dir "test-dist"
:compiler-options {:optimizations :simple
:source-map false
:parallel-build false}
:js-options {:js-provider :import}
:modules
{:testlib
{:entries [banca.testlib]
:exports {APP_SALT banca.config/APP-SALT
NS banca.config/NS
;; --- the wallet-kit seam (lib/wallet.cljs) ---
DOM_PAY_ORD banca.lib.wallet/DOM-PAY-ORD
DOM_PAY_RCP banca.lib.wallet/DOM-PAY-RCP
AMT_MIN banca.lib.wallet/AMT-MIN
AMT_MAX banca.lib.wallet/AMT-MAX
CTX_MAX banca.lib.wallet/CTX-MAX
MEMO_MAX banca.lib.wallet/MEMO-MAX
NEUTRAL_UNIT banca.lib.wallet/NEUTRAL-UNIT
NEUTRAL_CODE banca.lib.wallet/NEUTRAL-CODE
DECLINE_REASONS banca.lib.wallet/DECLINE-REASONS
canon banca.lib.wallet/canon
currencyId banca.lib.wallet/currency-id
bankerOf banca.lib.wallet/banker-of
parseCurrency banca.lib.wallet/parse-currency
isPayableCurrency banca.lib.wallet/payable-currency?
unsignedOrder banca.lib.wallet/unsigned-order
orderPreimage banca.lib.wallet/order-preimage
orderShape banca.lib.wallet/order-shape
orderId banca.lib.wallet/order-id
verifyOrder banca.lib.wallet/verify-order
unsignedSettlement banca.lib.wallet/unsigned-settlement
settlementPreimage banca.lib.wallet/settlement-preimage
receiptOf banca.lib.wallet/receipt-of
verifySettlement banca.lib.wallet/verify-settlement
;; the two signing builders, so the banker's ack arms are driven
;; end to end in node (a signer is publicKeyB64 + signRaw)
buildIssuance banca.lib.wallet/build-issuance
buildSettlement banca.lib.wallet/build-settlement
;; the issuance receipt (wri) — the wrc seam's mirror image
DOM_PAY_ISS banca.lib.wallet/DOM-PAY-ISS
unsignedIssuance banca.lib.wallet/unsigned-issuance
issuancePreimage banca.lib.wallet/issuance-preimage
issuanceShape banca.lib.wallet/issuance-shape
issuanceKey banca.lib.wallet/issuance-key
issuanceOf banca.lib.wallet/issuance-of
verifyIssuance banca.lib.wallet/verify-issuance
;; --- BANK/1's op union (lib/protocol.cljs) ---
MAX_NAME banca.lib.protocol/MAX-NAME
MAX_SYM banca.lib.protocol/MAX-SYM
MAX_DEC banca.lib.protocol/MAX-DEC
MAX_REF banca.lib.protocol/MAX-REF
mkCharter banca.lib.protocol/mk-charter
mkOpen banca.lib.protocol/mk-open
mkAcct banca.lib.protocol/mk-acct
mkMint banca.lib.protocol/mk-mint
mkBurn banca.lib.protocol/mk-burn
mkPay banca.lib.protocol/mk-pay
mkAck banca.lib.protocol/mk-ack
mkLock banca.lib.protocol/mk-lock
mkClaim banca.lib.protocol/mk-claim
mkUnlock banca.lib.protocol/mk-unlock
validLock banca.lib.protocol/valid-lock?
validClaim banca.lib.protocol/valid-claim?
validUnlock banca.lib.protocol/valid-unlock?
opVersion banca.lib.protocol/version-of-op
mkRate banca.lib.protocol/mk-rate
mkReq banca.lib.protocol/mk-req
validOp banca.lib.protocol/valid-op?
validCharter banca.lib.protocol/valid-charter?
validOpen banca.lib.protocol/valid-open?
validAcct banca.lib.protocol/valid-acct?
validMint banca.lib.protocol/valid-mint?
validBurn banca.lib.protocol/valid-burn?
validPay banca.lib.protocol/valid-pay?
validAck banca.lib.protocol/valid-ack?
validRate banca.lib.protocol/valid-rate?
validReq banca.lib.protocol/valid-req?
opType banca.lib.protocol/op-type?
slotType banca.lib.protocol/slot-type?
bankerOnly banca.lib.protocol/banker-only?
;; --- the settlement fold (lib/fold.cljs) ---
BankFold banca.lib.fold/BankFold
;; --- the bank link (lib/link.cljs) ---
parseLink banca.lib.link/parse
fmtLink banca.lib.link/fmt
isBankLink banca.lib.link/bank?
linkSecret banca.lib.link/secret-of
linkBanker banca.lib.link/banker-of
linkVersion banca.lib.link/version-of
linkSupported banca.lib.link/supported?
LINK_MAX_VERSION banca.lib.link/MAX-VERSION
saltFor banca.config/salt-for
;; --- the resident bots' public banks (lib/publicbanks.cljs) ---
PUBLIC_BANKS banca.lib.publicbanks/PUBLIC-BANKS
validPublicBank banca.lib.publicbanks/valid-entry?
publicBanksAvailable banca.lib.publicbanks/available
;; --- the view model (lib/view.cljs) ---
;;
;; Everything the INTERFACE decides, exported so the interface's
;; decisions are black-box tested in node rather than clicked
;; through a browser. `paymentState` and `stateKey` are the two
;; that matter most: they are where the fold's `settled` becomes
;; the word `provisional`, and where an interface that blurred
;; provisional into final would first go wrong.
decOf banca.lib.view/dec-of
symOf banca.lib.view/sym-of
nameOf banca.lib.view/name-of
fmtUnits banca.lib.view/fmt-units
fmtMoney banca.lib.view/fmt-money
fmtSigned banca.lib.view/fmt-signed
parseUnits banca.lib.view/parse-units
amountError banca.lib.view/amount-error
paymentState banca.lib.view/payment-state
stateKey banca.lib.view/state-key
stateNoteKey banca.lib.view/state-note-key
whyKey banca.lib.view/why-key
isAcked banca.lib.view/acked?
isIssuance banca.lib.view/issuance?
isReceiptable banca.lib.view/receiptable?
accountState banca.lib.view/account-state
isMember banca.lib.view/member?
viewBalanceOf banca.lib.view/balance-of
labelOf banca.lib.view/label-of
openAccounts banca.lib.view/open-accounts
historyOf banca.lib.view/history
ledgerOf banca.lib.view/ledger
provisionalCount banca.lib.view/provisional-count
provisionalNet banca.lib.view/provisional-net
unpinnedCount banca.lib.view/unpinned-count
unpinnedNet banca.lib.view/unpinned-net
requestsFor banca.lib.view/requests-for
verifyLockReceipt banca.lib.wallet/verify-lock-receipt
ackable banca.lib.view/ackable
lockedCount banca.lib.view/locked-count
lockedNet banca.lib.view/locked-net
allFinal banca.lib.view/all-final?
knocks banca.lib.view/knocks
;; the ack seams store/ack! runs on — the three-way dispatch and
;; the artifact-ts hand-off, driven black-box in test/view.test.mjs
ackDispatch banca.lib.view/ack-dispatch
ackOpFor banca.lib.view/ack-op-for
adoptLabel banca.lib.view/adopt-label
defaultKnockName banca.lib.view/default-knock-name
charterError banca.lib.view/charter-error
payError banca.lib.view/pay-error
issueError banca.lib.view/issue-error
burnError banca.lib.view/burn-error
rateError banca.lib.view/rate-error
reqError banca.lib.view/req-error
;; presentation windows/buckets/filters — how much of an
;; unbounded list a screen renders at once, never how much the
;; fold keeps (history is never capped; paging is presentation)
PAGE_INIT banca.lib.view/PAGE-INIT
PAGE_STEP banca.lib.view/PAGE-STEP
pagePlan banca.lib.view/page-plan
dayKey banca.lib.view/day-key
groupDays banca.lib.view/group-days
FILTER_THRESHOLD banca.lib.view/FILTER-THRESHOLD
accountMatches banca.lib.view/account-matches?
filterAccounts banca.lib.view/filter-accounts
whoDesc banca.lib.view/who-desc
;; --- the catalogs, so a key a screen asks for must exist ---
catalogKeys banca.testlib/catalog-keys
catalogValue banca.testlib/catalog-value}}}}}}
|