@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.
- package/README.md +95 -10
- package/dist/index.cjs +169 -507
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -223
- package/dist/index.d.ts +24 -223
- package/dist/index.js +175 -505
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +177 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +26 -0
- package/dist/logger.d.ts +26 -0
- package/dist/logger.js +158 -0
- package/dist/logger.js.map +1 -0
- package/package.json +36 -15
- package/.turbo/turbo-build.log +0 -22
- package/ADVANCED_FEATURES.md +0 -380
- package/API_REGISTRY.md +0 -392
- package/CHANGELOG.md +0 -472
- package/PHASE2_IMPLEMENTATION.md +0 -388
- package/REFACTORING_SUMMARY.md +0 -40
- package/examples/api-registry-example.ts +0 -559
- package/examples/kernel-features-example.ts +0 -311
- package/examples/phase2-integration.ts +0 -357
- package/src/api-registry-plugin.test.ts +0 -393
- package/src/api-registry-plugin.ts +0 -89
- package/src/api-registry.test.ts +0 -1089
- package/src/api-registry.ts +0 -739
- package/src/contracts/data-engine.ts +0 -57
- package/src/contracts/http-server.ts +0 -151
- package/src/contracts/logger.ts +0 -72
- package/src/dependency-resolver.test.ts +0 -287
- package/src/dependency-resolver.ts +0 -390
- package/src/fallbacks/fallbacks.test.ts +0 -281
- package/src/fallbacks/index.ts +0 -26
- package/src/fallbacks/memory-cache.ts +0 -34
- package/src/fallbacks/memory-i18n.ts +0 -112
- package/src/fallbacks/memory-job.ts +0 -23
- package/src/fallbacks/memory-metadata.ts +0 -50
- package/src/fallbacks/memory-queue.ts +0 -28
- package/src/health-monitor.test.ts +0 -81
- package/src/health-monitor.ts +0 -318
- package/src/hot-reload.ts +0 -382
- package/src/index.ts +0 -50
- package/src/kernel-base.ts +0 -273
- package/src/kernel.test.ts +0 -624
- package/src/kernel.ts +0 -631
- package/src/lite-kernel.test.ts +0 -248
- package/src/lite-kernel.ts +0 -137
- package/src/logger.test.ts +0 -116
- package/src/logger.ts +0 -355
- package/src/namespace-resolver.test.ts +0 -130
- package/src/namespace-resolver.ts +0 -188
- package/src/package-manager.test.ts +0 -225
- package/src/package-manager.ts +0 -428
- package/src/plugin-loader.test.ts +0 -421
- package/src/plugin-loader.ts +0 -484
- package/src/qa/adapter.ts +0 -16
- package/src/qa/http-adapter.ts +0 -116
- package/src/qa/index.ts +0 -5
- package/src/qa/runner.ts +0 -189
- package/src/security/index.ts +0 -50
- package/src/security/permission-manager.test.ts +0 -256
- package/src/security/permission-manager.ts +0 -338
- package/src/security/plugin-config-validator.test.ts +0 -276
- package/src/security/plugin-config-validator.ts +0 -193
- package/src/security/plugin-permission-enforcer.test.ts +0 -251
- package/src/security/plugin-permission-enforcer.ts +0 -436
- package/src/security/plugin-signature-verifier.ts +0 -403
- package/src/security/sandbox-runtime.ts +0 -462
- package/src/security/security-scanner.ts +0 -367
- package/src/types.ts +0 -120
- package/src/utils/env.test.ts +0 -62
- package/src/utils/env.ts +0 -53
- package/tsconfig.json +0 -10
- package/vitest.config.ts +0 -10
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
EngineQueryOptions,
|
|
5
|
-
DataEngineInsertOptions,
|
|
6
|
-
EngineUpdateOptions,
|
|
7
|
-
EngineDeleteOptions,
|
|
8
|
-
EngineAggregateOptions,
|
|
9
|
-
EngineCountOptions,
|
|
10
|
-
DataEngineRequest,
|
|
11
|
-
} from '@objectstack/spec/data';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* IDataEngine - Standard Data Engine Interface
|
|
15
|
-
*
|
|
16
|
-
* Abstract interface for data persistence capabilities.
|
|
17
|
-
* Following the Dependency Inversion Principle - plugins depend on this interface,
|
|
18
|
-
* not on concrete database implementations.
|
|
19
|
-
*
|
|
20
|
-
* All query methods use standard QueryAST parameter names
|
|
21
|
-
* (where/fields/orderBy/limit/offset/expand) to eliminate mechanical translation
|
|
22
|
-
* between the Engine and Driver layers.
|
|
23
|
-
*
|
|
24
|
-
* Aligned with 'src/data/data-engine.zod.ts' in @objectstack/spec.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
export interface IDataEngine {
|
|
28
|
-
find(objectName: string, query?: EngineQueryOptions): Promise<any[]>;
|
|
29
|
-
findOne(objectName: string, query?: EngineQueryOptions): Promise<any>;
|
|
30
|
-
insert(objectName: string, data: any | any[], options?: DataEngineInsertOptions): Promise<any>;
|
|
31
|
-
update(objectName: string, data: any, options?: EngineUpdateOptions): Promise<any>;
|
|
32
|
-
delete(objectName: string, options?: EngineDeleteOptions): Promise<any>;
|
|
33
|
-
count(objectName: string, query?: EngineCountOptions): Promise<number>;
|
|
34
|
-
aggregate(objectName: string, query: EngineAggregateOptions): Promise<any[]>;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Vector Search (AI/RAG)
|
|
38
|
-
*/
|
|
39
|
-
vectorFind?(objectName: string, vector: number[], options?: { where?: any, limit?: number, fields?: string[], threshold?: number }): Promise<any[]>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Batch Operations (Transactional)
|
|
43
|
-
*/
|
|
44
|
-
batch?(requests: DataEngineRequest[], options?: { transaction?: boolean }): Promise<any[]>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Execute raw command (Escape hatch)
|
|
48
|
-
*/
|
|
49
|
-
execute?(command: any, options?: Record<string, any>): Promise<any>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @deprecated Use `IDataDriver` from `@objectstack/spec/contracts` instead.
|
|
54
|
-
* This type is re-exported from `@objectstack/spec/contracts` for backward compatibility only.
|
|
55
|
-
*/
|
|
56
|
-
export type { DriverInterface } from '@objectstack/spec/contracts';
|
|
57
|
-
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* IHttpServer - Standard HTTP Server Interface
|
|
5
|
-
*
|
|
6
|
-
* Abstract interface for HTTP server capabilities.
|
|
7
|
-
* This allows plugins to interact with HTTP servers without knowing
|
|
8
|
-
* the underlying implementation (Express, Fastify, Hono, etc.).
|
|
9
|
-
*
|
|
10
|
-
* Follows Dependency Inversion Principle - plugins depend on this interface,
|
|
11
|
-
* not on concrete HTTP framework implementations.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
// We use Zod for validation but export interfaces for internal implementation
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Generic HTTP Request type
|
|
18
|
-
* Abstraction over framework-specific request objects
|
|
19
|
-
*/
|
|
20
|
-
export interface IHttpRequest {
|
|
21
|
-
/** Request path parameters */
|
|
22
|
-
params: Record<string, string>;
|
|
23
|
-
/** Request query parameters */
|
|
24
|
-
query: Record<string, string | string[]>;
|
|
25
|
-
/** Request body */
|
|
26
|
-
body?: any;
|
|
27
|
-
/** Request headers */
|
|
28
|
-
headers: Record<string, string | string[]>;
|
|
29
|
-
/** HTTP method */
|
|
30
|
-
method: string;
|
|
31
|
-
/** Request path */
|
|
32
|
-
path: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Generic HTTP Response type
|
|
37
|
-
* Abstraction over framework-specific response objects
|
|
38
|
-
*/
|
|
39
|
-
export interface IHttpResponse {
|
|
40
|
-
/**
|
|
41
|
-
* Send a JSON response
|
|
42
|
-
* @param data - Data to send
|
|
43
|
-
*/
|
|
44
|
-
json(data: any): void | Promise<void>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Send a text/html response
|
|
48
|
-
* @param data - Data to send
|
|
49
|
-
*/
|
|
50
|
-
send(data: string): void | Promise<void>;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Set HTTP status code
|
|
54
|
-
* @param code - HTTP status code
|
|
55
|
-
*/
|
|
56
|
-
status(code: number): IHttpResponse;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Set response header
|
|
60
|
-
* @param name - Header name
|
|
61
|
-
* @param value - Header value (string or array of strings for multi-value headers)
|
|
62
|
-
*/
|
|
63
|
-
header(name: string, value: string | string[]): IHttpResponse;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Route handler function
|
|
68
|
-
*/
|
|
69
|
-
export type RouteHandler = (
|
|
70
|
-
req: IHttpRequest,
|
|
71
|
-
res: IHttpResponse
|
|
72
|
-
) => void | Promise<void>;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Middleware function
|
|
76
|
-
*/
|
|
77
|
-
export type Middleware = (
|
|
78
|
-
req: IHttpRequest,
|
|
79
|
-
res: IHttpResponse,
|
|
80
|
-
next: () => void | Promise<void>
|
|
81
|
-
) => void | Promise<void>;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* IHttpServer - HTTP Server capability interface
|
|
85
|
-
*
|
|
86
|
-
* Defines the contract for HTTP server implementations.
|
|
87
|
-
* Concrete implementations (Express, Fastify, Hono) should implement this interface.
|
|
88
|
-
*/
|
|
89
|
-
export interface IHttpServer {
|
|
90
|
-
/**
|
|
91
|
-
* Register a GET route handler
|
|
92
|
-
* @param path - Route path (e.g., '/api/users/:id')
|
|
93
|
-
* @param handler - Route handler function
|
|
94
|
-
*/
|
|
95
|
-
get(path: string, handler: RouteHandler): void;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Register a POST route handler
|
|
99
|
-
* @param path - Route path
|
|
100
|
-
* @param handler - Route handler function
|
|
101
|
-
*/
|
|
102
|
-
post(path: string, handler: RouteHandler): void;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Register a PUT route handler
|
|
106
|
-
* @param path - Route path
|
|
107
|
-
* @param handler - Route handler function
|
|
108
|
-
*/
|
|
109
|
-
put(path: string, handler: RouteHandler): void;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Register a DELETE route handler
|
|
113
|
-
* @param path - Route path
|
|
114
|
-
* @param handler - Route handler function
|
|
115
|
-
*/
|
|
116
|
-
delete(path: string, handler: RouteHandler): void;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Register a PATCH route handler
|
|
120
|
-
* @param path - Route path
|
|
121
|
-
* @param handler - Route handler function
|
|
122
|
-
*/
|
|
123
|
-
patch(path: string, handler: RouteHandler): void;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Register middleware
|
|
127
|
-
* @param path - Optional path to apply middleware to (if omitted, applies globally)
|
|
128
|
-
* @param handler - Middleware function
|
|
129
|
-
*/
|
|
130
|
-
use(path: string | Middleware, handler?: Middleware): void;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Start the HTTP server
|
|
134
|
-
* @param port - Port number to listen on
|
|
135
|
-
* @returns Promise that resolves when server is ready
|
|
136
|
-
*/
|
|
137
|
-
listen(port: number): Promise<void>;
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get the port the server is listening on.
|
|
141
|
-
* Returns the actual bound port after `listen()` resolves, or the
|
|
142
|
-
* configured port before that.
|
|
143
|
-
*/
|
|
144
|
-
getPort?(): number;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Stop the HTTP server
|
|
148
|
-
* @returns Promise that resolves when server is stopped
|
|
149
|
-
*/
|
|
150
|
-
close?(): Promise<void>;
|
|
151
|
-
}
|
package/src/contracts/logger.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Logger Contract
|
|
5
|
-
*
|
|
6
|
-
* Defines the interface for logging in ObjectStack.
|
|
7
|
-
* Compatible with both browser console and structured logging systems.
|
|
8
|
-
*/
|
|
9
|
-
export interface Logger {
|
|
10
|
-
/**
|
|
11
|
-
* Log a debug message
|
|
12
|
-
* @param message - The message to log
|
|
13
|
-
* @param meta - Optional metadata to include
|
|
14
|
-
*/
|
|
15
|
-
debug(message: string, meta?: Record<string, any>): void;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Log an informational message
|
|
19
|
-
* @param message - The message to log
|
|
20
|
-
* @param meta - Optional metadata to include
|
|
21
|
-
*/
|
|
22
|
-
info(message: string, meta?: Record<string, any>): void;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Log a warning message
|
|
26
|
-
* @param message - The message to log
|
|
27
|
-
* @param meta - Optional metadata to include
|
|
28
|
-
*/
|
|
29
|
-
warn(message: string, meta?: Record<string, any>): void;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Log an error message
|
|
33
|
-
* @param message - The message to log
|
|
34
|
-
* @param error - Optional error object
|
|
35
|
-
* @param meta - Optional metadata to include
|
|
36
|
-
*/
|
|
37
|
-
error(message: string, error?: Error, meta?: Record<string, any>): void;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Log a fatal error message
|
|
41
|
-
* @param message - The message to log
|
|
42
|
-
* @param error - Optional error object
|
|
43
|
-
* @param meta - Optional metadata to include
|
|
44
|
-
*/
|
|
45
|
-
fatal?(message: string, error?: Error, meta?: Record<string, any>): void;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Create a child logger with additional context
|
|
49
|
-
* @param context - Context to add to all logs from this child
|
|
50
|
-
*/
|
|
51
|
-
child?(context: Record<string, any>): Logger;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Set trace context for distributed tracing
|
|
55
|
-
* @param traceId - Trace identifier
|
|
56
|
-
* @param spanId - Span identifier
|
|
57
|
-
*/
|
|
58
|
-
withTrace?(traceId: string, spanId?: string): Logger;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Compatibility method for console.log usage
|
|
62
|
-
* @param message - The message to log
|
|
63
|
-
* @param args - Additional arguments
|
|
64
|
-
*/
|
|
65
|
-
log?(message: string, ...args: any[]): void;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Cleanup resources (close file streams, etc.)
|
|
69
|
-
* Should be called when the logger is no longer needed
|
|
70
|
-
*/
|
|
71
|
-
destroy?(): Promise<void>;
|
|
72
|
-
}
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { SemanticVersionManager, DependencyResolver } from './dependency-resolver.js';
|
|
3
|
-
import { createLogger } from './logger.js';
|
|
4
|
-
|
|
5
|
-
describe('SemanticVersionManager', () => {
|
|
6
|
-
describe('parse', () => {
|
|
7
|
-
it('should parse standard semver', () => {
|
|
8
|
-
const version = SemanticVersionManager.parse('1.2.3');
|
|
9
|
-
expect(version).toEqual({
|
|
10
|
-
major: 1,
|
|
11
|
-
minor: 2,
|
|
12
|
-
patch: 3,
|
|
13
|
-
preRelease: undefined,
|
|
14
|
-
build: undefined,
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should parse semver with pre-release', () => {
|
|
19
|
-
const version = SemanticVersionManager.parse('1.2.3-alpha.1');
|
|
20
|
-
expect(version).toEqual({
|
|
21
|
-
major: 1,
|
|
22
|
-
minor: 2,
|
|
23
|
-
patch: 3,
|
|
24
|
-
preRelease: 'alpha.1',
|
|
25
|
-
build: undefined,
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should parse semver with build metadata', () => {
|
|
30
|
-
const version = SemanticVersionManager.parse('1.2.3+build.123');
|
|
31
|
-
expect(version).toEqual({
|
|
32
|
-
major: 1,
|
|
33
|
-
minor: 2,
|
|
34
|
-
patch: 3,
|
|
35
|
-
preRelease: undefined,
|
|
36
|
-
build: 'build.123',
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should parse semver with both pre-release and build', () => {
|
|
41
|
-
const version = SemanticVersionManager.parse('1.2.3-beta.2+build.456');
|
|
42
|
-
expect(version).toEqual({
|
|
43
|
-
major: 1,
|
|
44
|
-
minor: 2,
|
|
45
|
-
patch: 3,
|
|
46
|
-
preRelease: 'beta.2',
|
|
47
|
-
build: 'build.456',
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should handle v prefix', () => {
|
|
52
|
-
const version = SemanticVersionManager.parse('v1.2.3');
|
|
53
|
-
expect(version.major).toBe(1);
|
|
54
|
-
expect(version.minor).toBe(2);
|
|
55
|
-
expect(version.patch).toBe(3);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('compare', () => {
|
|
60
|
-
it('should compare major versions', () => {
|
|
61
|
-
const v1 = SemanticVersionManager.parse('2.0.0');
|
|
62
|
-
const v2 = SemanticVersionManager.parse('1.0.0');
|
|
63
|
-
expect(SemanticVersionManager.compare(v1, v2)).toBeGreaterThan(0);
|
|
64
|
-
expect(SemanticVersionManager.compare(v2, v1)).toBeLessThan(0);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should compare minor versions', () => {
|
|
68
|
-
const v1 = SemanticVersionManager.parse('1.2.0');
|
|
69
|
-
const v2 = SemanticVersionManager.parse('1.1.0');
|
|
70
|
-
expect(SemanticVersionManager.compare(v1, v2)).toBeGreaterThan(0);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should compare patch versions', () => {
|
|
74
|
-
const v1 = SemanticVersionManager.parse('1.0.2');
|
|
75
|
-
const v2 = SemanticVersionManager.parse('1.0.1');
|
|
76
|
-
expect(SemanticVersionManager.compare(v1, v2)).toBeGreaterThan(0);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should handle equal versions', () => {
|
|
80
|
-
const v1 = SemanticVersionManager.parse('1.2.3');
|
|
81
|
-
const v2 = SemanticVersionManager.parse('1.2.3');
|
|
82
|
-
expect(SemanticVersionManager.compare(v1, v2)).toBe(0);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should treat pre-release as lower than release', () => {
|
|
86
|
-
const v1 = SemanticVersionManager.parse('1.0.0-alpha');
|
|
87
|
-
const v2 = SemanticVersionManager.parse('1.0.0');
|
|
88
|
-
expect(SemanticVersionManager.compare(v1, v2)).toBeLessThan(0);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('satisfies', () => {
|
|
93
|
-
it('should match exact version', () => {
|
|
94
|
-
const version = SemanticVersionManager.parse('1.2.3');
|
|
95
|
-
expect(SemanticVersionManager.satisfies(version, '1.2.3')).toBe(true);
|
|
96
|
-
expect(SemanticVersionManager.satisfies(version, '1.2.4')).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should match caret range', () => {
|
|
100
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
101
|
-
expect(SemanticVersionManager.satisfies(version, '^1.2.3')).toBe(true);
|
|
102
|
-
expect(SemanticVersionManager.satisfies(version, '^1.3.0')).toBe(false);
|
|
103
|
-
expect(SemanticVersionManager.satisfies(version, '^2.0.0')).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should match tilde range', () => {
|
|
107
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
108
|
-
expect(SemanticVersionManager.satisfies(version, '~1.2.3')).toBe(true);
|
|
109
|
-
expect(SemanticVersionManager.satisfies(version, '~1.3.0')).toBe(false);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should match greater than or equal', () => {
|
|
113
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
114
|
-
expect(SemanticVersionManager.satisfies(version, '>=1.2.3')).toBe(true);
|
|
115
|
-
expect(SemanticVersionManager.satisfies(version, '>=1.2.5')).toBe(true);
|
|
116
|
-
expect(SemanticVersionManager.satisfies(version, '>=1.3.0')).toBe(false);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should match less than', () => {
|
|
120
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
121
|
-
expect(SemanticVersionManager.satisfies(version, '<1.3.0')).toBe(true);
|
|
122
|
-
expect(SemanticVersionManager.satisfies(version, '<1.2.5')).toBe(false);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should match range', () => {
|
|
126
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
127
|
-
expect(SemanticVersionManager.satisfies(version, '1.2.0 - 1.3.0')).toBe(true);
|
|
128
|
-
expect(SemanticVersionManager.satisfies(version, '1.3.0 - 1.4.0')).toBe(false);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should match wildcard', () => {
|
|
132
|
-
const version = SemanticVersionManager.parse('1.2.5');
|
|
133
|
-
expect(SemanticVersionManager.satisfies(version, '*')).toBe(true);
|
|
134
|
-
expect(SemanticVersionManager.satisfies(version, 'latest')).toBe(true);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('getCompatibilityLevel', () => {
|
|
139
|
-
it('should detect fully compatible versions', () => {
|
|
140
|
-
const from = SemanticVersionManager.parse('1.2.3');
|
|
141
|
-
const to = SemanticVersionManager.parse('1.2.3');
|
|
142
|
-
expect(SemanticVersionManager.getCompatibilityLevel(from, to)).toBe('fully-compatible');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should detect backward compatible versions', () => {
|
|
146
|
-
const from = SemanticVersionManager.parse('1.2.3');
|
|
147
|
-
const to = SemanticVersionManager.parse('1.3.0');
|
|
148
|
-
expect(SemanticVersionManager.getCompatibilityLevel(from, to)).toBe('backward-compatible');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('should detect breaking changes', () => {
|
|
152
|
-
const from = SemanticVersionManager.parse('1.2.3');
|
|
153
|
-
const to = SemanticVersionManager.parse('2.0.0');
|
|
154
|
-
expect(SemanticVersionManager.getCompatibilityLevel(from, to)).toBe('breaking-changes');
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should detect incompatible (downgrade)', () => {
|
|
158
|
-
const from = SemanticVersionManager.parse('1.3.0');
|
|
159
|
-
const to = SemanticVersionManager.parse('1.2.0');
|
|
160
|
-
expect(SemanticVersionManager.getCompatibilityLevel(from, to)).toBe('incompatible');
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe('DependencyResolver', () => {
|
|
166
|
-
let resolver: DependencyResolver;
|
|
167
|
-
let logger: ReturnType<typeof createLogger>;
|
|
168
|
-
|
|
169
|
-
beforeEach(() => {
|
|
170
|
-
logger = createLogger({ level: 'silent' });
|
|
171
|
-
resolver = new DependencyResolver(logger);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
describe('resolve', () => {
|
|
175
|
-
it('should resolve dependencies in topological order', () => {
|
|
176
|
-
const plugins = new Map([
|
|
177
|
-
['a', { dependencies: [] }],
|
|
178
|
-
['b', { dependencies: ['a'] }],
|
|
179
|
-
['c', { dependencies: ['a', 'b'] }],
|
|
180
|
-
]);
|
|
181
|
-
|
|
182
|
-
const order = resolver.resolve(plugins);
|
|
183
|
-
|
|
184
|
-
expect(order.indexOf('a')).toBeLessThan(order.indexOf('b'));
|
|
185
|
-
expect(order.indexOf('b')).toBeLessThan(order.indexOf('c'));
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should handle plugins with no dependencies', () => {
|
|
189
|
-
const plugins = new Map([
|
|
190
|
-
['a', { dependencies: [] }],
|
|
191
|
-
['b', { dependencies: [] }],
|
|
192
|
-
]);
|
|
193
|
-
|
|
194
|
-
const order = resolver.resolve(plugins);
|
|
195
|
-
expect(order).toHaveLength(2);
|
|
196
|
-
expect(order).toContain('a');
|
|
197
|
-
expect(order).toContain('b');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('should detect circular dependencies', () => {
|
|
201
|
-
const plugins = new Map([
|
|
202
|
-
['a', { dependencies: ['b'] }],
|
|
203
|
-
['b', { dependencies: ['a'] }],
|
|
204
|
-
]);
|
|
205
|
-
|
|
206
|
-
expect(() => resolver.resolve(plugins)).toThrow('Circular dependency');
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('should detect missing dependencies', () => {
|
|
210
|
-
const plugins = new Map([
|
|
211
|
-
['a', { dependencies: ['missing'] }],
|
|
212
|
-
]);
|
|
213
|
-
|
|
214
|
-
expect(() => resolver.resolve(plugins)).toThrow('Missing dependency');
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
describe('detectConflicts', () => {
|
|
219
|
-
it('should detect version mismatches', () => {
|
|
220
|
-
const plugins = new Map<string, any>([
|
|
221
|
-
['core', { version: '1.0.0', dependencies: {} }],
|
|
222
|
-
['plugin-a', { version: '1.0.0', dependencies: { core: '^2.0.0' } }],
|
|
223
|
-
]);
|
|
224
|
-
|
|
225
|
-
const conflicts = resolver.detectConflicts(plugins);
|
|
226
|
-
expect(conflicts.length).toBeGreaterThan(0);
|
|
227
|
-
expect(conflicts[0].type).toBe('version-mismatch');
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should return no conflicts for compatible versions', () => {
|
|
231
|
-
const plugins = new Map<string, any>([
|
|
232
|
-
['core', { version: '1.2.0', dependencies: {} }],
|
|
233
|
-
['plugin-a', { version: '1.0.0', dependencies: { core: '^1.0.0' } }],
|
|
234
|
-
]);
|
|
235
|
-
|
|
236
|
-
const conflicts = resolver.detectConflicts(plugins);
|
|
237
|
-
expect(conflicts.length).toBe(0);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('findBestVersion', () => {
|
|
242
|
-
it('should find highest matching version', () => {
|
|
243
|
-
const available = ['1.0.0', '1.1.0', '1.2.0', '2.0.0'];
|
|
244
|
-
const constraints = ['^1.0.0'];
|
|
245
|
-
|
|
246
|
-
const best = resolver.findBestVersion(available, constraints);
|
|
247
|
-
expect(best).toBe('1.2.0');
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('should satisfy all constraints', () => {
|
|
251
|
-
const available = ['1.0.0', '1.1.0', '1.2.0', '2.0.0'];
|
|
252
|
-
const constraints = ['^1.0.0', '>=1.1.0', '<2.0.0'];
|
|
253
|
-
|
|
254
|
-
const best = resolver.findBestVersion(available, constraints);
|
|
255
|
-
expect(best).toBe('1.2.0');
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('should return undefined if no version satisfies', () => {
|
|
259
|
-
const available = ['1.0.0', '1.1.0'];
|
|
260
|
-
const constraints = ['^2.0.0'];
|
|
261
|
-
|
|
262
|
-
const best = resolver.findBestVersion(available, constraints);
|
|
263
|
-
expect(best).toBeUndefined();
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
describe('isAcyclic', () => {
|
|
268
|
-
it('should detect acyclic graph', () => {
|
|
269
|
-
const deps = new Map([
|
|
270
|
-
['a', []],
|
|
271
|
-
['b', ['a']],
|
|
272
|
-
['c', ['a', 'b']],
|
|
273
|
-
]);
|
|
274
|
-
|
|
275
|
-
expect(resolver.isAcyclic(deps)).toBe(true);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it('should detect cyclic graph', () => {
|
|
279
|
-
const deps = new Map([
|
|
280
|
-
['a', ['b']],
|
|
281
|
-
['b', ['a']],
|
|
282
|
-
]);
|
|
283
|
-
|
|
284
|
-
expect(resolver.isAcyclic(deps)).toBe(false);
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
});
|