@africode/core 5.0.8 → 5.0.9

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 (62) hide show
  1. package/AGENT_INSTRUCTIONS.md +595 -595
  2. package/COMPONENT_SCHEMA.json +1800 -991
  3. package/bin/create-africode.js +87 -25
  4. package/components/auth-form.js +154 -0
  5. package/components/index.js +10 -0
  6. package/components/kyc-upload.js +173 -0
  7. package/components/nav-drawer.js +217 -0
  8. package/components/transaction-ledger.js +138 -0
  9. package/components/wallet-balance.js +114 -0
  10. package/core/a2ui-schema-manager.js +1 -1
  11. package/core/a2ui.js +178 -1
  12. package/core/bun-runtime.js +122 -7
  13. package/core/cli/commands/build.js +30 -5
  14. package/core/cli/ui.js +13 -3
  15. package/core/compliance.js +201 -0
  16. package/core/middleware.js +80 -17
  17. package/core/patterns.js +168 -0
  18. package/core/request-analytics.js +254 -0
  19. package/core/request-identity.js +79 -29
  20. package/core/sdk.js +4 -1
  21. package/core/validation.js +13 -0
  22. package/dist/africode.js +858 -457
  23. package/dist/africode.js.map +14 -9
  24. package/dist/build-info.json +3 -3
  25. package/dist/components.js +784 -383
  26. package/dist/components.js.map +11 -6
  27. package/package.json +1 -1
  28. package/templates/starter/package.json +5 -5
  29. package/templates/starter/src/index.js +18 -0
  30. package/templates/starter/src/pages/index.js +1 -1
  31. package/templates/starter-3d/package.json +5 -5
  32. package/templates/starter-3d/src/pages/index.js +1 -1
  33. package/templates/starter-dashboard/.env.example +21 -0
  34. package/templates/starter-dashboard/africode.config.js +20 -0
  35. package/templates/starter-dashboard/package.json +14 -0
  36. package/templates/starter-dashboard/src/index.js +17 -0
  37. package/templates/starter-dashboard/src/pages/api/analytics.js +24 -0
  38. package/templates/starter-dashboard/src/pages/index.html +118 -0
  39. package/templates/starter-dashboard/src/pages/index.js +110 -0
  40. package/templates/starter-dashboard/src/styles/main.css +172 -0
  41. package/templates/starter-fintech/.env.example +28 -0
  42. package/templates/starter-fintech/africode.config.js +20 -0
  43. package/templates/starter-fintech/package.json +15 -0
  44. package/templates/starter-fintech/src/index.js +17 -0
  45. package/templates/starter-fintech/src/pages/api/auth.js +45 -0
  46. package/templates/starter-fintech/src/pages/api/transfer.js +65 -0
  47. package/templates/starter-fintech/src/pages/api/wallet.js +39 -0
  48. package/templates/starter-fintech/src/pages/api/webhooks/payment.js +32 -0
  49. package/templates/starter-fintech/src/pages/index.html +169 -0
  50. package/templates/starter-fintech/src/pages/index.js +161 -0
  51. package/templates/starter-fintech/src/styles/main.css +246 -0
  52. package/templates/starter-react/package.json +5 -5
  53. package/templates/starter-react/src/pages/index.js +1 -1
  54. package/templates/starter-tailwind/package.json +5 -5
  55. package/templates/starter-tailwind/src/pages/index.js +1 -1
  56. package/templates/starter-website/.env.example +18 -0
  57. package/templates/starter-website/africode.config.js +20 -0
  58. package/templates/starter-website/package.json +14 -0
  59. package/templates/starter-website/src/index.js +17 -0
  60. package/templates/starter-website/src/pages/index.html +124 -0
  61. package/templates/starter-website/src/pages/index.js +116 -0
  62. package/templates/starter-website/src/styles/main.css +195 -0
