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 | ;; shadow-cljs builds for the portofel client (ROOMS stack in CLJS — chat
;; (sueta) is the canon this scaffold mirrors; dev/docs/CLJS.md is the law).
;;
;; The shared rooms core — ardegazu.rooms.js and ardegazu.rooms.lib.* — is NOT
;; in this repo: it is ardegazu-rooms-kit's own sources, compiled off the
;; classpath (client/deps.edn adds node_modules/ardegazu-rooms-kit/src, and the
;; sha pin in package.json decides which sha sits there). shadow compiles them
;; exactly like your own namespaces, so they land in the modules below by the
;; same lowest-common-ancestor rule; nothing here has to name the kit.
;;
;; :app — the browser build. Unlike the kits (external ESM imports), an APP
;; bundles its npm deps: the libp2p/helia/@orbitdb family is plain ESM in
;; node_modules, which shadow's default :browser bundling consumes. OUR OWN kits
;; are not among them — id-kit, social-kit, wallet-kit and rooms-kit (and banca's
;; pure namespaces) are ClojureScript SOURCE off the classpath, exactly like the
;; rooms core above; client/deps.edn states the rule, and scripts/build.mjs gates
;; that no chunk links a kit dist.
;;
;; :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 two dynamic boundaries REAL, and scripts/build.mjs
;; gates all three. Portofel has NO room of its own — the :room chunk is the
;; WALLET ENGINE (the bank-session stack), kept under its scaffold name because
;; the build gates know the chunk split by these names:
;; :main first paint — i18n + config + the empty/boot screen
;; :room the whole p2p stack (libp2p v2, Helia, @orbitdb/core, the mailbox,
;; banca's fold, the wallet UI), loaded via shadow.lazy at boot
;; :social ardegazu.social.app-boot/attach-social — the social ENGINE, whose
;; only entry is portofel.social
;;
;; :asset-path is RELATIVE — one build must serve at https://portofel.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:app`, the :testlib RELEASE and the black-box
;; suite, in that order. The testlib build belongs IN the script: test-dist/ is
;; gitignored, so without it the vectors run against whatever a previous
;; session happened to compile — a gate that passes by not running, exactly
;; what deps.edn's cljfmt note warns about.
{: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.
;; :use-index-files true — without it shadow's undertow file handler gets NO
;; welcome files (it only sets them from this key), so a directory request
;; ("/", "/id/") falls through to the push-state handler, which 404s any
;; request whose Accept header lacks text/html (curl, fetch). With it, "/"
;; serves index.html from the first root that has one.
:dev-http {5173 {:roots ["public" "dist-dev"] :push-state/index "index.html" :use-index-files true}
4173 {:roots ["public" "dist-dev"] :push-state/index "index.html" :use-index-files true}}
: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 portofel.main/init}
:room {:entries [portofel.room]
:depends-on #{:main}}
:social {:entries [portofel.social]
:depends-on #{:room}}}}
;; The black-box test façade: everything test/*.test.mjs may touch, and the
;; ONLY thing it may touch — vectors run against this build's output, never
;; against src/ (a vector that reads the source pins the source rather than
;; what ships).
: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 [portofel.testlib]
:exports {APP_SALT portofel.config/APP-SALT
NS portofel.config/NS
catalogKeys portofel.testlib/catalog-keys
catalogValue portofel.testlib/catalog-value
;; --- the pure wallet decisions (lib/model.cljs) ---
tokenOfPaste portofel.lib.model/token-of-paste
isV1Token portofel.lib.model/v1-token?
payablePartition portofel.lib.model/payable-partition
;; --- in-flight tracking (lib/pending.cljs) ---
trackPending portofel.lib.pending/track!}}}}}}
|