@swissjs/swite 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.
Files changed (163) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.github/workflows/ci.yml +59 -0
  3. package/.github/workflows/publish.yml +50 -0
  4. package/.github/workflows/release.yml +53 -0
  5. package/BUILD_ANALYSIS.md +89 -0
  6. package/BUILD_STRATEGY.md +75 -0
  7. package/CHANGELOG.md +53 -0
  8. package/DIRECTIVE.md +488 -0
  9. package/__tests__/css-extraction.test.ts +261 -0
  10. package/__tests__/css-injection-integration.test.ts +247 -0
  11. package/__tests__/css-middleware.test.ts +191 -0
  12. package/__tests__/import-rewriter-bug.test.ts +135 -0
  13. package/dist/builder.d.ts +36 -0
  14. package/dist/builder.d.ts.map +1 -0
  15. package/dist/builder.js +772 -0
  16. package/dist/cache/compilation-cache.d.ts +33 -0
  17. package/dist/cache/compilation-cache.d.ts.map +1 -0
  18. package/dist/cache/compilation-cache.js +130 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +85 -0
  22. package/dist/config-loader.d.ts +8 -0
  23. package/dist/config-loader.d.ts.map +1 -0
  24. package/dist/config-loader.js +40 -0
  25. package/dist/config.d.ts +29 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +7 -0
  28. package/dist/dev/pythonDevManager.d.ts +12 -0
  29. package/dist/dev/pythonDevManager.d.ts.map +1 -0
  30. package/dist/dev/pythonDevManager.js +85 -0
  31. package/dist/env.d.ts +19 -0
  32. package/dist/env.d.ts.map +1 -0
  33. package/dist/env.js +112 -0
  34. package/dist/handlers/base-handler.d.ts +21 -0
  35. package/dist/handlers/base-handler.d.ts.map +1 -0
  36. package/dist/handlers/base-handler.js +38 -0
  37. package/dist/handlers/js-handler.d.ts +10 -0
  38. package/dist/handlers/js-handler.d.ts.map +1 -0
  39. package/dist/handlers/js-handler.js +87 -0
  40. package/dist/handlers/mjs-handler.d.ts +8 -0
  41. package/dist/handlers/mjs-handler.d.ts.map +1 -0
  42. package/dist/handlers/mjs-handler.js +44 -0
  43. package/dist/handlers/node-module-handler.d.ts +16 -0
  44. package/dist/handlers/node-module-handler.d.ts.map +1 -0
  45. package/dist/handlers/node-module-handler.js +267 -0
  46. package/dist/handlers/ts-handler.d.ts +11 -0
  47. package/dist/handlers/ts-handler.d.ts.map +1 -0
  48. package/dist/handlers/ts-handler.js +120 -0
  49. package/dist/handlers/ui-handler.d.ts +12 -0
  50. package/dist/handlers/ui-handler.d.ts.map +1 -0
  51. package/dist/handlers/ui-handler.js +182 -0
  52. package/dist/handlers/uix-handler.d.ts +12 -0
  53. package/dist/handlers/uix-handler.d.ts.map +1 -0
  54. package/dist/handlers/uix-handler.js +135 -0
  55. package/dist/hmr.d.ts +20 -0
  56. package/dist/hmr.d.ts.map +1 -0
  57. package/dist/hmr.js +265 -0
  58. package/dist/import-rewriter.d.ts +3 -0
  59. package/dist/import-rewriter.d.ts.map +1 -0
  60. package/dist/import-rewriter.js +351 -0
  61. package/dist/index.d.ts +14 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +13 -0
  64. package/dist/middleware/hmr-routes.d.ts +12 -0
  65. package/dist/middleware/hmr-routes.d.ts.map +1 -0
  66. package/dist/middleware/hmr-routes.js +97 -0
  67. package/dist/middleware/middleware-setup.d.ts +23 -0
  68. package/dist/middleware/middleware-setup.d.ts.map +1 -0
  69. package/dist/middleware/middleware-setup.js +596 -0
  70. package/dist/middleware/static-files.d.ts +15 -0
  71. package/dist/middleware/static-files.d.ts.map +1 -0
  72. package/dist/middleware/static-files.js +585 -0
  73. package/dist/proxy/SwiteProxyError.d.ts +6 -0
  74. package/dist/proxy/SwiteProxyError.d.ts.map +1 -0
  75. package/dist/proxy/SwiteProxyError.js +9 -0
  76. package/dist/proxy/proxyToPython.d.ts +28 -0
  77. package/dist/proxy/proxyToPython.d.ts.map +1 -0
  78. package/dist/proxy/proxyToPython.js +66 -0
  79. package/dist/resolver/bare-import-resolver.d.ts +9 -0
  80. package/dist/resolver/bare-import-resolver.d.ts.map +1 -0
  81. package/dist/resolver/bare-import-resolver.js +363 -0
  82. package/dist/resolver/symlink-registry.d.ts +13 -0
  83. package/dist/resolver/symlink-registry.d.ts.map +1 -0
  84. package/dist/resolver/symlink-registry.js +98 -0
  85. package/dist/resolver/url-resolver.d.ts +11 -0
  86. package/dist/resolver/url-resolver.d.ts.map +1 -0
  87. package/dist/resolver/url-resolver.js +268 -0
  88. package/dist/resolver/workspace-package-resolver.d.ts +10 -0
  89. package/dist/resolver/workspace-package-resolver.d.ts.map +1 -0
  90. package/dist/resolver/workspace-package-resolver.js +185 -0
  91. package/dist/resolver.d.ts +17 -0
  92. package/dist/resolver.d.ts.map +1 -0
  93. package/dist/resolver.js +191 -0
  94. package/dist/router/file-router.d.ts +19 -0
  95. package/dist/router/file-router.d.ts.map +1 -0
  96. package/dist/router/file-router.js +114 -0
  97. package/dist/server.d.ts +22 -0
  98. package/dist/server.d.ts.map +1 -0
  99. package/dist/server.js +122 -0
  100. package/dist/utils/cdn-fallback.d.ts +14 -0
  101. package/dist/utils/cdn-fallback.d.ts.map +1 -0
  102. package/dist/utils/cdn-fallback.js +36 -0
  103. package/dist/utils/file-path-resolver.d.ts +9 -0
  104. package/dist/utils/file-path-resolver.d.ts.map +1 -0
  105. package/dist/utils/file-path-resolver.js +187 -0
  106. package/dist/utils/generate-import-map-cli.d.ts +3 -0
  107. package/dist/utils/generate-import-map-cli.d.ts.map +1 -0
  108. package/dist/utils/generate-import-map-cli.js +32 -0
  109. package/dist/utils/generate-import-map.d.ts +21 -0
  110. package/dist/utils/generate-import-map.d.ts.map +1 -0
  111. package/dist/utils/generate-import-map.js +119 -0
  112. package/dist/utils/package-finder.d.ts +24 -0
  113. package/dist/utils/package-finder.d.ts.map +1 -0
  114. package/dist/utils/package-finder.js +161 -0
  115. package/dist/utils/package-registry.d.ts +36 -0
  116. package/dist/utils/package-registry.d.ts.map +1 -0
  117. package/dist/utils/package-registry.js +159 -0
  118. package/dist/utils/workspace.d.ts +6 -0
  119. package/dist/utils/workspace.d.ts.map +1 -0
  120. package/dist/utils/workspace.js +65 -0
  121. package/docs/IMPORT_REWRITING.md +164 -0
  122. package/docs/IMPORT_REWRITING_TROUBLESHOOTING.md +139 -0
  123. package/docs/PATH_RESOLUTION_GUIDE.md +221 -0
  124. package/package.json +49 -0
  125. package/src/adapters/proxy/SwiteProxyError.ts +12 -0
  126. package/src/adapters/proxy/proxyToPython.ts +88 -0
  127. package/src/build-engine/builder.ts +960 -0
  128. package/src/cli.ts +109 -0
  129. package/src/config/config-loader.ts +46 -0
  130. package/src/config/config.ts +34 -0
  131. package/src/config/env.ts +98 -0
  132. package/src/dev-engine/handlers/base-handler.ts +68 -0
  133. package/src/dev-engine/handlers/js-handler.ts +134 -0
  134. package/src/dev-engine/handlers/mjs-handler.ts +65 -0
  135. package/src/dev-engine/handlers/node-module-handler.ts +339 -0
  136. package/src/dev-engine/handlers/ts-handler.ts +143 -0
  137. package/src/dev-engine/handlers/ui-handler.ts +105 -0
  138. package/src/dev-engine/handlers/uix-handler.ts +90 -0
  139. package/src/dev-engine/hmr/hmr-client-template.ts +122 -0
  140. package/src/dev-engine/hmr/hmr.ts +173 -0
  141. package/src/dev-engine/middleware/hmr-routes.ts +120 -0
  142. package/src/dev-engine/middleware/middleware-setup.ts +351 -0
  143. package/src/dev-engine/middleware/static-files.ts +728 -0
  144. package/src/dev-engine/pythonDevManager.ts +116 -0
  145. package/src/dev-engine/router/file-router.ts +164 -0
  146. package/src/dev-engine/server.ts +152 -0
  147. package/src/index.ts +26 -0
  148. package/src/internal/cache/compilation-cache.ts +182 -0
  149. package/src/internal/generate-import-map-cli.ts +40 -0
  150. package/src/internal/generate-import-map.ts +154 -0
  151. package/src/kernel/package-finder.ts +164 -0
  152. package/src/kernel/package-registry.ts +198 -0
  153. package/src/kernel/workspace.ts +62 -0
  154. package/src/resolution/bare-import-resolver.ts +400 -0
  155. package/src/resolution/cdn/cdn-fallback.ts +37 -0
  156. package/src/resolution/path/file-path-resolver.ts +190 -0
  157. package/src/resolution/path/path-fixup.ts +19 -0
  158. package/src/resolution/resolver.ts +198 -0
  159. package/src/resolution/rewriting/import-rewriter.ts +237 -0
  160. package/src/resolution/symlink-registry.ts +114 -0
  161. package/src/resolution/url-resolver.ts +231 -0
  162. package/src/resolution/workspace-package-resolver.ts +94 -0
  163. package/tsconfig.json +37 -0
