@africode/core 5.0.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.
- package/AFRICODE_FRAMEWORK_GUIDE.md +707 -0
- package/LICENSE +623 -0
- package/README.md +442 -0
- package/bin/africode.js +73 -0
- package/bin/africode.js.1758507140 +343 -0
- package/bin/cli.ts +83 -0
- package/bin/create-africode.js +158 -0
- package/bin/scaffold.ts +219 -0
- package/components/accordion.js +183 -0
- package/components/alert.js +131 -0
- package/components/auth.js +172 -0
- package/components/avatar.js +117 -0
- package/components/badge.js +104 -0
- package/components/base.d.ts +139 -0
- package/components/base.js +184 -0
- package/components/button.js +164 -0
- package/components/card.js +137 -0
- package/components/cultural-card.js +243 -0
- package/components/divider.js +83 -0
- package/components/dropdown.js +171 -0
- package/components/error-boundary.js +155 -0
- package/components/form.js +131 -0
- package/components/grid.js +273 -0
- package/components/hero.js +138 -0
- package/components/icon.js +36 -0
- package/components/index.js +57 -0
- package/components/input.js +256 -0
- package/components/kanga-card.js +185 -0
- package/components/language-switcher.js +108 -0
- package/components/loader.js +80 -0
- package/components/modal.js +262 -0
- package/components/motion.js +84 -0
- package/components/navbar.js +236 -0
- package/components/pattern-showcase.js +225 -0
- package/components/progress.js +134 -0
- package/components/react.js +111 -0
- package/components/section.js +54 -0
- package/components/select.js +322 -0
- package/components/sidebar.js +180 -0
- package/components/skeleton.js +85 -0
- package/components/table.js +181 -0
- package/components/tabs.js +202 -0
- package/components/theme-toggle.js +82 -0
- package/components/toast.js +139 -0
- package/components/tooltip.js +167 -0
- package/core/a2ui-schema-manager.js +344 -0
- package/core/a2ui.js +431 -0
- package/core/bun-runtime.js +799 -0
- package/core/cli/commands/add.js +23 -0
- package/core/cli/commands/audit.js +58 -0
- package/core/cli/commands/build.js +137 -0
- package/core/cli/commands/create-plugin.js +241 -0
- package/core/cli/commands/dev.js +228 -0
- package/core/cli/commands/lint.js +23 -0
- package/core/cli/commands/test.js +34 -0
- package/core/cli/migrator.js +71 -0
- package/core/cli/ui.js +46 -0
- package/core/compliance.js +628 -0
- package/core/config.js +263 -0
- package/core/db-advanced.js +481 -0
- package/core/db.js +284 -0
- package/core/enhanced-hmr.js +404 -0
- package/core/errors.js +222 -0
- package/core/file-router.js +290 -0
- package/core/heartbeat.js +64 -0
- package/core/hmr-client.js +204 -0
- package/core/hmr.js +196 -0
- package/core/html.d.ts +116 -0
- package/core/html.js +160 -0
- package/core/hydration.js +52 -0
- package/core/lipa-namba-journey.js +572 -0
- package/core/motion.js +106 -0
- package/core/nida-cig-middleware.js +455 -0
- package/core/patterns.d.ts +124 -0
- package/core/patterns.js +833 -0
- package/core/plugins/index.js +312 -0
- package/core/router.js +387 -0
- package/core/sdk-client.js +62 -0
- package/core/sdk.d.ts +133 -0
- package/core/sdk.js +123 -0
- package/core/seo.js +76 -0
- package/core/server/auth-endpoints.js +339 -0
- package/core/server/auth.js +180 -0
- package/core/server/csrf.js +206 -0
- package/core/server/db.js +39 -0
- package/core/server/middleware.js +324 -0
- package/core/server/rate-limit.js +238 -0
- package/core/server/render.js +69 -0
- package/core/server/router.js +120 -0
- package/core/shim.js +28 -0
- package/core/state.d.ts +86 -0
- package/core/state.js +242 -0
- package/core/store.d.ts +122 -0
- package/core/store.js +61 -0
- package/core/validation.d.ts +233 -0
- package/core/validation.js +590 -0
- package/core/websocket.js +639 -0
- package/dist/africode.js +2905 -0
- package/dist/africode.js.map +61 -0
- package/dist/build-info.json +23 -0
- package/dist/components.js +2888 -0
- package/dist/components.js.map +58 -0
- package/dist/styles/africanity.css +322 -0
- package/dist/styles/typography.css +141 -0
- package/docs/IDE-Guide.md +50 -0
- package/package.json +110 -0
- package/src/index.ts +196 -0
- package/styles/africanity.css +322 -0
- package/styles/typography.css +141 -0
- package/templates/starter/.env.example +15 -0
- package/templates/starter/africode.config.js +40 -0
- package/templates/starter/package.json +14 -0
- package/templates/starter/src/pages/index.html +46 -0
- package/templates/starter/src/pages/index.js +32 -0
- package/templates/starter/src/styles/main.css +4 -0
- package/templates/starter-3d/.env.example +7 -0
- package/templates/starter-3d/africode.config.js +29 -0
- package/templates/starter-3d/components/af-model-viewer.js +125 -0
- package/templates/starter-3d/package.json +15 -0
- package/templates/starter-3d/src/pages/index.html +46 -0
- package/templates/starter-3d/src/pages/index.js +50 -0
- package/templates/starter-3d/src/styles/main.css +4 -0
- package/templates/starter-react/.env.example +15 -0
- package/templates/starter-react/africode.config.js +40 -0
- package/templates/starter-react/package.json +16 -0
- package/templates/starter-react/src/pages/index.html +46 -0
- package/templates/starter-react/src/pages/index.js +68 -0
- package/templates/starter-react/src/styles/main.css +4 -0
- package/templates/starter-tailwind/.env.example +15 -0
- package/templates/starter-tailwind/africode.config.js +40 -0
- package/templates/starter-tailwind/package.json +20 -0
- package/templates/starter-tailwind/src/pages/index.html +46 -0
- package/templates/starter-tailwind/src/pages/index.js +37 -0
- package/templates/starter-tailwind/src/styles/main.css +4 -0
- package/templates/starter-tailwind/src/styles/tailwind.css +1 -0
- package/templates/starter-tailwind/src/tailwind-loader.js +30 -0
package/core/config.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AfriCode Framework Configuration
|
|
3
|
+
*
|
|
4
|
+
* Centralized configuration for the entire framework.
|
|
5
|
+
* Provides createFramework() as the entry point for apps.
|
|
6
|
+
*
|
|
7
|
+
* Design:
|
|
8
|
+
* - Single config object controls all framework behavior
|
|
9
|
+
* - Defaults are strict and secure
|
|
10
|
+
* - Every opt-in behavior is explicit
|
|
11
|
+
* - Observability hooks are first-class
|
|
12
|
+
*
|
|
13
|
+
* @module core/config
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} AfriCodeConfig
|
|
18
|
+
*
|
|
19
|
+
* @property {Object} [validation] - Validation configuration
|
|
20
|
+
* @property {boolean} [validation.trimStrings=false] - Trim whitespace from string inputs
|
|
21
|
+
* @property {boolean} [validation.emptyAsNullDefault=false] - Convert "" → null for nullable fields (NOT recommended)
|
|
22
|
+
*
|
|
23
|
+
* @property {Object} [security] - Security configuration
|
|
24
|
+
* @property {Object} [security.csrf] - CSRF configuration
|
|
25
|
+
* @property {boolean} [security.csrf.enabled=true] - Enable CSRF protection
|
|
26
|
+
* @property {string[]} [security.csrf.excludePaths=[]] - Paths to exclude from CSRF
|
|
27
|
+
* @property {string} [security.csrf.sameSite='Strict'] - SameSite cookie policy
|
|
28
|
+
* @property {boolean} [security.csrf.secure=false] - Require HTTPS for cookies
|
|
29
|
+
* @property {Object} [security.rateLimit] - Rate limit configuration
|
|
30
|
+
* @property {boolean} [security.rateLimit.enabled=true] - Enable rate limiting
|
|
31
|
+
* @property {number} [security.rateLimit.windowMs=60000] - Window in milliseconds
|
|
32
|
+
* @property {number} [security.rateLimit.maxRequests=60] - Max requests per window
|
|
33
|
+
* @property {string[]} [security.rateLimit.excludePaths=[]] - Paths to exclude
|
|
34
|
+
*
|
|
35
|
+
* @property {Object} [hooks] - Observability hooks
|
|
36
|
+
* @property {Function} [hooks.onValidationError] - Called on validation failure
|
|
37
|
+
* @property {Function} [hooks.onSecurityViolation] - Called on CSRF/security failure
|
|
38
|
+
* @property {Function} [hooks.onRateLimit] - Called when rate limit is hit
|
|
39
|
+
* @property {Function} [hooks.onDatabaseError] - Called on database error
|
|
40
|
+
* @property {Function} [hooks.onRequest] - Called on every incoming request
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Default configuration values.
|
|
45
|
+
* Strict by default. Secure by default.
|
|
46
|
+
*/
|
|
47
|
+
const DEFAULT_CONFIG = {
|
|
48
|
+
validation: {
|
|
49
|
+
trimStrings: false,
|
|
50
|
+
emptyAsNullDefault: false
|
|
51
|
+
},
|
|
52
|
+
security: {
|
|
53
|
+
csrf: {
|
|
54
|
+
enabled: true,
|
|
55
|
+
excludePaths: [],
|
|
56
|
+
sameSite: 'Strict',
|
|
57
|
+
secure: false
|
|
58
|
+
},
|
|
59
|
+
rateLimit: {
|
|
60
|
+
enabled: true,
|
|
61
|
+
windowMs: 60 * 1000,
|
|
62
|
+
maxRequests: 60,
|
|
63
|
+
excludePaths: []
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
hooks: {
|
|
67
|
+
onValidationError: null,
|
|
68
|
+
onSecurityViolation: null,
|
|
69
|
+
onRateLimit: null,
|
|
70
|
+
onDatabaseError: null,
|
|
71
|
+
onRequest: null
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** @type {AfriCodeConfig} */
|
|
76
|
+
let _config = deepClone(DEFAULT_CONFIG);
|
|
77
|
+
|
|
78
|
+
/** @type {boolean} */
|
|
79
|
+
let _initialized = false;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Deep clone a plain object.
|
|
83
|
+
* @param {Object} obj
|
|
84
|
+
* @returns {Object}
|
|
85
|
+
*/
|
|
86
|
+
function deepClone(obj) {
|
|
87
|
+
if (obj === null || typeof obj !== 'object') {return obj;}
|
|
88
|
+
if (Array.isArray(obj)) {return obj.map(deepClone);}
|
|
89
|
+
const cloned = {};
|
|
90
|
+
for (const key of Object.keys(obj)) {
|
|
91
|
+
cloned[key] = deepClone(obj[key]);
|
|
92
|
+
}
|
|
93
|
+
return cloned;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Deep merge source into target.
|
|
98
|
+
* @param {Object} target
|
|
99
|
+
* @param {Object} source
|
|
100
|
+
* @returns {Object}
|
|
101
|
+
*/
|
|
102
|
+
function deepMerge(target, source) {
|
|
103
|
+
const result = { ...target };
|
|
104
|
+
for (const key of Object.keys(source)) {
|
|
105
|
+
if (
|
|
106
|
+
source[key] !== null &&
|
|
107
|
+
typeof source[key] === 'object' &&
|
|
108
|
+
!Array.isArray(source[key]) &&
|
|
109
|
+
typeof target[key] === 'object' &&
|
|
110
|
+
!Array.isArray(target[key])
|
|
111
|
+
) {
|
|
112
|
+
result[key] = deepMerge(target[key] || {}, source[key]);
|
|
113
|
+
} else {
|
|
114
|
+
result[key] = source[key];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initialize the AfriCode framework with configuration.
|
|
122
|
+
*
|
|
123
|
+
* This is the single entry point for framework configuration.
|
|
124
|
+
* Call once at app startup. All systems read from this config.
|
|
125
|
+
*
|
|
126
|
+
* @param {Partial<AfriCodeConfig>} [userConfig={}] - User overrides
|
|
127
|
+
* @returns {AfriCodeConfig} The resolved configuration
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* import { createFramework } from 'africode/core/config';
|
|
131
|
+
*
|
|
132
|
+
* createFramework({
|
|
133
|
+
* validation: {
|
|
134
|
+
* trimStrings: true
|
|
135
|
+
* },
|
|
136
|
+
* security: {
|
|
137
|
+
* csrf: { enabled: true, secure: true },
|
|
138
|
+
* rateLimit: { maxRequests: 100 }
|
|
139
|
+
* },
|
|
140
|
+
* hooks: {
|
|
141
|
+
* onValidationError: (error) => logger.warn('Validation:', error),
|
|
142
|
+
* onSecurityViolation: (error) => logger.error('Security:', error),
|
|
143
|
+
* onRateLimit: (key) => metrics.increment('rate_limit_hit')
|
|
144
|
+
* }
|
|
145
|
+
* });
|
|
146
|
+
*/
|
|
147
|
+
export function createFramework(userConfig = {}) {
|
|
148
|
+
_config = deepMerge(DEFAULT_CONFIG, userConfig);
|
|
149
|
+
_initialized = true;
|
|
150
|
+
return getConfig();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Get the current framework configuration.
|
|
155
|
+
* Returns a frozen copy to prevent accidental mutation.
|
|
156
|
+
*
|
|
157
|
+
* @returns {AfriCodeConfig}
|
|
158
|
+
*/
|
|
159
|
+
export function getConfig() {
|
|
160
|
+
return Object.freeze(deepClone(_config));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if the framework has been initialized.
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
export function isInitialized() {
|
|
168
|
+
return _initialized;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Reset configuration to defaults.
|
|
173
|
+
* Primarily for testing.
|
|
174
|
+
*/
|
|
175
|
+
export function resetConfig() {
|
|
176
|
+
_config = deepClone(DEFAULT_CONFIG);
|
|
177
|
+
_initialized = false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ─────────────────────────────────────────────────────────────
|
|
181
|
+
// Observability Hooks — fire-and-forget event emitters
|
|
182
|
+
//
|
|
183
|
+
// These are framework-level hooks for monitoring and logging.
|
|
184
|
+
// They never throw — errors in hooks are caught and logged.
|
|
185
|
+
// ─────────────────────────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Emit a validation error event.
|
|
189
|
+
* @param {import('./errors.js').ValidationError} error
|
|
190
|
+
*/
|
|
191
|
+
export function emitValidationError(error) {
|
|
192
|
+
const hook = _config.hooks?.onValidationError;
|
|
193
|
+
if (typeof hook === 'function') {
|
|
194
|
+
try { hook(error); } catch (e) {
|
|
195
|
+
console.error('[AfriCode] Hook error in onValidationError:', e);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Emit a security violation event.
|
|
202
|
+
* @param {import('./errors.js').SecurityError} error
|
|
203
|
+
*/
|
|
204
|
+
export function emitSecurityViolation(error) {
|
|
205
|
+
const hook = _config.hooks?.onSecurityViolation;
|
|
206
|
+
if (typeof hook === 'function') {
|
|
207
|
+
try { hook(error); } catch (e) {
|
|
208
|
+
console.error('[AfriCode] Hook error in onSecurityViolation:', e);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Emit a rate limit event.
|
|
215
|
+
* @param {string} key - The client identifier that was rate limited
|
|
216
|
+
* @param {Request} [request] - The request that triggered the limit
|
|
217
|
+
*/
|
|
218
|
+
export function emitRateLimit(key, request = null) {
|
|
219
|
+
const hook = _config.hooks?.onRateLimit;
|
|
220
|
+
if (typeof hook === 'function') {
|
|
221
|
+
try { hook(key, request); } catch (e) {
|
|
222
|
+
console.error('[AfriCode] Hook error in onRateLimit:', e);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Emit a database error event.
|
|
229
|
+
* @param {import('./errors.js').DatabaseError} error
|
|
230
|
+
*/
|
|
231
|
+
export function emitDatabaseError(error) {
|
|
232
|
+
const hook = _config.hooks?.onDatabaseError;
|
|
233
|
+
if (typeof hook === 'function') {
|
|
234
|
+
try { hook(error); } catch (e) {
|
|
235
|
+
console.error('[AfriCode] Hook error in onDatabaseError:', e);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Emit a request event.
|
|
242
|
+
* @param {Request} request
|
|
243
|
+
*/
|
|
244
|
+
export function emitRequest(request) {
|
|
245
|
+
const hook = _config.hooks?.onRequest;
|
|
246
|
+
if (typeof hook === 'function') {
|
|
247
|
+
try { hook(request); } catch (e) {
|
|
248
|
+
console.error('[AfriCode] Hook error in onRequest:', e);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export default {
|
|
254
|
+
createFramework,
|
|
255
|
+
getConfig,
|
|
256
|
+
isInitialized,
|
|
257
|
+
resetConfig,
|
|
258
|
+
emitValidationError,
|
|
259
|
+
emitSecurityViolation,
|
|
260
|
+
emitRateLimit,
|
|
261
|
+
emitDatabaseError,
|
|
262
|
+
emitRequest
|
|
263
|
+
};
|