@@ -0,0 +1,246 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --bg: #f6f7fb;
4
+ --surface: #ffffff;
5
+ --surface-muted: #eef2f7;
6
+ --text: #172033;
7
+ --muted: #647084;
8
+ --border: #d8dee8;
9
+ --primary: #0f766e;
10
+ --primary-strong: #0b5f59;
11
+ --accent: #b7791f;
12
+ --danger: #b42318;
13
+ --success: #087443;
14
+ --shadow: 0 16px 40px rgba(23, 32, 51, 0.08);
15
+ }
16
+
17
+ [data-theme="dark"] {
18
+ color-scheme: dark;
19
+ --bg: #07111f;
20
+ --surface: #101b2d;
21
+ --surface-muted: #17243a;
22
+ --text: #f8fafc;
23
+ --muted: #a7b4c8;
24
+ --border: #26364f;
25
+ --primary: #2dd4bf;
26
+ --primary-strong: #5eead4;
27
+ --accent: #f5b84b;
28
+ --danger: #fb7185;
29
+ --success: #34d399;
30
+ --shadow: 0 18px 44px rgba(0, 0, 0, 0.24);
31
+ }
32
+
33
+ * {
34
+ box-sizing: border-box;
35
+ }
36
+
37
+ body {
38
+ min-height: 100vh;
39
+ margin: 0;
40
+ background: var(--bg);
41
+ color: var(--text);
42
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
43
+ }
44
+
45
+ button,
46
+ input,
47
+ select {
48
+ font: inherit;
49
+ }
50
+
51
+ .app-shell {
52
+ width: min(1180px, calc(100% - 32px));
53
+ margin: 0 auto;
54
+ padding: 32px 0;
55
+ }
56
+
57
+ .topbar,
58
+ .panel,
59
+ .metric,
60
+ .ledger,
61
+ .form-panel {
62
+ background: var(--surface);
63
+ border: 1px solid var(--border);
64
+ box-shadow: var(--shadow);
65
+ }
66
+
67
+ .topbar {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: space-between;
71
+ gap: 16px;
72
+ padding: 18px 20px;
73
+ border-radius: 8px;
74
+ }
75
+
76
+ .brand {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 4px;
80
+ }
81
+
82
+ .eyebrow,
83
+ .label,
84
+ .status {
85
+ color: var(--muted);
86
+ font-size: 0.82rem;
87
+ }
88
+
89
+ h1,
90
+ h2,
91
+ h3,
92
+ p {
93
+ margin: 0;
94
+ }
95
+
96
+ h1 {
97
+ font-size: clamp(1.45rem, 3vw, 2.25rem);
98
+ line-height: 1.1;
99
+ }
100
+
101
+ h2 {
102
+ font-size: 1rem;
103
+ }
104
+
105
+ .actions,
106
+ .grid,
107
+ .metrics,
108
+ .form-grid {
109
+ display: grid;
110
+ gap: 16px;
111
+ }
112
+
113
+ .actions {
114
+ grid-auto-flow: column;
115
+ align-items: center;
116
+ }
117
+
118
+ .button {
119
+ min-height: 40px;
120
+ border: 1px solid var(--border);
121
+ border-radius: 6px;
122
+ padding: 0 14px;
123
+ background: var(--surface-muted);
124
+ color: var(--text);
125
+ cursor: pointer;
126
+ }
127
+
128
+ .button.primary {
129
+ border-color: var(--primary);
130
+ background: var(--primary);
131
+ color: #ffffff;
132
+ }
133
+
134
+ [data-theme="dark"] .button.primary {
135
+ color: #07111f;
136
+ }
137
+
138
+ .grid {
139
+ grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr);
140
+ margin-top: 18px;
141
+ }
142
+
143
+ .metrics {
144
+ grid-template-columns: repeat(3, minmax(0, 1fr));
145
+ }
146
+
147
+ .metric,
148
+ .panel,
149
+ .ledger,
150
+ .form-panel {
151
+ border-radius: 8px;
152
+ padding: 18px;
153
+ }
154
+
155
+ .value {
156
+ margin-top: 10px;
157
+ font-size: 1.65rem;
158
+ font-weight: 760;
159
+ }
160
+
161
+ .status.good {
162
+ color: var(--success);
163
+ }
164
+
165
+ .status.warn {
166
+ color: var(--accent);
167
+ }
168
+
169
+ .ledger {
170
+ margin-top: 16px;
171
+ }
172
+
173
+ .ledger-list {
174
+ display: grid;
175
+ gap: 10px;
176
+ margin-top: 14px;
177
+ }
178
+
179
+ .ledger-row {
180
+ display: grid;
181
+ grid-template-columns: 1fr auto;
182
+ gap: 12px;
183
+ padding: 12px;
184
+ border-radius: 6px;
185
+ background: var(--surface-muted);
186
+ }
187
+
188
+ .amount {
189
+ font-weight: 720;
190
+ }
191
+
192
+ .form-panel {
193
+ display: grid;
194
+ gap: 18px;
195
+ }
196
+
197
+ .form-grid {
198
+ grid-template-columns: 1fr;
199
+ }
200
+
201
+ label {
202
+ display: grid;
203
+ gap: 6px;
204
+ color: var(--muted);
205
+ font-size: 0.86rem;
206
+ }
207
+
208
+ input {
209
+ min-height: 42px;
210
+ width: 100%;
211
+ border: 1px solid var(--border);
212
+ border-radius: 6px;
213
+ padding: 0 12px;
214
+ background: var(--surface-muted);
215
+ color: var(--text);
216
+ }
217
+
218
+ .notice {
219
+ min-height: 46px;
220
+ border-radius: 6px;
221
+ padding: 12px;
222
+ background: var(--surface-muted);
223
+ color: var(--muted);
224
+ }
225
+
226
+ .notice.error {
227
+ color: var(--danger);
228
+ }
229
+
230
+ .notice.success {
231
+ color: var(--success);
232
+ }
233
+
234
+ @media (max-width: 820px) {
235
+ .topbar,
236
+ .grid,
237
+ .metrics {
238
+ grid-template-columns: 1fr;
239
+ }
240
+
241
+ .topbar,
242
+ .actions {
243
+ display: grid;
244
+ grid-auto-flow: row;
245
+ }
246
+ }
@@ -4,13 +4,13 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "africode dev",
8
- "build": "africode build",
9
- "migrate": "africode migrate"
7
+ "dev": "bun run ./bin/africode.js dev",
8
+ "build": "bun run ./bin/africode.js build",
9
+ "migrate": "bun run ./bin/africode.js migrate"
10
10
  },