package/DIRECTIVE.md ADDED
@@ -0,0 +1,488 @@
1
+ # DIRECTIVE — swite
2
+ > Last updated: 2026-05-19 · Owner: Kibologic · Repo: kibologic/swite
3
+
4
+ ---
5
+
6
+ ## Status
7
+ `IN ACTIVE DEVELOPMENT` — Core dev server functional. Python service integration not yet implemented. This is the primary sprint focus.
8
+
9
+ ---
10
+
11
+ ## Current Sprint
12
+
13
+ ### S-01 — swiss.config.ts Python Service Schema
14
+ Define the `services.python` config block type. This is the foundation everything else in this sprint depends on.
15
+
16
+ Target API:
17
+ ```ts
18
+ export default defineConfig({
19
+ server: { port: 3000 },
20
+ services: {
21
+ python: {
22
+ entry: './services/main.py',
23
+ port: 8000,
24
+ autoStart: true,
25
+ healthCheck: '/health',
26
+ env: {},
27
+ }
28
+ }
29
+ })
30
+ ```
31
+
32
+ Acceptance: `defineConfig` accepts and types the `services.python` block without errors. Unknown fields are rejected by TypeScript.
33
+
34
+ ---
35
+
36
+ ### S-02 — proxyToPython Utility
37
+ Internal proxy function that Node route handlers use to communicate with the Python service. Lives in `packages/swite/src/proxy.ts`.
38
+
39
+ Requirements:
40
+ - Accepts path + RequestInit options
41
+ - Reads `PYTHON_SERVICE_URL` from env (default: http://localhost:8000)
42
+ - Attaches `X-Internal-Token` header from env
43
+ - Throws typed `SwiteProxyError` on non-2xx responses
44
+ - Fully typed — no `any`, generic return type
45
+
46
+ Acceptance: A route handler can call `proxyToPython<MyType>('/some/path')` and get back a typed response.
47
+
48
+ ---
49
+
50
+ ### S-03 — CLI Dev Process Manager
51
+ Extend `swite dev` command to spawn and manage the Python process when `services.python.autoStart` is true.
52
+
53
+ Sequence:
54
+ 1. Read `swiss.config.ts` — check if `services.python` is defined
55
+ 2. Spawn Python via `uvicorn services.main:app --port {port} --reload`
56
+ 3. Poll `healthCheck` endpoint every 500ms — max 30s timeout
57
+ 4. Once healthy — start Node server
58
+ 5. Stream both process logs prefixed `[node]` and `[python]`
59
+ 6. On Python crash — log prominently, continue Node in degraded mode
60
+ 7. On Ctrl+C — kill both processes cleanly
61
+
62
+ Acceptance: Running `swite dev` in Alpine ERP boots both servers. Killing one does not orphan the other.
63
+
64
+ ---
65
+
66
+ ### S-04 — Production Mode
67
+ `swite start` must not attempt to spawn Python. Reads `PYTHON_SERVICE_URL` from env only.
68
+
69
+ Acceptance: `swite start` with no `PYTHON_SERVICE_URL` set logs a clear warning but does not crash.
70
+
71
+ ---
72
+
73
+ ### ✅ S-06 — Fix module resolver — search parent node_modules (COMPLETED 2026-03-26)
74
+ Added `path.join(path.dirname(context.root), "node_modules")` to `nodeModulesLocations`
75
+ in `src/resolver/bare-import-resolver.ts`. Resolver now checks parent directory node_modules
76
+ in addition to app root and workspace root.
77
+
78
+ ---
79
+
80
+ ### ✅ S-08 — Support monorepo rootDir in dev server (COMPLETED 2026-02-28)
81
+
82
+ Swite's serve root must be configurable to cover the full monorepo.
83
+ Apps import from sibling `packages/` and `modules/` directories outside
84
+ the app folder. Add `rootDir` to `swiss.config.ts` schema — distinct from
85
+ `root` (app source directory). The dev server must be able to resolve and
86
+ serve files anywhere within `rootDir`.
87
+
88
+ **Files modified:**
89
+
90
+ - `src/server.ts` — added `rootDir` to `SwiteConfig`, exported `defineConfig`, resolves rootDir to absolute
91
+ - `src/resolver.ts` — `ModuleResolver` accepts optional `rootDir`, passes to `UrlResolverContext`
92
+ - `src/resolver/url-resolver.ts` — `toUrl` checks rootDir before workspace root to generate clean URLs
93
+ - `src/utils/file-path-resolver.ts` — `resolveFilePath` uses rootDir as fallback when workspace root is null
94
+ - `src/handlers/base-handler.ts` — `HandlerContext` includes rootDir, passes to resolveFilePath
95
+ - `src/middleware/middleware-setup.ts` — `MiddlewareConfig` includes rootDir, passes to handlerContext
96
+ - `src/index.ts` — exports `defineConfig`
97
+ - `src/resolver/bare-import-resolver.ts` — removed dead code (lines 128–262) that blocked build
98
+
99
+ **Verified in alpine-erp (2026-02-28):**
100
+
101
+ ```text
102
+ GET /packages/core/src/index.ui → 200 ✅
103
+ GET /modules/dashboard/src/index.ui → 200 ✅
104
+ GET /modules/users/src/index.ui → 200 ✅
105
+ GET /modules/settings/src/index.ui → 200 ✅
106
+ ```
107
+
108
+ ---
109
+
110
+ ### ✅ S-09 — Fix MIME type for .ui/.uix and .ts responses (COMPLETED 2026-02-28)
111
+
112
+ Swite was returning `text/html` for `.uix` and `.ts` non-cached responses.
113
+ `res.send()` in Express defaults to `text/html` when no Content-Type is set.
114
+
115
+ **Root cause:** `uix-handler.ts` and `ts-handler.ts` set Content-Type on the
116
+ cached path but not on the non-cached (compile) path.
117
+
118
+ **Fix:** Added `res.setHeader("Content-Type", "application/javascript; charset=utf-8")`
119
+ before `res.send()` in:
120
+
121
+ - `src/handlers/uix-handler.ts` (line 175)
122
+ - `src/handlers/ts-handler.ts` (line 166)
123
+
124
+ **Verified:** `App.uix`, `index.ts`, `index.ui` all return `Content-Type: application/javascript`.
125
+
126
+ ---
127
+
128
+ ### ✅ S-07 — Fix findSwissLibMonorepo path (COMPLETED 2026-03-26)
129
+ `findSwissLibMonorepo` in `src/utils/package-finder.ts` now scans immediate
130
+ subdirectories of each ancestor (excluding node_modules) for a `swiss-lib/` child.
131
+ Handles `SWS/swiss-lib/` and any other one-level-deep monorepo layouts.
132
+
133
+ ---
134
+
135
+ ## Blocked
136
+ _Nothing blocked currently._
137
+
138
+ ---
139
+
140
+ ## Swiss Gaps
141
+ > Gaps discovered in swiss-lib during swite development. Each becomes a swiss-lib task.
142
+
143
+ _None discovered yet. Populate as development proceeds._
144
+
145
+ ---
146
+
147
+ ## Compiler Gaps
148
+ > Discovered during alpine-mobile Phase 5 build (2026-03-26). All fixed as hotfixes in swite/dist/ — need porting to swite source before next version cut.
149
+
150
+ - **CG-01** CLI entry hardcoded as `.ts` — should resolve `.ui` — FIXED in source `src/cli.ts` line 76
151
+ - **CG-02** `@swissjs/*` and `@skltn/*` not in externals — bundled instead of left as browser imports — FIXED in source `src/builder.ts` nodeBuiltins
152
+ - **CG-03** `findSwissFiles`/`findFiles` do not follow NTFS junctions (`isSymbolicLink()` check missing) — FIXED in source `src/builder.ts`
153
+ - **CG-04** Traversal enters `node_modules` via symlinks — `node_modules` not excluded from junction traversal — FIXED in source `src/builder.ts`
154
+ - **CG-05** `UiCompiler` rewrites `.ui` imports to `.js` but emits `.tsx` files — `jsTsxFallbackPlugin` added — FIXED in source `src/builder.ts`
155
+ - **CG-06** Compiler emits named exports only — default imports fail at bundle time — `export default` injected post-compile — FIXED in source `src/builder.ts`
156
+
157
+ ---
158
+
159
+ ## Session Log
160
+
161
+ ### 2026-03-26
162
+
163
+ - Logged CG-01 through CG-06 from alpine-mobile Phase 5 build
164
+ - All 6 fixed in swite/dist/ as hotfixes — need porting to swite source before next version cut
165
+ - Fixed CG-01 through CG-06 in swite source (src/cli.ts + src/builder.ts)
166
+ - swite tsc build fails on swiss-lib project reference errors (pre-existing TD-02) — dist updated via linter auto-compile
167
+ - Verified alpine-mobile build passes end-to-end: dist/index.js 30.5kb ✅
168
+ - Fixed S-06: parent node_modules added to bare-import-resolver nodeModulesLocations
169
+ - Fixed S-07: findSwissLibMonorepo now scans immediate subdirs one level deeper
170
+ - alpine-mobile build on Linux blocked by missing NTFS junctions (src/modules, src/packages) — pre-existing Linux env constraint, not caused by these changes
171
+ - Commit: 4cf8c6e
172
+ - Bumped version to 0.2.0 (commit fd039ce) — wrote CHANGELOG.md covering CG-01–06 and 0.1.0 baseline
173
+ - swiss-lib CG fixes committed (commit 6d9c296): CG-03/04/05 in compiler + core hookRegistry alignment + cli traversal
174
+
175
+ ---
176
+
177
+ ## Done
178
+ _Nothing completed yet. Append items here as sprints close._
179
+
180
+ ---
181
+
182
+ ## Versioning & Release Strategy (locked 2026-03-01)
183
+
184
+ ### Decisions
185
+ - Registry: npm public registry (MIT license)
186
+ - Scope: @swissjs/swite
187
+ - Cadence: milestone-based, versions with swiss-lib
188
+ - Changesets: @changesets/cli
189
+ - Pre-v1: publish 0.1.0 NOW alongside swiss-lib
190
+
191
+ ### Pipeline (LIVE — commit cefd6ef, 2026-03-02)
192
+
193
+ File: .github/workflows/ci.yml ✓
194
+ Trigger: push to main, all PRs
195
+ Jobs: pnpm install → pnpm build → pnpm test
196
+ changeset presence check on PRs (warn only)
197
+
198
+ File: .github/workflows/release.yml ✓
199
+ Trigger: push to main
200
+ Jobs: changesets/action — creates "Version Packages" PR
201
+ when .changeset/ has entries; publishes to npm
202
+ when version PR is merged; GitHub releases auto-created
203
+
204
+ File: .github/workflows/publish.yml ✓
205
+ Trigger: manual (workflow_dispatch)
206
+ Jobs: emergency re-publish with optional dry-run mode
207
+
208
+ ### Secrets required
209
+ NPM_TOKEN — same token as swiss-lib
210
+ CHANGESET_TOKEN — same token as swiss-lib
211
+ GITHUB_TOKEN — auto-provided
212
+
213
+ ### Pending tasks
214
+ S-05 — Fix workspace:* deps so swite installs
215
+ standalone without swiss-lib monorepo.
216
+ MUST be done before first npm publish.
217
+ Current workaround: link: overrides in
218
+ consuming repos (alpine-erp).
219
+
220
+ ### Known issues (to fix before publish)
221
+ - packages/cli has @swissjs/swite workspace:* dep
222
+ fixed to link:../../../swite for local builds
223
+ needs proper peer dep config for npm publish
224
+ - @swissjs/css Buffer conflict unrelated to swite
225
+
226
+ ### Brand Rule
227
+ Swite is a global build tool.
228
+ Remove any regional labels from all docs.
229
+
230
+ ---
231
+
232
+ ## Kibologic Foundational Decisions (locked 2026-03-01)
233
+
234
+ ### Security & Repository Hardening
235
+
236
+ Signed commits
237
+ Required on main branch in all kibologic repos
238
+ Enforced via branch protection rules
239
+ No unsigned commits merged to main
240
+
241
+ SECURITY.md
242
+ Required in every public repo
243
+ Contains: security@kibologic.com contact
244
+ Disclosure timeline: 90 days
245
+ CVE process: GitHub Security Advisories
246
+
247
+ CODEOWNERS
248
+ Required in every repo
249
+ Founder owns everything initially
250
+ Format: * @themba-kibologic
251
+ Expandable as team grows
252
+
253
+ CodeQL scanning
254
+ Enabled on all PRs in all repos
255
+ GitHub Advanced Security
256
+ Blocks merge if critical vulnerability found
257
+
258
+ Pre-commit hooks
259
+ Tool: gitleaks
260
+ Blocks commits containing secrets/tokens
261
+ Applied to all repos on dev machines
262
+ Also runs in CI as second layer
263
+
264
+ ### npm & Publishing Security
265
+
266
+ Automation tokens only for CI publish
267
+ Granular access tokens for human use
268
+ No local manual publish ever
269
+ 2FA mandatory on npm org accounts
270
+ Unpublish policy: never after public release
271
+ Deprecation only via npm deprecate command
272
+
273
+ ### GitHub Org Security
274
+
275
+ Dependabot enabled all repos
276
+ Secret scanning enabled all repos
277
+ CodeQL enabled all repos
278
+ Branch protection on main — all repos
279
+ Require 1 PR review
280
+ Require status checks to pass
281
+ Dismiss stale reviews
282
+ No admin bypass
283
+ CODEOWNERS required before merge
284
+
285
+ ### License & Legal
286
+
287
+ BSL 1.1 on Alpine ERP and enterprise packages
288
+ Change date: 2029-12-31 → Apache 2.0
289
+ Trademark intent-to-use filed for:
290
+ SwissJS, Alpine ERP, Swite
291
+ CLA required for all external contributors
292
+ SECURITY.md in every public repo
293
+ BSL notice in repo root AND in every release
294
+
295
+ ### Enterprise License Architecture
296
+
297
+ Format: signed JSON payload
298
+ Algorithm: ed25519
299
+ Private key: offline secure storage
300
+ Public key: embedded in backend only
301
+ Validation: backend only, never frontend only
302
+ Frontend role: feature visibility only
303
+ Offline validation: supported
304
+ Seat enforcement: hard block new user creation
305
+ Module enforcement: backend service layer guard
306
+ Self-hosted: license file in server env/config
307
+ SaaS: database-driven feature flags
308
+
309
+ ### Deployment
310
+
311
+ Static sites: Cloudflare Pages
312
+ swissjs.dev, alpineerp.com, kibologic.com
313
+ SaaS backend: Fly.io or equivalent
314
+ Self-hosted: Docker Compose first
315
+ Official distribution: Docker image
316
+ Database: managed PostgreSQL provider
317
+ Kubernetes: not initially
318
+
319
+ ### Domain & Email
320
+
321
+ All three domains on Cloudflare
322
+ SSL: Full strict
323
+ www → root redirect
324
+ HTTP → HTTPS
325
+ DNSSEC enabled
326
+ HSTS enabled
327
+ Email: Google Workspace or equivalent
328
+ Required addresses:
329
+ hello@kibologic.com
330
+ support@kibologic.com
331
+ legal@kibologic.com
332
+ SPF, DKIM, DMARC reject policy
333
+
334
+ ### Community & Support
335
+
336
+ Initial channels: GitHub Issues only
337
+ Discord: after measurable traffic
338
+ Governance: founder-led
339
+ CONTRIBUTING.md required in all repos
340
+ Issue templates required in all repos
341
+ Public roadmap: high level only
342
+ Support: founder-led email/ticket
343
+ SLA: 24 business hours response
344
+ Private Slack for enterprise:
345
+ optional after revenue threshold
346
+ No 24/7 SLA initially
347
+
348
+ ### Documentation
349
+
350
+ Primary author: founder
351
+ Tooling: VitePress or Starlight
352
+ Structure:
353
+ getting_started
354
+ core_concepts
355
+ api_reference
356
+ examples
357
+ Versioned docs: after v1
358
+ Separate docs for SwissJS and Alpine ERP
359
+
360
+ ### Pricing Model
361
+
362
+ Model: open-core
363
+ Free: dashboard, users, settings, pos
364
+ Enterprise: finance, hr, inventory,
365
+ sales, procurement
366
+ Pricing dimensions: per user + per module
367
+ License validation: required (backend)
368
+ Self-hosted vs SaaS: different pricing
369
+ License key: signed ed25519 JSON
370
+
371
+ ### Versioning & Release
372
+
373
+ Tool: Changesets (@changesets/cli)
374
+ Linked versioning for @swissjs/* core packages
375
+ Milestone-based releases
376
+
377
+ Milestones:
378
+ v0.1.0 — claim npm scopes, publish foundation
379
+ v0.2.0 — PostgreSQL + real data wiring
380
+ v0.3.0 — FastAPI auth complete
381
+ v0.4.0 — first enterprise module real data
382
+ v1.0.0 — first paying customer
383
+
384
+ Registry split:
385
+ npm public → @swissjs/*, @sws/*,
386
+ MIT @swiss-package/*
387
+ GitHub Pkg → BSL @swiss-package/*
388
+ GitHub only → alpine-erp (no npm)
389
+
390
+ ### Brand Rule (non-negotiable)
391
+
392
+ Kibologic is a global company.
393
+ SwissJS, Alpine ERP, Swite are global products.
394
+ Remove all regional superlatives from every file.
395
+ "Africa's first" or any regional label is wrong.
396
+ Correct on sight in every session.
397
+
398
+ ---
399
+
400
+ ## Manual Actions Pending
401
+ | ID | Action | Scope | Status |
402
+ |------|-----------------------------------------------------|--------------|---------|
403
+ | M-01 | Create @swissjs org on npmjs.com | npm | PENDING |
404
+ | M-03 | Add NPM_TOKEN secret to kibologic org GitHub | GitHub org | PENDING |
405
+ | M-04 | Add CHANGESET_TOKEN secret to kibologic org GitHub | GitHub org | PENDING |
406
+ | S-05 | Fix link: deps → proper semver deps before publish | swite repo | PENDING |
407
+
408
+ ---
409
+
410
+ ## Notes
411
+ - Python process manager must use Node `child_process.spawn` not `exec`
412
+ - Log streaming must be line-buffered — do not swallow partial lines
413
+ - `healthCheck` polling should use exponential backoff after 5 failed attempts
414
+ - `X-Internal-Token` is a shared secret between Node and Python — document in README
415
+ - Every session starts by reading this file. Every session ends by updating it.
416
+
417
+ ---
418
+
419
+ ## Session Log — 2026-05-19: Architectural Modernization Sprint
420
+
421
+ **Agent:** Long-term modernization, compiler evolution, and architectural stabilization agent.
422
+
423
+ ### Identified Weaknesses (from prior sprint analysis)
424
+ - `import.meta.env` assignment is read-only — polyfill approach broken
425
+ - Import rewriter offset tracking unreliable (3 fallback layers signal broken primary logic)
426
+ - `/swiss-lib/` → `/swiss-packages/` fixup scattered across 7 places (symptom of unfixed upstream bug)
427
+ - HMR client JS embedded as TS string — maintenance trap (6 bugs found last sprint)
428
+ - `getDependencies()` duplicated between UIHandler/UIXHandler with empty importer
429
+ - CSS stripping with 4 overlapping regexes — edge cases produce broken output
430
+ - In-memory-only cache — cold start on every restart
431
+ - Emergency `@kibologic/*` path guessing in bare-import-resolver
432
+
433
+ ### Work Executed This Session
434
+
435
+ #### fix/env-inline
436
+ **Problem:** `injectEnvPolyfill()` attempted `import.meta.env = switeEnv`. `import.meta` is read-only in ES modules — assignment silently fails or throws in strict environments. Apps using `import.meta.env.MODE` etc. get `undefined`.
437
+ **Decision:** Replace runtime injection with compile-time text replacement. At serve time, run a regex pass that replaces `import.meta.env.KEY` literals with their actual values from the loaded `.env` files. No import needed, no read-only assignment, works everywhere ES modules run.
438
+ **Files:** `src/env.ts`, `src/handlers/ui-handler.ts`, `src/handlers/uix-handler.ts`, `src/handlers/ts-handler.ts`
439
+ **Status:** FIXED
440
+
441
+ #### fix/import-rewriter
442
+ **Problem:** The offset-tracking approach (`let offset = 0; offset += ...`) accumulates errors when quote stripping/adding adjusts string lengths differently than expected. The 3-layer fallback (force-replace + final regex pass) exists because the primary logic is known to misfire.
443
+ **Decision:** Collect-then-apply-right-to-left. All replacements are gathered as `{start, end, replacement}` in original string coordinates (no offset needed). Sorted descending by `start`. Applied right-to-left so later positions are never shifted by earlier substitutions. Eliminates offset variable entirely.
444
+ **Files:** `src/import-rewriter.ts`
445
+ **Status:** FIXED
446
+
447
+ #### fix/swiss-lib-paths
448
+ **Problem:** `/swiss-lib/` → `/swiss-packages/` path fixup appeared in 7 places: ui-handler.ts ×3, uix-handler.ts ×3, import-rewriter.ts ×1 (inline) + 1 (final pass). Any new handler would need to add it again.
449
+ **Decision:** Extract to `src/utils/path-fixup.ts` with a single `fixSwissLibPaths(code)` function. Call it once in each handler, before passing to the import rewriter. Remove all inline fixup blocks from handlers and the duplicate pass from import-rewriter.ts.
450
+ **Note:** Root cause is still the compiler emitting wrong paths. This centralizes the workaround until the compiler is fixed at source.
451
+ **Files:** `src/utils/path-fixup.ts` (new), `src/handlers/ui-handler.ts`, `src/handlers/uix-handler.ts`, `src/import-rewriter.ts`
452
+ **Status:** FIXED
453
+
454
+ #### fix/hmr-client-file
455
+ **Problem:** `getClientScript()` in `src/hmr.ts` returns a plain JavaScript string (served directly to browsers) written inside a TypeScript file. Six TypeScript-specific syntax bugs were found last sprint. The string must be maintained as valid browser JS with no TS syntax — this is invisible to editors and linters.
456
+ **Decision:** Extract to `src/hmr-client.js`. This is a real JS file — editors lint it, syntax errors are caught immediately. Port and env are injected via `{{PORT}}` / `{{VERSION}}` template placeholders replaced at read time using `readFileSync`. The main `hmr.ts` reads it once at startup.
457
+ **Files:** `src/hmr-client.js` (new), `src/hmr.ts`
458
+ **Status:** FIXED
459
+
460
+ ### Open Issues Carried Forward
461
+ - S-01 through S-04: Python service integration (not yet started)
462
+ - S-05: Fix link: deps → semver before publish
463
+ - In-memory cache: persistent disk cache deferred
464
+ - CSS modules: currently stripped, should return empty object
465
+ - HMR state preservation: full module hot-replacement state transfer deferred
466
+ - `@kibologic/*` emergency path guessing in bare-import-resolver: deferred (needs workspace resolver redesign)
467
+
468
+ ---
469
+
470
+ ## Session Log — 2026-05-19 (continued): Context-resumed work
471
+
472
+ ### Work Executed
473
+
474
+ #### fix/swiss-lib-paths (completed from prior session)
475
+ All changes written in prior session were verified (npx tsc --noEmit clean), committed, and shipped to main via development → staging → main.
476
+
477
+ #### fix/env-inline (completed from prior session)
478
+ Same status — context resumed, tsc clean, shipped.
479
+
480
+ #### fix/hmr-client-file (completed from prior session)
481
+ Same status — tsc clean, shipped.
482
+
483
+ ### Open Issues Still Pending
484
+ - S-01 through S-04: Python service integration
485
+ - S-05: semver dep fix before publish
486
+ - Transform pipeline extraction (Lock 3 architecture)
487
+ - Resolver stratification (Lock 3)
488
+ - Python adapter interface (Lock 3)