@rangka/core 0.1.0 → 0.1.2
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/package.json +6 -2
- package/.claude/skills/extend-core/SKILL.md +0 -133
- package/.turbo/turbo-build.log +0 -4
- package/CHANGELOG.md +0 -18
- package/CLAUDE.md +0 -180
- package/src/__tests__/coerce.test.ts +0 -154
- package/src/__tests__/context.test.ts +0 -111
- package/src/__tests__/helpers.ts +0 -21
- package/src/__tests__/index.test.ts +0 -7
- package/src/__tests__/widgets.test.ts +0 -197
- package/src/api/__tests__/handlers.test.ts +0 -389
- package/src/api/__tests__/include-resolver.test.ts +0 -393
- package/src/api/__tests__/middleware.test.ts +0 -100
- package/src/api/__tests__/openapi-schema.test.ts +0 -210
- package/src/api/__tests__/query-parser.test.ts +0 -291
- package/src/api/__tests__/route-generator.test.ts +0 -137
- package/src/api/__tests__/server.test.ts +0 -73
- package/src/api/__tests__/swagger.test.ts +0 -166
- package/src/api/handlers.ts +0 -274
- package/src/api/include-resolver.ts +0 -27
- package/src/api/index.ts +0 -4
- package/src/api/meta-handler.ts +0 -254
- package/src/api/openapi-schema.ts +0 -99
- package/src/api/query-parser.ts +0 -315
- package/src/api/route-generator.ts +0 -448
- package/src/api/server.ts +0 -147
- package/src/api/types.ts +0 -16
- package/src/audit/__tests__/audit.test.ts +0 -144
- package/src/audit/index.ts +0 -3
- package/src/audit/record.ts +0 -69
- package/src/audit/tables.ts +0 -48
- package/src/audit/types.ts +0 -26
- package/src/auth/__tests__/core-module.test.ts +0 -54
- package/src/auth/__tests__/debug.test.ts +0 -47
- package/src/auth/__tests__/field-permissions.test.ts +0 -245
- package/src/auth/__tests__/integration.test.ts +0 -208
- package/src/auth/__tests__/meta-boot.test.ts +0 -538
- package/src/auth/__tests__/model-permissions.test.ts +0 -205
- package/src/auth/__tests__/password.test.ts +0 -29
- package/src/auth/__tests__/permission-registry.test.ts +0 -313
- package/src/auth/__tests__/scope-hook.test.ts +0 -509
- package/src/auth/__tests__/scope-registry.test.ts +0 -297
- package/src/auth/__tests__/scopes.test.ts +0 -66
- package/src/auth/__tests__/session.test.ts +0 -214
- package/src/auth/core-models.ts +0 -52
- package/src/auth/core-module.ts +0 -59
- package/src/auth/debug.ts +0 -157
- package/src/auth/field-permissions.ts +0 -116
- package/src/auth/index.ts +0 -37
- package/src/auth/model-permissions.ts +0 -59
- package/src/auth/password.ts +0 -22
- package/src/auth/permission-registry.ts +0 -171
- package/src/auth/scope-filters.ts +0 -11
- package/src/auth/scope-registry.ts +0 -121
- package/src/auth/scopes.ts +0 -146
- package/src/auth/seed.ts +0 -44
- package/src/auth/session.ts +0 -178
- package/src/auth/types.ts +0 -50
- package/src/boot/__tests__/page-scanning.test.ts +0 -170
- package/src/boot/__tests__/page-utils.test.ts +0 -225
- package/src/boot/__tests__/project-scanner.test.ts +0 -88
- package/src/boot/dependency-sort.ts +0 -82
- package/src/boot/discovery.ts +0 -85
- package/src/boot/index.ts +0 -457
- package/src/boot/page-utils.ts +0 -110
- package/src/boot/project-scanner.ts +0 -397
- package/src/boot/schema-loader.ts +0 -26
- package/src/boot/schema-merger.ts +0 -125
- package/src/boot/traits.ts +0 -25
- package/src/boot/types.ts +0 -73
- package/src/context.ts +0 -105
- package/src/db/__tests__/cascade-delete.test.ts +0 -182
- package/src/db/__tests__/desired-state.test.ts +0 -136
- package/src/db/__tests__/diff-engine.test.ts +0 -635
- package/src/db/__tests__/field-mapper.test.ts +0 -355
- package/src/db/__tests__/introspect.test.ts +0 -70
- package/src/db/__tests__/search-filter.test.ts +0 -45
- package/src/db/__tests__/sequence.test.ts +0 -221
- package/src/db/auto-sync.ts +0 -133
- package/src/db/client.ts +0 -147
- package/src/db/desired-state.ts +0 -98
- package/src/db/diff-engine.ts +0 -305
- package/src/db/field-mapper.ts +0 -504
- package/src/db/filter-applier.ts +0 -89
- package/src/db/include-resolver.ts +0 -40
- package/src/db/index.ts +0 -23
- package/src/db/introspect.ts +0 -265
- package/src/db/model-include-resolver.ts +0 -327
- package/src/db/model-ops.ts +0 -281
- package/src/db/scope-enforcer.ts +0 -37
- package/src/db/types.ts +0 -98
- package/src/errors.ts +0 -41
- package/src/events/__tests__/bus.test.ts +0 -105
- package/src/events/bus.ts +0 -89
- package/src/events/index.ts +0 -2
- package/src/events/types.ts +0 -9
- package/src/external-model/__tests__/computed-fields.test.ts +0 -106
- package/src/external-model/__tests__/field-mapper.test.ts +0 -160
- package/src/external-model/__tests__/in-memory-ops.test.ts +0 -247
- package/src/external-model/__tests__/mutation-executor.test.ts +0 -160
- package/src/external-model/__tests__/query-executor.test.ts +0 -284
- package/src/external-model/__tests__/schema-converter.test.ts +0 -174
- package/src/external-model/computed-fields.ts +0 -15
- package/src/external-model/define.ts +0 -5
- package/src/external-model/external-model-ops.ts +0 -108
- package/src/external-model/field-mapper.ts +0 -66
- package/src/external-model/in-memory-ops.ts +0 -107
- package/src/external-model/index.ts +0 -7
- package/src/external-model/mutation-executor.ts +0 -71
- package/src/external-model/query-executor.ts +0 -100
- package/src/external-model/schema-converter.ts +0 -53
- package/src/external-model/types.ts +0 -32
- package/src/fixtures/__tests__/fixtures.test.ts +0 -203
- package/src/fixtures/index.ts +0 -10
- package/src/fixtures/loader.ts +0 -196
- package/src/fixtures/registry.ts +0 -125
- package/src/fixtures/types.ts +0 -33
- package/src/helpers/assert-ownership.ts +0 -19
- package/src/helpers/coerce.ts +0 -28
- package/src/helpers/stamping.ts +0 -28
- package/src/helpers/validation.ts +0 -14
- package/src/hooks/__tests__/context.test.ts +0 -73
- package/src/hooks/__tests__/executor.test.ts +0 -433
- package/src/hooks/__tests__/middleware.test.ts +0 -224
- package/src/hooks/__tests__/registry.test.ts +0 -50
- package/src/hooks/context.ts +0 -89
- package/src/hooks/errors.ts +0 -11
- package/src/hooks/executor.ts +0 -115
- package/src/hooks/index.ts +0 -10
- package/src/hooks/middleware.ts +0 -220
- package/src/hooks/registry.ts +0 -20
- package/src/hooks/types.ts +0 -32
- package/src/index.ts +0 -172
- package/src/jobs/__tests__/enqueue.test.ts +0 -77
- package/src/jobs/__tests__/integration.test.ts +0 -71
- package/src/jobs/__tests__/registry.test.ts +0 -103
- package/src/jobs/__tests__/scheduler.test.ts +0 -92
- package/src/jobs/__tests__/worker-execution.test.ts +0 -202
- package/src/jobs/__tests__/worker.test.ts +0 -119
- package/src/jobs/enqueue.ts +0 -93
- package/src/jobs/index.ts +0 -14
- package/src/jobs/registry.ts +0 -92
- package/src/jobs/scheduler.ts +0 -205
- package/src/jobs/tables.ts +0 -132
- package/src/jobs/types.ts +0 -62
- package/src/jobs/worker.ts +0 -272
- package/src/model-api/__tests__/cross-boundary-includes.test.ts +0 -366
- package/src/model-api/__tests__/extended-api.test.ts +0 -244
- package/src/model-api/__tests__/filter-applier.test.ts +0 -177
- package/src/model-api/__tests__/filter-translator.test.ts +0 -186
- package/src/model-api/__tests__/include-resolver.test.ts +0 -226
- package/src/model-api/__tests__/model-access.test.ts +0 -284
- package/src/model-api/__tests__/query-builder.test.ts +0 -224
- package/src/model-api/__tests__/scope-enforcer.test.ts +0 -268
- package/src/model-api/field-access.ts +0 -28
- package/src/model-api/filter-applier.ts +0 -1
- package/src/model-api/filter-translator.ts +0 -67
- package/src/model-api/include-resolver.ts +0 -2
- package/src/model-api/index.ts +0 -86
- package/src/model-api/query-builder.ts +0 -155
- package/src/model-api/scope-enforcer.ts +0 -3
- package/src/model-api/types.ts +0 -139
- package/src/plugins/__tests__/adapter-registry.test.ts +0 -92
- package/src/plugins/__tests__/lifecycle.test.ts +0 -96
- package/src/plugins/__tests__/loader.test.ts +0 -273
- package/src/plugins/__tests__/validator.test.ts +0 -275
- package/src/plugins/adapter-registry.ts +0 -42
- package/src/plugins/define.ts +0 -5
- package/src/plugins/index.ts +0 -28
- package/src/plugins/lifecycle.ts +0 -27
- package/src/plugins/loader.ts +0 -126
- package/src/plugins/types.ts +0 -76
- package/src/plugins/validator.ts +0 -141
- package/src/schema/__tests__/registry-models-by-module.test.ts +0 -58
- package/src/schema/registry.ts +0 -93
- package/src/schema/relationships.ts +0 -93
- package/src/schema/types.ts +0 -43
- package/src/services/__tests__/integration.test.ts +0 -63
- package/src/services/__tests__/registry.test.ts +0 -175
- package/src/services/index.ts +0 -13
- package/src/services/registry.ts +0 -156
- package/src/services/types.ts +0 -27
- package/src/validation/__tests__/field-validator.test.ts +0 -195
- package/src/validation/field-validator.ts +0 -113
- package/src/validation/index.ts +0 -1
- package/src/widgets/index.ts +0 -3
- package/src/widgets/slot-validator.ts +0 -87
- package/src/widgets/widget-registry.ts +0 -32
- package/tests/boot.test.ts +0 -323
- package/tests/dependency-sort.test.ts +0 -99
- package/tests/discovery.test.ts +0 -126
- package/tests/registry.test.ts +0 -216
- package/tests/schema-loader.test.ts +0 -52
- package/tests/schema-merger.test.ts +0 -180
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -14
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import type { SchemaRegistry } from '../schema/registry.js';
|
|
2
|
-
import type { ResolvedModel } from '../schema/types.js';
|
|
3
|
-
import type { RequestContext } from '../auth/types.js';
|
|
4
|
-
import type {
|
|
5
|
-
FilterExpression,
|
|
6
|
-
IncludeResolver,
|
|
7
|
-
ModelOps,
|
|
8
|
-
ModelQuery,
|
|
9
|
-
QueryResult,
|
|
10
|
-
QueryResultWithMeta,
|
|
11
|
-
QueryState,
|
|
12
|
-
TranslatedFilter,
|
|
13
|
-
} from './types.js';
|
|
14
|
-
import { translateFilters } from './filter-translator.js';
|
|
15
|
-
|
|
16
|
-
export type { QueryState } from './types.js';
|
|
17
|
-
|
|
18
|
-
export class ModelQueryBuilder implements ModelQuery {
|
|
19
|
-
private readonly ops: ModelOps;
|
|
20
|
-
private readonly model: ResolvedModel;
|
|
21
|
-
private readonly registry: SchemaRegistry;
|
|
22
|
-
private readonly includeResolver?: IncludeResolver;
|
|
23
|
-
private readonly state: QueryState;
|
|
24
|
-
|
|
25
|
-
constructor(
|
|
26
|
-
ops: ModelOps,
|
|
27
|
-
model: ResolvedModel,
|
|
28
|
-
registry: SchemaRegistry,
|
|
29
|
-
includeResolver?: IncludeResolver,
|
|
30
|
-
state?: QueryState,
|
|
31
|
-
) {
|
|
32
|
-
this.ops = ops;
|
|
33
|
-
this.model = model;
|
|
34
|
-
this.registry = registry;
|
|
35
|
-
this.includeResolver = includeResolver;
|
|
36
|
-
this.state = state ?? {
|
|
37
|
-
filters: [],
|
|
38
|
-
sorts: [],
|
|
39
|
-
fieldNames: [],
|
|
40
|
-
includes: [],
|
|
41
|
-
unscopedFlag: false,
|
|
42
|
-
includeArchivedFlag: false,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private clone(patch: Partial<QueryState>): ModelQueryBuilder {
|
|
47
|
-
return new ModelQueryBuilder(this.ops, this.model, this.registry, this.includeResolver, {
|
|
48
|
-
...this.state,
|
|
49
|
-
...patch,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
filter(conditions: FilterExpression): ModelQueryBuilder {
|
|
54
|
-
const translated = translateFilters(conditions);
|
|
55
|
-
return this.clone({ filters: [...this.state.filters, ...translated] });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
filterRaw(filters: TranslatedFilter[]): ModelQueryBuilder {
|
|
59
|
-
return this.clone({ filters: [...this.state.filters, ...filters] });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
sort(field: string, direction: 'asc' | 'desc' = 'asc'): ModelQueryBuilder {
|
|
63
|
-
return this.clone({ sorts: [...this.state.sorts, { field, direction }] });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
limit(count: number): ModelQueryBuilder {
|
|
67
|
-
return this.clone({ limitVal: count });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
offset(count: number): ModelQueryBuilder {
|
|
71
|
-
return this.clone({ offsetVal: count });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
page(num: number): ModelQueryBuilder {
|
|
75
|
-
return this.clone({ pageVal: num });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
include(relation: string): ModelQueryBuilder {
|
|
79
|
-
if (this.state.includes.includes(relation)) return this;
|
|
80
|
-
return this.clone({ includes: [...this.state.includes, relation] });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
fields(fieldNames: string[]): ModelQueryBuilder {
|
|
84
|
-
return this.clone({ fieldNames });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
unscoped(): ModelQueryBuilder {
|
|
88
|
-
return this.clone({ unscopedFlag: true });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
includeArchived(): ModelQueryBuilder {
|
|
92
|
-
return this.clone({ includeArchivedFlag: true });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
search(term: string, fields: string[]): ModelQueryBuilder {
|
|
96
|
-
if (!term || fields.length === 0) return this;
|
|
97
|
-
return this.clone({ searchTerm: term, searchFields: fields });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
withAuth(auth: RequestContext): ModelQueryBuilder {
|
|
101
|
-
return this.clone({ auth });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
isUnscoped(): boolean {
|
|
105
|
-
return this.state.unscopedFlag;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
getIncludes(): string[] {
|
|
109
|
-
return this.state.includes;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
compile(): unknown {
|
|
113
|
-
return this.ops.compile?.(this.state) ?? this.state;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
compileCount(): unknown {
|
|
117
|
-
return this.ops.compileCount?.(this.state) ?? this.state;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async exec(): Promise<QueryResult> {
|
|
121
|
-
const result = await this.ops.find(this.state);
|
|
122
|
-
if (this.state.includes.length > 0 && this.includeResolver) {
|
|
123
|
-
await this.includeResolver.resolve(
|
|
124
|
-
result.data,
|
|
125
|
-
this.state.includes,
|
|
126
|
-
this.model.qualifiedName,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
return result;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async execWithMeta(): Promise<QueryResultWithMeta> {
|
|
133
|
-
const result = await this.ops.findWithMeta(this.state);
|
|
134
|
-
if (this.state.includes.length > 0 && this.includeResolver) {
|
|
135
|
-
await this.includeResolver.resolve(
|
|
136
|
-
result.data,
|
|
137
|
-
this.state.includes,
|
|
138
|
-
this.model.qualifiedName,
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async first(): Promise<Record<string, unknown> | null> {
|
|
145
|
-
const result = await this.ops.findOne(this.state);
|
|
146
|
-
if (result && this.state.includes.length > 0 && this.includeResolver) {
|
|
147
|
-
await this.includeResolver.resolve([result], this.state.includes, this.model.qualifiedName);
|
|
148
|
-
}
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async count(): Promise<number> {
|
|
153
|
-
return this.ops.count(this.state);
|
|
154
|
-
}
|
|
155
|
-
}
|
package/src/model-api/types.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
export interface FilterOperators {
|
|
2
|
-
eq?: unknown;
|
|
3
|
-
neq?: unknown;
|
|
4
|
-
gt?: unknown;
|
|
5
|
-
gte?: unknown;
|
|
6
|
-
lt?: unknown;
|
|
7
|
-
lte?: unknown;
|
|
8
|
-
in?: unknown[];
|
|
9
|
-
notIn?: unknown[];
|
|
10
|
-
contains?: string;
|
|
11
|
-
startsWith?: string;
|
|
12
|
-
endsWith?: string;
|
|
13
|
-
is?: null | 'not_null';
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type FilterValue = unknown | FilterOperators;
|
|
17
|
-
|
|
18
|
-
export type FilterExpression = Record<string, FilterValue>;
|
|
19
|
-
|
|
20
|
-
export interface PaginationMeta {
|
|
21
|
-
total: number;
|
|
22
|
-
page: number;
|
|
23
|
-
limit: number;
|
|
24
|
-
totalPages: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface QueryResult {
|
|
28
|
-
data: Record<string, unknown>[];
|
|
29
|
-
total?: number;
|
|
30
|
-
hasMore?: boolean;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface QueryResultWithMeta {
|
|
34
|
-
data: Record<string, unknown>[];
|
|
35
|
-
meta: PaginationMeta;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
import type { RequestContext } from '../auth/types.js';
|
|
39
|
-
|
|
40
|
-
export interface TranslatedFilter {
|
|
41
|
-
field: string;
|
|
42
|
-
operator: string;
|
|
43
|
-
value: unknown;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface QueryState {
|
|
47
|
-
filters: TranslatedFilter[];
|
|
48
|
-
sorts: Array<{ field: string; direction: 'asc' | 'desc' }>;
|
|
49
|
-
limitVal?: number;
|
|
50
|
-
offsetVal?: number;
|
|
51
|
-
pageVal?: number;
|
|
52
|
-
fieldNames: string[];
|
|
53
|
-
includes: string[];
|
|
54
|
-
unscopedFlag: boolean;
|
|
55
|
-
includeArchivedFlag: boolean;
|
|
56
|
-
auth?: RequestContext;
|
|
57
|
-
searchTerm?: string;
|
|
58
|
-
searchFields?: string[];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface ModelOps {
|
|
62
|
-
find(state: QueryState): Promise<QueryResult>;
|
|
63
|
-
findWithMeta(state: QueryState): Promise<QueryResultWithMeta>;
|
|
64
|
-
findOne(state: QueryState): Promise<Record<string, unknown> | null>;
|
|
65
|
-
count(state: QueryState): Promise<number>;
|
|
66
|
-
get(id: string): Promise<Record<string, unknown> | null>;
|
|
67
|
-
create(data: Record<string, unknown>, auth?: RequestContext): Promise<Record<string, unknown>>;
|
|
68
|
-
update(
|
|
69
|
-
id: string,
|
|
70
|
-
data: Record<string, unknown>,
|
|
71
|
-
auth?: RequestContext,
|
|
72
|
-
): Promise<Record<string, unknown>>;
|
|
73
|
-
delete(id: string, auth?: RequestContext): Promise<Record<string, unknown>>;
|
|
74
|
-
withTransaction?(trx: unknown): ModelOps;
|
|
75
|
-
compile?(state: QueryState): unknown;
|
|
76
|
-
compileCount?(state: QueryState): unknown;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface IncludeResolver {
|
|
80
|
-
resolve(
|
|
81
|
-
records: Record<string, unknown>[],
|
|
82
|
-
includes: string[],
|
|
83
|
-
sourceModel: string,
|
|
84
|
-
): Promise<void>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface ModelQuery {
|
|
88
|
-
filter(conditions: FilterExpression): ModelQuery;
|
|
89
|
-
filterRaw(filters: TranslatedFilter[]): ModelQuery;
|
|
90
|
-
sort(field: string, direction?: 'asc' | 'desc'): ModelQuery;
|
|
91
|
-
limit(count: number): ModelQuery;
|
|
92
|
-
offset(count: number): ModelQuery;
|
|
93
|
-
page(num: number): ModelQuery;
|
|
94
|
-
include(relation: string): ModelQuery;
|
|
95
|
-
fields(fieldNames: string[]): ModelQuery;
|
|
96
|
-
search(term: string, fields: string[]): ModelQuery;
|
|
97
|
-
unscoped(): ModelQuery;
|
|
98
|
-
includeArchived(): ModelQuery;
|
|
99
|
-
withAuth(auth: import('../auth/types.js').RequestContext): ModelQuery;
|
|
100
|
-
exec(): Promise<QueryResult>;
|
|
101
|
-
execWithMeta(): Promise<QueryResultWithMeta>;
|
|
102
|
-
first(): Promise<Record<string, unknown> | null>;
|
|
103
|
-
count(): Promise<number>;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface ModelAccess {
|
|
107
|
-
get(model: string, id: string): Promise<Record<string, unknown> | null>;
|
|
108
|
-
query(model: string): ModelQuery;
|
|
109
|
-
create(model: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
110
|
-
update(
|
|
111
|
-
model: string,
|
|
112
|
-
id: string,
|
|
113
|
-
data: Record<string, unknown>,
|
|
114
|
-
): Promise<Record<string, unknown>>;
|
|
115
|
-
delete(model: string, id: string): Promise<Record<string, unknown>>;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface ModelAccessOptions {
|
|
119
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
120
|
-
db: {
|
|
121
|
-
selectFrom(table: string): any;
|
|
122
|
-
insertInto(table: string): any;
|
|
123
|
-
updateTable(table: string): any;
|
|
124
|
-
deleteFrom(table: string): any;
|
|
125
|
-
};
|
|
126
|
-
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
127
|
-
registry: import('../schema/registry.js').SchemaRegistry;
|
|
128
|
-
hookRegistry?: import('../hooks/registry.js').HookRegistry;
|
|
129
|
-
auth?: import('../auth/types.js').RequestContext;
|
|
130
|
-
serviceRegistry?: import('../services/registry.js').ServiceRegistry;
|
|
131
|
-
eventBus?: import('../events/bus.js').EventBus;
|
|
132
|
-
config?: Record<string, unknown>;
|
|
133
|
-
adapterRegistry?: import('../plugins/adapter-registry.js').AdapterRegistry;
|
|
134
|
-
externalModelFields?: Record<
|
|
135
|
-
string,
|
|
136
|
-
Record<string, import('../external-model/types.js').ExternalFieldConfig>
|
|
137
|
-
>;
|
|
138
|
-
adapterCapabilities?: Record<string, import('../plugins/types.js').AdapterCapability[]>;
|
|
139
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
AdapterRegistry,
|
|
4
|
-
AdapterNotFoundError,
|
|
5
|
-
DuplicateAdapterError,
|
|
6
|
-
} from '../adapter-registry.js';
|
|
7
|
-
import type { DataAdapter } from '../types.js';
|
|
8
|
-
|
|
9
|
-
function makeAdapter(overrides?: Partial<DataAdapter>): DataAdapter {
|
|
10
|
-
return {
|
|
11
|
-
async get(_model: string, _id: string) {
|
|
12
|
-
return { id: '1' };
|
|
13
|
-
},
|
|
14
|
-
...overrides,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('AdapterRegistry', () => {
|
|
19
|
-
describe('register', () => {
|
|
20
|
-
it('registers an adapter', () => {
|
|
21
|
-
const registry = new AdapterRegistry();
|
|
22
|
-
const adapter = makeAdapter();
|
|
23
|
-
registry.register('stripe', adapter);
|
|
24
|
-
expect(registry.has('stripe')).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('throws DuplicateAdapterError on duplicate name', () => {
|
|
28
|
-
const registry = new AdapterRegistry();
|
|
29
|
-
registry.register('stripe', makeAdapter());
|
|
30
|
-
expect(() => registry.register('stripe', makeAdapter())).toThrow(DuplicateAdapterError);
|
|
31
|
-
expect(() => registry.register('stripe', makeAdapter())).toThrow(
|
|
32
|
-
'Adapter "stripe" is already registered',
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('allows different names', () => {
|
|
37
|
-
const registry = new AdapterRegistry();
|
|
38
|
-
registry.register('stripe', makeAdapter());
|
|
39
|
-
registry.register('hubspot', makeAdapter());
|
|
40
|
-
expect(registry.has('stripe')).toBe(true);
|
|
41
|
-
expect(registry.has('hubspot')).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe('get', () => {
|
|
46
|
-
it('returns the registered adapter', () => {
|
|
47
|
-
const registry = new AdapterRegistry();
|
|
48
|
-
const adapter = makeAdapter();
|
|
49
|
-
registry.register('stripe', adapter);
|
|
50
|
-
expect(registry.get('stripe')).toBe(adapter);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('throws AdapterNotFoundError for unknown name', () => {
|
|
54
|
-
const registry = new AdapterRegistry();
|
|
55
|
-
expect(() => registry.get('unknown')).toThrow(AdapterNotFoundError);
|
|
56
|
-
expect(() => registry.get('unknown')).toThrow('Adapter "unknown" is not registered');
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('has', () => {
|
|
61
|
-
it('returns false for unregistered adapter', () => {
|
|
62
|
-
const registry = new AdapterRegistry();
|
|
63
|
-
expect(registry.has('stripe')).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('returns true after registration', () => {
|
|
67
|
-
const registry = new AdapterRegistry();
|
|
68
|
-
registry.register('stripe', makeAdapter());
|
|
69
|
-
expect(registry.has('stripe')).toBe(true);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('getAll', () => {
|
|
74
|
-
it('returns empty array when no adapters registered', () => {
|
|
75
|
-
const registry = new AdapterRegistry();
|
|
76
|
-
expect(registry.getAll()).toEqual([]);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('returns all registered adapters with names', () => {
|
|
80
|
-
const registry = new AdapterRegistry();
|
|
81
|
-
const stripe = makeAdapter();
|
|
82
|
-
const hubspot = makeAdapter();
|
|
83
|
-
registry.register('stripe', stripe);
|
|
84
|
-
registry.register('hubspot', hubspot);
|
|
85
|
-
|
|
86
|
-
const all = registry.getAll();
|
|
87
|
-
expect(all).toHaveLength(2);
|
|
88
|
-
expect(all).toContainEqual({ name: 'stripe', adapter: stripe });
|
|
89
|
-
expect(all).toContainEqual({ name: 'hubspot', adapter: hubspot });
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { PluginLifecycleManager } from '../lifecycle.js';
|
|
3
|
-
import type { PluginLifecycleEvent } from '../types.js';
|
|
4
|
-
|
|
5
|
-
describe('PluginLifecycleManager', () => {
|
|
6
|
-
describe('register and emit', () => {
|
|
7
|
-
it('calls registered handler on emit', async () => {
|
|
8
|
-
const manager = new PluginLifecycleManager();
|
|
9
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
10
|
-
manager.register('afterBoot', handler);
|
|
11
|
-
|
|
12
|
-
await manager.emit('afterBoot');
|
|
13
|
-
expect(handler).toHaveBeenCalledOnce();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('passes arguments to handler', async () => {
|
|
17
|
-
const manager = new PluginLifecycleManager();
|
|
18
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
19
|
-
manager.register('beforeRequest', handler);
|
|
20
|
-
|
|
21
|
-
await manager.emit('beforeRequest', { url: '/api/test' });
|
|
22
|
-
expect(handler).toHaveBeenCalledWith({ url: '/api/test' });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('calls multiple handlers in registration order', async () => {
|
|
26
|
-
const manager = new PluginLifecycleManager();
|
|
27
|
-
const order: number[] = [];
|
|
28
|
-
|
|
29
|
-
manager.register('afterBoot', async () => {
|
|
30
|
-
order.push(1);
|
|
31
|
-
});
|
|
32
|
-
manager.register('afterBoot', async () => {
|
|
33
|
-
order.push(2);
|
|
34
|
-
});
|
|
35
|
-
manager.register('afterBoot', async () => {
|
|
36
|
-
order.push(3);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
await manager.emit('afterBoot');
|
|
40
|
-
expect(order).toEqual([1, 2, 3]);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('does nothing when no handlers for event', async () => {
|
|
44
|
-
const manager = new PluginLifecycleManager();
|
|
45
|
-
await expect(manager.emit('beforeShutdown')).resolves.toBeUndefined();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('supports all lifecycle events', async () => {
|
|
49
|
-
const manager = new PluginLifecycleManager();
|
|
50
|
-
const events: PluginLifecycleEvent[] = [
|
|
51
|
-
'beforeBoot',
|
|
52
|
-
'afterBoot',
|
|
53
|
-
'beforeRequest',
|
|
54
|
-
'afterRequest',
|
|
55
|
-
'beforeShutdown',
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
for (const event of events) {
|
|
59
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
60
|
-
manager.register(event, handler);
|
|
61
|
-
await manager.emit(event);
|
|
62
|
-
expect(handler).toHaveBeenCalledOnce();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('awaits async handlers sequentially', async () => {
|
|
67
|
-
const manager = new PluginLifecycleManager();
|
|
68
|
-
const order: number[] = [];
|
|
69
|
-
|
|
70
|
-
manager.register('afterBoot', async () => {
|
|
71
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
72
|
-
order.push(1);
|
|
73
|
-
});
|
|
74
|
-
manager.register('afterBoot', async () => {
|
|
75
|
-
order.push(2);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
await manager.emit('afterBoot');
|
|
79
|
-
expect(order).toEqual([1, 2]);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('getHandlers', () => {
|
|
84
|
-
it('returns empty array for unregistered event', () => {
|
|
85
|
-
const manager = new PluginLifecycleManager();
|
|
86
|
-
expect(manager.getHandlers('beforeBoot')).toEqual([]);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('returns registered handlers', () => {
|
|
90
|
-
const manager = new PluginLifecycleManager();
|
|
91
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
92
|
-
manager.register('afterBoot', handler);
|
|
93
|
-
expect(manager.getHandlers('afterBoot')).toEqual([handler]);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
});
|