11
11
  "dependencies": {
12
- "@africode/core": "^5.0.2",
12
+ "@africode/core": "^5.0.9",
13
13
  "react": "^19.0.0",
14
14
  "react-dom": "^19.0.0"
15
15
  }
16
- }
16
+ }
@@ -1,4 +1,4 @@
1
- import { html, Layout } from 'africode';
1
+ import { html, Layout } from '@africode/core';
2
2
 
3
3
  /**
4
4
  * Home Page — React Interop Starter
@@ -4,17 +4,17 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "concurrently \"africode dev\" \"npx @tailwindcss/cli -i ./src/styles/tailwind.css -o ./src/styles/tailwind.out.css --watch\"",
7
+ "dev": "concurrently \"bun run ./bin/africode.js dev\" \"npx @tailwindcss/cli -i ./src/styles/tailwind.css -o ./src/styles/tailwind.out.css --watch\"",
8
8
  "build:css": "npx @tailwindcss/cli -i ./src/styles/tailwind.css -o ./src/styles/tailwind.out.css --minify",
9
- "build": "npm run build:css && africode build",
10
- "migrate": "africode migrate"
9
+ "build": "npm run build:css && bun run ./bin/africode.js build",
10
+ "migrate": "bun run ./bin/africode.js migrate"
11
11
  },
12
12
  "dependencies": {
13
- "@africode/core": "^5.0.2"
13
+ "@africode/core": "^5.0.9"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@tailwindcss/cli": "^4.0.0",
17
17
  "tailwindcss": "^4.0.0",
18
18
  "concurrently": "^9.0.0"
19
19
  }
20
- }
20
+ }
@@ -1,5 +1,5 @@
1
1
  import '../tailwind-loader.js';
2
- import { html, Layout } from 'africode';
2
+ import { html, Layout } from '@africode/core';
3
3
 
4
4
  /**
5
5
  * Home Page — Tailwind Starter
@@ -0,0 +1,18 @@
1
+ # AfriCode Website Starter Environment
2
+
3
+ # Server
4
+ PORT=3000
5
+ NODE_ENV=development
6
+ PUBLIC_SITE_URL=http://localhost:3000
7
+
8
+ # Content and forms
9
+ PUBLIC_SITE_NAME=AfriCode Website
10
+ CONTACT_TO_EMAIL=hello@example.com
11
+ NEWSLETTER_PROVIDER=mock
12
+ NEWSLETTER_API_KEY=newsletter_mock_key
13
+
14
+ # Optional local data
15
+ DB_FILE=./data.db
16
+
17
+ # Security
18
+ SESSION_SECRET=replace_this_with_a_long_random_string
@@ -0,0 +1,20 @@
1
+ /**
2
+ * AfriCode Website Starter Configuration
3
+ */
4
+ export default {
5
+ entry: 'src/index.js',
6
+ server: {
7
+ port: process.env.PORT || 3000,
8
+ host: '0.0.0.0',
9
+ staticDir: 'public',
10
+ cors: true
11
+ },
12
+ directories: {
13
+ src: 'src',
14
+ pages: 'src/pages',
15
+ components: 'src/components',
16
+ styles: 'src/styles',
17
+ build: 'dist'
18
+ },
19
+ theme: { default: 'light', toggleAttribute: 'data-theme' }
20
+ };
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "africode-website-starter",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "bun run ./bin/africode.js dev",
8
+ "build": "bun run ./bin/africode.js build",
9
+ "migrate": "bun run ./bin/africode.js migrate"
10
+ },
11
+ "dependencies": {
12
+ "@africode/core": "^5.0.9"
13
+ }
14
+ }
@@ -0,0 +1,17 @@
1
+ import { html, Layout } from '@africode/core';
2
+
3
+ export function loader() {
4
+ return { title: 'AfriCode Website Starter' };
5
+ }
6
+
7
+ export default function App({ data }) {
8
+ return Layout({
9
+ title: data?.title || 'AfriCode Website Starter',
10
+ children: html`
11
+ <main>
12
+ <h1>Website starter ready</h1>
13
+ <p>Use this template for marketing sites, content pages, and product launches.</p>
14
+ </main>
15
+ `
16
+ });
17
+ }
@@ -0,0 +1,124 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AfriCode Website Starter</title>
7
+ <script type="importmap">
8
+ {
9
+ "imports": {
10
+ "africode": "/node_modules/@africode/core/core/sdk-browser.js",
11
+ "africode/components": "/node_modules/@africode/core/components/index.js"
12
+ }
13
+ }
14
+ </script>
15
+ <link rel="stylesheet" href="/node_modules/@africode/core/styles/africanity.css" />
16
+ <link rel="stylesheet" href="/styles/main.css" />
17
+ <script type="module" src="/node_modules/@africode/core/core/sdk-browser.js"></script>
18
+ </head>
19
+ <body>
20
+ <main class="site-shell">
21
+ <nav class="nav" aria-label="Primary">
22
+ <a class="brand" href="/">AfriCode Site</a>
23
+ <div class="nav-links">
24
+ <a href="#features">Features</a>
25
+ <a href="#proof">Proof</a>
26
+ <a href="#contact">Contact</a>
27
+ <button class="button" id="theme-toggle" type="button">Toggle theme</button>
28
+ </div>
29
+ </nav>
30
+
31
+ <section class="hero">
32
+ <div>
33
+ <span class="eyebrow">Website starter</span>
34
+ <h1>Launch a fast, structured site with AfriCode.</h1>
35
+ <p class="hero-copy">A production-minded starter for product pages, service sites, and content launches with clean sections, theme tokens, and a contact-ready call to action.</p>
36
+ <div class="hero-actions">
37
+ <a class="button primary" href="#contact">Start a project</a>
38
+ <a class="button" href="#features">Explore sections</a>
39
+ </div>
40
+ </div>
41
+
42
+ <aside class="hero-panel" aria-label="Site readiness">
43
+ <div class="signal">
44
+ <span class="muted">Pages</span>
45
+ <strong>4 sections</strong>
46
+ </div>
47
+ <div class="signal">
48
+ <span class="muted">Theme</span>
49
+ <strong>Light and dark</strong>
50
+ </div>
51
+ <div class="signal">
52
+ <span class="muted">Forms</span>
53
+ <strong>Contact-ready</strong>
54
+ </div>
55
+ </aside>
56
+ </section>
57
+
58
+ <section class="section" id="features">
59
+ <div class="section-head">
60
+ <div>
61
+ <span class="eyebrow">Structure</span>
62
+ <h2>Everything a small site needs first</h2>
63
+ </div>
64
+ <p class="muted">Swap copy, connect forms, and keep moving.</p>
65
+ </div>
66
+ <div class="grid">
67
+ <article class="card">
68
+ <h3>Clear sections</h3>
69
+ <p>Hero, feature grid, proof area, and CTA are ready without extra layout work.</p>
70
+ </article>
71
+ <article class="card">
72
+ <h3>Theme tokens</h3>
73
+ <p>CSS variables make brand changes predictable across light and dark modes.</p>
74
+ </article>
75
+ <article class="card">
76
+ <h3>Component-ready</h3>
77
+ <p>Import AfriCode components when the project grows beyond static sections.</p>
78
+ </article>
79
+ </div>
80
+ </section>
81
+
82
+ <section class="section" id="proof">
83
+ <div class="grid">
84
+ <article class="proof">
85
+ <h3>98</h3>
86
+ <p>Performance-minded structure with minimal client JavaScript.</p>
87
+ </article>
88
+ <article class="proof">
89
+ <h3>0</h3>
90
+ <p>Framework lock-in for the content layer.</p>
91
+ </article>
92
+ <article class="proof">
93
+ <h3>1</h3>
94
+ <p>Shared theme system for every starter page.</p>
95
+ </article>
96
+ </div>
97
+ </section>
98
+
99
+ <section class="cta" id="contact">
100
+ <div>
101
+ <span class="eyebrow">Contact</span>
102
+ <h2>Connect this CTA to your own endpoint.</h2>
103
+ <p class="muted">The `.env.example` file includes contact and newsletter placeholders.</p>
104
+ </div>
105
+ <form class="signup">
106
+ <input type="email" placeholder="you@example.com" aria-label="Email address" />
107
+ <button class="button primary" type="submit">Notify me</button>
108
+ </form>
109
+ </section>
110
+ </main>
111
+
112
+ <script type="module">
113
+ document.querySelector('#theme-toggle').addEventListener('click', () => {
114
+ const root = document.documentElement;
115
+ root.dataset.theme = root.dataset.theme === 'dark' ? 'light' : 'dark';
116
+ });
117
+
118
+ document.querySelector('.signup').addEventListener('submit', (event) => {
119
+ event.preventDefault();
120
+ event.currentTarget.querySelector('button').textContent = 'Received';
121
+ });
122
+ </script>
123
+ </body>
124
+ </html>
@@ -0,0 +1,116 @@
1
+ import { html, Layout } from '@africode/core';
2
+
3
+ export function loader() {
4
+ return { title: 'AfriCode Website Starter' };
5
+ }
6
+
7
+ export default function HomePage({ data }) {
8
+ return Layout({
9
+ title: data?.title || 'AfriCode Website Starter',
10
+ children: html`
11
+ <main class="site-shell">
12
+ <nav class="nav" aria-label="Primary">
13
+ <a class="brand" href="/">AfriCode Site</a>
14
+ <div class="nav-links">
15
+ <a href="#features">Features</a>
16
+ <a href="#proof">Proof</a>
17
+ <a href="#contact">Contact</a>
18
+ <button class="button" id="theme-toggle" type="button">Toggle theme</button>
19
+ </div>
20
+ </nav>
21
+
22
+ <section class="hero">
23
+ <div>
24
+ <span class="eyebrow">Website starter</span>
25
+ <h1>Launch a fast, structured site with AfriCode.</h1>
26
+ <p class="hero-copy">A production-minded starter for product pages, service sites, and content launches with clean sections, theme tokens, and a contact-ready call to action.</p>
27
+ <div class="hero-actions">
28
+ <a class="button primary" href="#contact">Start a project</a>
29
+ <a class="button" href="#features">Explore sections</a>
30
+ </div>
31
+ </div>
32
+
33
+ <aside class="hero-panel" aria-label="Site readiness">
34
+ <div class="signal">
35
+ <span class="muted">Pages</span>
36
+ <strong>4 sections</strong>
37
+ </div>
38
+ <div class="signal">
39
+ <span class="muted">Theme</span>
40
+ <strong>Light and dark</strong>
41
+ </div>
42
+ <div class="signal">
43
+ <span class="muted">Forms</span>
44
+ <strong>Contact-ready</strong>
45
+ </div>
46
+ </aside>
47
+ </section>
48
+
49
+ <section class="section" id="features">
50
+ <div class="section-head">
51
+ <div>
52
+ <span class="eyebrow">Structure</span>
53
+ <h2>Everything a small site needs first</h2>
54
+ </div>
55
+ <p class="muted">Swap copy, connect forms, and keep moving.</p>
56
+ </div>
57
+ <div class="grid">
58
+ <article class="card">
59
+ <h3>Clear sections</h3>
60
+ <p>Hero, feature grid, proof area, and CTA are ready without extra layout work.</p>
61
+ </article>
62
+ <article class="card">
63
+ <h3>Theme tokens</h3>
64
+ <p>CSS variables make brand changes predictable across light and dark modes.</p>
65
+ </article>
66
+ <article class="card">
67
+ <h3>Component-ready</h3>
68
+ <p>Import AfriCode components when the project grows beyond static sections.</p>
69
+ </article>
70
+ </div>
71
+ </section>
72
+
73
+ <section class="section" id="proof">
74
+ <div class="grid">
75
+ <article class="proof">
76
+ <h3>98</h3>
77
+ <p>Performance-minded structure with minimal client JavaScript.</p>
78
+ </article>
79
+ <article class="proof">
80
+ <h3>0</h3>
81
+ <p>Framework lock-in for the content layer.</p>
82
+ </article>
83
+ <article class="proof">
84
+ <h3>1</h3>
85
+ <p>Shared theme system for every starter page.</p>
86
+ </article>
87
+ </div>
88
+ </section>
89
+
90
+ <section class="cta" id="contact">
91
+ <div>
92
+ <span class="eyebrow">Contact</span>
93
+ <h2>Connect this CTA to your own endpoint.</h2>
94
+ <p class="muted">The `.env.example` file includes contact and newsletter placeholders.</p>
95
+ </div>
96
+ <form class="signup">
97
+ <input type="email" placeholder="you@example.com" aria-label="Email address" />
98
+ <button class="button primary" type="submit">Notify me</button>
99
+ </form>
100
+ </section>
101
+ </main>
102
+
103
+ <script type="module">
104
+ document.querySelector('#theme-toggle').addEventListener('click', () => {
105
+ const root = document.documentElement;
106
+ root.dataset.theme = root.dataset.theme === 'dark' ? 'light' : 'dark';
107
+ });
108
+
109
+ document.querySelector('.signup').addEventListener('submit', (event) => {
110
+ event.preventDefault();
111
+ event.currentTarget.querySelector('button').textContent = 'Received';
112
+ });
113
+ </script>
114
+ `
115
+ });
116
+ }