@objectstack/core 4.0.4 → 4.0.5

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 (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +169 -507
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +24 -223
  5. package/dist/index.d.ts +24 -223
  6. package/dist/index.js +175 -505
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.cjs +177 -0
  9. package/dist/logger.cjs.map +1 -0
  10. package/dist/logger.d.cts +26 -0
  11. package/dist/logger.d.ts +26 -0
  12. package/dist/logger.js +158 -0
  13. package/dist/logger.js.map +1 -0
  14. package/package.json +36 -15
  15. package/.turbo/turbo-build.log +0 -22
  16. package/ADVANCED_FEATURES.md +0 -380
  17. package/API_REGISTRY.md +0 -392
  18. package/CHANGELOG.md +0 -472
  19. package/PHASE2_IMPLEMENTATION.md +0 -388
  20. package/REFACTORING_SUMMARY.md +0 -40
  21. package/examples/api-registry-example.ts +0 -559
  22. package/examples/kernel-features-example.ts +0 -311
  23. package/examples/phase2-integration.ts +0 -357
  24. package/src/api-registry-plugin.test.ts +0 -393
  25. package/src/api-registry-plugin.ts +0 -89
  26. package/src/api-registry.test.ts +0 -1089
  27. package/src/api-registry.ts +0 -739
  28. package/src/contracts/data-engine.ts +0 -57
  29. package/src/contracts/http-server.ts +0 -151
  30. package/src/contracts/logger.ts +0 -72
  31. package/src/dependency-resolver.test.ts +0 -287
  32. package/src/dependency-resolver.ts +0 -390
  33. package/src/fallbacks/fallbacks.test.ts +0 -281
  34. package/src/fallbacks/index.ts +0 -26
  35. package/src/fallbacks/memory-cache.ts +0 -34
  36. package/src/fallbacks/memory-i18n.ts +0 -112
  37. package/src/fallbacks/memory-job.ts +0 -23
  38. package/src/fallbacks/memory-metadata.ts +0 -50
  39. package/src/fallbacks/memory-queue.ts +0 -28
  40. package/src/health-monitor.test.ts +0 -81
  41. package/src/health-monitor.ts +0 -318
  42. package/src/hot-reload.ts +0 -382
  43. package/src/index.ts +0 -50
  44. package/src/kernel-base.ts +0 -273
  45. package/src/kernel.test.ts +0 -624
  46. package/src/kernel.ts +0 -631
  47. package/src/lite-kernel.test.ts +0 -248
  48. package/src/lite-kernel.ts +0 -137
  49. package/src/logger.test.ts +0 -116
  50. package/src/logger.ts +0 -355
  51. package/src/namespace-resolver.test.ts +0 -130
  52. package/src/namespace-resolver.ts +0 -188
  53. package/src/package-manager.test.ts +0 -225
  54. package/src/package-manager.ts +0 -428
  55. package/src/plugin-loader.test.ts +0 -421
  56. package/src/plugin-loader.ts +0 -484
  57. package/src/qa/adapter.ts +0 -16
  58. package/src/qa/http-adapter.ts +0 -116
  59. package/src/qa/index.ts +0 -5
  60. package/src/qa/runner.ts +0 -189
  61. package/src/security/index.ts +0 -50
  62. package/src/security/permission-manager.test.ts +0 -256
  63. package/src/security/permission-manager.ts +0 -338
  64. package/src/security/plugin-config-validator.test.ts +0 -276
  65. package/src/security/plugin-config-validator.ts +0 -193
  66. package/src/security/plugin-permission-enforcer.test.ts +0 -251
  67. package/src/security/plugin-permission-enforcer.ts +0 -436
  68. package/src/security/plugin-signature-verifier.ts +0 -403
  69. package/src/security/sandbox-runtime.ts +0 -462
  70. package/src/security/security-scanner.ts +0 -367
  71. package/src/types.ts +0 -120
  72. package/src/utils/env.test.ts +0 -62
  73. package/src/utils/env.ts +0 -53
  74. package/tsconfig.json +0 -10
  75. package/vitest.config.ts +0 -10
@@ -1,367 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type {
4
- KernelSecurityVulnerability,
5
- KernelSecurityScanResult
6
- } from '@objectstack/spec/kernel';
7
- import type { ObjectLogger } from '../logger.js';
8
-
9
- /**
10
- * Scan Target
11
- */
12
- export interface ScanTarget {
13
- pluginId: string;
14
- version: string;
15
- files?: string[];
16
- dependencies?: Record<string, string>;
17
- }
18
-
19
- /**
20
- * Security Issue
21
- */
22
- export interface SecurityIssue {
23
- id: string;
24
- severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
25
- category: 'vulnerability' | 'malware' | 'license' | 'code-quality' | 'configuration';
26
- title: string;
27
- description: string;
28
- location?: {
29
- file?: string;
30
- line?: number;
31
- column?: number;
32
- };
33
- remediation?: string;
34
- cve?: string;
35
- cvss?: number;
36
- }
37
-
38
- /**
39
- * Plugin Security Scanner
40
- *
41
- * Scans plugins for security vulnerabilities, malware, and license issues
42
- */
43
- export class PluginSecurityScanner {
44
- private logger: ObjectLogger;
45
-
46
- // Known vulnerabilities database (CVE cache)
47
- private vulnerabilityDb = new Map<string, KernelSecurityVulnerability>();
48
-
49
- // Scan results cache
50
- private scanResults = new Map<string, KernelSecurityScanResult>();
51
-
52
- private passThreshold: number = 70;
53
-
54
- constructor(logger: ObjectLogger, config?: { passThreshold?: number }) {
55
- this.logger = logger.child({ component: 'SecurityScanner' });
56
- if (config?.passThreshold !== undefined) {
57
- this.passThreshold = config.passThreshold;
58
- }
59
- }
60
-
61
- /**
62
- * Perform a comprehensive security scan on a plugin
63
- */
64
- async scan(target: ScanTarget): Promise<KernelSecurityScanResult> {
65
- this.logger.info('Starting security scan', {
66
- pluginId: target.pluginId,
67
- version: target.version
68
- });
69
-
70
- const issues: SecurityIssue[] = [];
71
-
72
- try {
73
- // 1. Scan for code vulnerabilities
74
- const codeIssues = await this.scanCode(target);
75
- issues.push(...codeIssues);
76
-
77
- // 2. Scan dependencies for known vulnerabilities
78
- const depIssues = await this.scanDependencies(target);
79
- issues.push(...depIssues);
80
-
81
- // 3. Scan for malware patterns
82
- const malwareIssues = await this.scanMalware(target);
83
- issues.push(...malwareIssues);
84
-
85
- // 4. Check license compliance
86
- const licenseIssues = await this.scanLicenses(target);
87
- issues.push(...licenseIssues);
88
-
89
- // 5. Check configuration security
90
- const configIssues = await this.scanConfiguration(target);
91
- issues.push(...configIssues);
92
-
93
- // Calculate security score (0-100, higher is better)
94
- const score = this.calculateSecurityScore(issues);
95
-
96
- const result: KernelSecurityScanResult = {
97
- timestamp: new Date().toISOString(),
98
- scanner: { name: 'ObjectStack Security Scanner', version: '1.0.0' },
99
- status: score >= this.passThreshold ? 'passed' : 'failed',
100
- vulnerabilities: issues.map(issue => ({
101
- id: issue.id,
102
- severity: issue.severity,
103
- category: issue.category,
104
- title: issue.title,
105
- description: issue.description,
106
- location: issue.location ? `${issue.location.file}:${issue.location.line}` : undefined,
107
- remediation: issue.remediation,
108
- affectedVersions: [],
109
- exploitAvailable: false,
110
- patchAvailable: false,
111
- })),
112
- summary: {
113
- totalVulnerabilities: issues.length,
114
- criticalCount: issues.filter(i => i.severity === 'critical').length,
115
- highCount: issues.filter(i => i.severity === 'high').length,
116
- mediumCount: issues.filter(i => i.severity === 'medium').length,
117
- lowCount: issues.filter(i => i.severity === 'low').length,
118
- infoCount: issues.filter(i => i.severity === 'info').length,
119
- },
120
- };
121
-
122
- this.scanResults.set(`${target.pluginId}:${target.version}`, result);
123
-
124
- this.logger.info('Security scan complete', {
125
- pluginId: target.pluginId,
126
- score,
127
- status: result.status,
128
- summary: result.summary
129
- });
130
-
131
- return result;
132
- } catch (error) {
133
- this.logger.error('Security scan failed', {
134
- pluginId: target.pluginId,
135
- error
136
- });
137
-
138
- throw error;
139
- }
140
- }
141
-
142
- /**
143
- * Scan code for vulnerabilities
144
- */
145
- private async scanCode(target: ScanTarget): Promise<SecurityIssue[]> {
146
- const issues: SecurityIssue[] = [];
147
-
148
- // In a real implementation, this would:
149
- // - Parse code with AST (e.g., using @typescript-eslint/parser)
150
- // - Check for dangerous patterns (eval, Function constructor, etc.)
151
- // - Check for XSS vulnerabilities
152
- // - Check for SQL injection patterns
153
- // - Check for insecure crypto usage
154
- // - Check for path traversal vulnerabilities
155
-
156
- this.logger.debug('Code scan complete', {
157
- pluginId: target.pluginId,
158
- issuesFound: issues.length
159
- });
160
-
161
- return issues;
162
- }
163
-
164
- /**
165
- * Scan dependencies for known vulnerabilities
166
- */
167
- private async scanDependencies(target: ScanTarget): Promise<SecurityIssue[]> {
168
- const issues: SecurityIssue[] = [];
169
-
170
- if (!target.dependencies) {
171
- return issues;
172
- }
173
-
174
- // In a real implementation, this would:
175
- // - Query npm audit API
176
- // - Check GitHub Advisory Database
177
- // - Check Snyk vulnerability database
178
- // - Check OSV (Open Source Vulnerabilities)
179
-
180
- for (const [depName, version] of Object.entries(target.dependencies)) {
181
- const vulnKey = `${depName}@${version}`;
182
- const vulnerability = this.vulnerabilityDb.get(vulnKey);
183
-
184
- if (vulnerability) {
185
- issues.push({
186
- id: `vuln-${vulnerability.cve || depName}`,
187
- severity: vulnerability.severity,
188
- category: 'vulnerability',
189
- title: `Vulnerable dependency: ${depName}`,
190
- description: `${depName}@${version} has known security vulnerabilities`,
191
- remediation: vulnerability.fixedIn
192
- ? `Upgrade to ${vulnerability.fixedIn.join(' or ')}`
193
- : 'No fix available',
194
- cve: vulnerability.cve,
195
- });
196
- }
197
- }
198
-
199
- this.logger.debug('Dependency scan complete', {
200
- pluginId: target.pluginId,
201
- dependencies: Object.keys(target.dependencies).length,
202
- vulnerabilities: issues.length
203
- });
204
-
205
- return issues;
206
- }
207
-
208
- /**
209
- * Scan for malware patterns
210
- */
211
- private async scanMalware(target: ScanTarget): Promise<SecurityIssue[]> {
212
- const issues: SecurityIssue[] = [];
213
-
214
- // In a real implementation, this would:
215
- // - Check for obfuscated code
216
- // - Check for suspicious network activity patterns
217
- // - Check for crypto mining patterns
218
- // - Check for data exfiltration patterns
219
- // - Use ML-based malware detection
220
- // - Check file hashes against known malware databases
221
-
222
- this.logger.debug('Malware scan complete', {
223
- pluginId: target.pluginId,
224
- issuesFound: issues.length
225
- });
226
-
227
- return issues;
228
- }
229
-
230
- /**
231
- * Check license compliance
232
- */
233
- private async scanLicenses(target: ScanTarget): Promise<SecurityIssue[]> {
234
- const issues: SecurityIssue[] = [];
235
-
236
- if (!target.dependencies) {
237
- return issues;
238
- }
239
-
240
- // In a real implementation, this would:
241
- // - Check license compatibility
242
- // - Detect GPL contamination
243
- // - Flag proprietary dependencies
244
- // - Check for missing licenses
245
- // - Verify SPDX identifiers
246
-
247
- this.logger.debug('License scan complete', {
248
- pluginId: target.pluginId,
249
- issuesFound: issues.length
250
- });
251
-
252
- return issues;
253
- }
254
-
255
- /**
256
- * Check configuration security
257
- */
258
- private async scanConfiguration(target: ScanTarget): Promise<SecurityIssue[]> {
259
- const issues: SecurityIssue[] = [];
260
-
261
- // In a real implementation, this would:
262
- // - Check for hardcoded secrets
263
- // - Check for weak permissions
264
- // - Check for insecure defaults
265
- // - Check for missing security headers
266
- // - Check CSP policies
267
-
268
- this.logger.debug('Configuration scan complete', {
269
- pluginId: target.pluginId,
270
- issuesFound: issues.length
271
- });
272
-
273
- return issues;
274
- }
275
-
276
- /**
277
- * Calculate security score based on issues
278
- */
279
- private calculateSecurityScore(issues: SecurityIssue[]): number {
280
- // Start with perfect score
281
- let score = 100;
282
-
283
- // Deduct points based on severity
284
- for (const issue of issues) {
285
- switch (issue.severity) {
286
- case 'critical':
287
- score -= 20;
288
- break;
289
- case 'high':
290
- score -= 10;
291
- break;
292
- case 'medium':
293
- score -= 5;
294
- break;
295
- case 'low':
296
- score -= 2;
297
- break;
298
- case 'info':
299
- score -= 0;
300
- break;
301
- }
302
- }
303
-
304
- // Ensure score doesn't go below 0
305
- return Math.max(0, score);
306
- }
307
-
308
- /**
309
- * Add a vulnerability to the database
310
- */
311
- addVulnerability(
312
- packageName: string,
313
- version: string,
314
- vulnerability: KernelSecurityVulnerability
315
- ): void {
316
- const key = `${packageName}@${version}`;
317
- this.vulnerabilityDb.set(key, vulnerability);
318
-
319
- this.logger.debug('Vulnerability added to database', {
320
- package: packageName,
321
- version,
322
- cve: vulnerability.cve
323
- });
324
- }
325
-
326
- /**
327
- * Get scan result from cache
328
- */
329
- getScanResult(pluginId: string, version: string): KernelSecurityScanResult | undefined {
330
- return this.scanResults.get(`${pluginId}:${version}`);
331
- }
332
-
333
- /**
334
- * Clear scan results cache
335
- */
336
- clearCache(): void {
337
- this.scanResults.clear();
338
- this.logger.debug('Scan results cache cleared');
339
- }
340
-
341
- /**
342
- * Update vulnerability database from external source
343
- */
344
- async updateVulnerabilityDatabase(): Promise<void> {
345
- this.logger.info('Updating vulnerability database');
346
-
347
- // In a real implementation, this would:
348
- // - Fetch from GitHub Advisory Database
349
- // - Fetch from npm audit
350
- // - Fetch from NVD (National Vulnerability Database)
351
- // - Parse and cache vulnerability data
352
-
353
- this.logger.info('Vulnerability database updated', {
354
- entries: this.vulnerabilityDb.size
355
- });
356
- }
357
-
358
- /**
359
- * Shutdown security scanner
360
- */
361
- shutdown(): void {
362
- this.vulnerabilityDb.clear();
363
- this.scanResults.clear();
364
-
365
- this.logger.info('Security scanner shutdown complete');
366
- }
367
- }
package/src/types.ts DELETED
@@ -1,120 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { ObjectKernel } from './kernel.js';
4
- import type { Logger } from '@objectstack/spec/contracts';
5
-
6
- /**
7
- * PluginContext - Runtime context available to plugins
8
- *
9
- * Provides access to:
10
- * - Service registry (registerService/getService)
11
- * - Event/Hook system (hook/trigger)
12
- * - Logger
13
- * - Kernel instance (for advanced use cases)
14
- */
15
- export interface PluginContext {
16
- /**
17
- * Register a service that can be consumed by other plugins
18
- * @param name - Service name (e.g., 'db', 'http-server', 'objectql')
19
- * @param service - Service instance
20
- */
21
- registerService(name: string, service: any): void;
22
-
23
- /**
24
- * Get a service registered by another plugin
25
- * @param name - Service name
26
- * @returns Service instance
27
- * @throws Error if service not found
28
- */
29
- getService<T>(name: string): T;
30
-
31
- /**
32
- * Replace an existing service with a new implementation.
33
- * Useful for optimization plugins that wrap or swap kernel internals
34
- * (e.g., metadata registry, connection pooling).
35
- *
36
- * @param name - Service name to replace
37
- * @param implementation - New service implementation
38
- * @throws Error if the service does not exist
39
- */
40
- replaceService<T>(name: string, implementation: T): void;
41
-
42
- /**
43
- * Get all registered services
44
- */
45
- getServices(): Map<string, any>;
46
-
47
- /**
48
- * Register a hook handler
49
- * @param name - Hook name (e.g., 'kernel:ready', 'data:beforeInsert')
50
- * @param handler - Hook handler function
51
- */
52
- hook(name: string, handler: (...args: any[]) => void | Promise<void>): void;
53
-
54
- /**
55
- * Trigger a hook
56
- * @param name - Hook name
57
- * @param args - Arguments to pass to hook handlers
58
- */
59
- trigger(name: string, ...args: any[]): Promise<void>;
60
-
61
- /**
62
- * Logger instance
63
- */
64
- logger: Logger;
65
-
66
- /**
67
- * Get the kernel instance (for advanced use cases)
68
- * @returns Kernel instance
69
- */
70
- getKernel(): ObjectKernel;
71
- }
72
-
73
- /**
74
- * Plugin Interface
75
- *
76
- * All ObjectStack plugins must implement this interface.
77
- */
78
- export interface Plugin {
79
- /**
80
- * Unique plugin name (e.g., 'com.objectstack.engine.objectql')
81
- */
82
- name: string;
83
-
84
- /**
85
- * Plugin version
86
- */
87
- version?: string;
88
-
89
- /**
90
- * Plugin type (standard, ui, driver, server, app, theme, agent)
91
- * @default 'standard'
92
- */
93
- type?: string;
94
-
95
- /**
96
- * List of other plugin names that this plugin depends on.
97
- * The kernel ensures these plugins are initialized before this one.
98
- */
99
- dependencies?: string[];
100
-
101
- /**
102
- * Init Phase: Register services
103
- * Called when kernel is initializing.
104
- * Use this to register services that other plugins might need.
105
- */
106
- init(ctx: PluginContext): Promise<void> | void;
107
-
108
- /**
109
- * Start Phase: Execute business logic
110
- * Called after all plugins have been initialized.
111
- * Use this to start servers, connect to DBs, or execute main logic.
112
- */
113
- start?(ctx: PluginContext): Promise<void> | void;
114
-
115
- /**
116
- * Destroy Phase: Cleanup
117
- * Called when kernel is shutting down.
118
- */
119
- destroy?(): Promise<void> | void;
120
- }
@@ -1,62 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest';
2
- import * as envUtils from './env';
3
-
4
- describe('Environment Utilities', () => {
5
-
6
- // Save original process
7
- const originalProcess = globalThis.process;
8
-
9
- afterEach(() => {
10
- // Restore process after each test
11
- globalThis.process = originalProcess;
12
- vi.restoreAllMocks();
13
- });
14
-
15
- describe('isNode', () => {
16
- it('should detect Node environment', () => {
17
- // Since we are running in Vitest (Node), this should be true
18
- expect(envUtils.isNode).toBe(true);
19
- });
20
- });
21
-
22
- describe('getEnv', () => {
23
- it('should retrieve environment variable in Node', () => {
24
- process.env.TEST_VAR = 'test_value';
25
- expect(envUtils.getEnv('TEST_VAR')).toBe('test_value');
26
- delete process.env.TEST_VAR;
27
- });
28
-
29
- it('should return default value if variable not found', () => {
30
- expect(envUtils.getEnv('NON_EXISTENT_VAR', 'default')).toBe('default');
31
- });
32
-
33
- it('should access globalThis.process.env if process is not available directly', () => {
34
- // This is tricky to test in Node because 'process' is globally available.
35
- // We can't easily delete global.process in strict mode or without breaking tooling.
36
- // But we can verify it works via globalThis
37
-
38
- // @ts-ignore
39
- globalThis.process.env.TEST_GLOBAL_VAR = 'global_value';
40
- expect(envUtils.getEnv('TEST_GLOBAL_VAR')).toBe('global_value');
41
- // @ts-ignore
42
- delete globalThis.process.env.TEST_GLOBAL_VAR;
43
- });
44
- });
45
-
46
- describe('getMemoryUsage', () => {
47
- it('should return memory usage in Node', () => {
48
- const usage = envUtils.getMemoryUsage();
49
- expect(usage).toHaveProperty('heapUsed');
50
- expect(usage).toHaveProperty('heapTotal');
51
- expect(usage.heapUsed).toBeGreaterThan(0);
52
- });
53
- });
54
-
55
- describe('safeExit', () => {
56
- it('should call process.exit in Node', () => {
57
- const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
58
- envUtils.safeExit(1);
59
- expect(exitSpy).toHaveBeenCalledWith(1);
60
- });
61
- });
62
- });
package/src/utils/env.ts DELETED
@@ -1,53 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * Environment utilities for universal (Node/Browser) compatibility.
5
- */
6
-
7
- // Check if running in a Node.js environment
8
- export const isNode = typeof process !== 'undefined' &&
9
- process.versions != null &&
10
- process.versions.node != null;
11
-
12
- /**
13
- * Safely access environment variables
14
- */
15
- export function getEnv(key: string, defaultValue?: string): string | undefined {
16
- // Node.js
17
- if (typeof process !== 'undefined' && process.env) {
18
- return process.env[key] || defaultValue;
19
- }
20
-
21
- // Browser (Vite/Webpack replacement usually handles process.env,
22
- // but if not, we check safe global access)
23
- try {
24
- // @ts-ignore
25
- if (typeof globalThis !== 'undefined' && globalThis.process?.env) {
26
- // @ts-ignore
27
- return globalThis.process.env[key] || defaultValue;
28
- }
29
- } catch (e) {
30
- // Ignore access errors
31
- }
32
-
33
- return defaultValue;
34
- }
35
-
36
- /**
37
- * Safely exit the process if in Node.js
38
- */
39
- export function safeExit(code: number = 0): void {
40
- if (isNode) {
41
- process.exit(code);
42
- }
43
- }
44
-
45
- /**
46
- * Safely get memory usage
47
- */
48
- export function getMemoryUsage(): { heapUsed: number; heapTotal: number } {
49
- if (isNode) {
50
- return process.memoryUsage();
51
- }
52
- return { heapUsed: 0, heapTotal: 0 };
53
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src",
6
- "types": ["node"]
7
- },
8
- "include": ["src/**/*"],
9
- "exclude": []
10
- }
package/vitest.config.ts DELETED
@@ -1,10 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { defineConfig } from 'vitest/config';
4
-
5
- export default defineConfig({
6
- test: {
7
- globals: true,
8
- environment: 'node',
9
- },
10
- });