@declaro/core 2.0.0-beta.9 → 2.0.0-beta.90
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/{LICENSE → LICENSE.md} +1 -1
- package/README.md +203 -0
- package/dist/browser/index.js +34 -0
- package/dist/browser/index.js.map +123 -0
- package/dist/browser/scope/index.js +4 -0
- package/dist/browser/scope/index.js.map +9 -0
- package/dist/node/index.cjs +17329 -0
- package/dist/node/index.cjs.map +123 -0
- package/dist/node/index.js +17303 -0
- package/dist/node/index.js.map +123 -0
- package/dist/node/scope/index.cjs +48 -0
- package/dist/node/scope/index.cjs.map +9 -0
- package/dist/node/scope/index.js +29 -0
- package/dist/node/scope/index.js.map +9 -0
- package/dist/ts/app/app-context.d.ts +9 -0
- package/dist/ts/app/app-context.d.ts.map +1 -0
- package/dist/ts/app/app-lifecycle.d.ts +6 -0
- package/dist/ts/app/app-lifecycle.d.ts.map +1 -0
- package/dist/ts/app/app.d.ts +24 -0
- package/dist/ts/app/app.d.ts.map +1 -0
- package/dist/ts/app/index.d.ts +4 -0
- package/dist/ts/app/index.d.ts.map +1 -0
- package/dist/ts/application/create-request-context.d.ts +4 -0
- package/dist/ts/application/create-request-context.d.ts.map +1 -0
- package/dist/ts/application/create-request-context.test.d.ts +2 -0
- package/dist/ts/application/create-request-context.test.d.ts.map +1 -0
- package/dist/ts/application/use-declaro.d.ts +3 -0
- package/dist/ts/application/use-declaro.d.ts.map +1 -0
- package/dist/ts/auth/permission-validator.d.ts +35 -0
- package/dist/ts/auth/permission-validator.d.ts.map +1 -0
- package/dist/ts/auth/permission-validator.test.d.ts +2 -0
- package/dist/ts/auth/permission-validator.test.d.ts.map +1 -0
- package/dist/{context → ts/context}/context-consumer.d.ts +4 -0
- package/dist/ts/context/context-consumer.d.ts.map +1 -0
- package/dist/ts/context/context.d.ts +193 -0
- package/dist/ts/context/context.d.ts.map +1 -0
- package/dist/ts/context/context.test.d.ts +2 -0
- package/dist/ts/context/context.test.d.ts.map +1 -0
- package/dist/ts/context/legacy-context.test.d.ts +2 -0
- package/dist/ts/context/legacy-context.test.d.ts.map +1 -0
- package/dist/{context → ts/context}/validators.d.ts +2 -1
- package/dist/ts/context/validators.d.ts.map +1 -0
- package/dist/ts/dataflow/index.d.ts +2 -0
- package/dist/ts/dataflow/index.d.ts.map +1 -0
- package/dist/ts/dataflow/objects.d.ts +7 -0
- package/dist/ts/dataflow/objects.d.ts.map +1 -0
- package/dist/ts/dataflow/objects.test.d.ts +2 -0
- package/dist/ts/dataflow/objects.test.d.ts.map +1 -0
- package/dist/ts/errors/errors.d.ts +49 -0
- package/dist/ts/errors/errors.d.ts.map +1 -0
- package/dist/ts/events/event-manager.d.ts +19 -0
- package/dist/ts/events/event-manager.d.ts.map +1 -0
- package/dist/ts/events/event-manager.spec.d.ts +2 -0
- package/dist/ts/events/event-manager.spec.d.ts.map +1 -0
- package/dist/ts/events/index.d.ts +2 -0
- package/dist/ts/events/index.d.ts.map +1 -0
- package/dist/ts/http/headers.d.ts +21 -0
- package/dist/ts/http/headers.d.ts.map +1 -0
- package/dist/ts/http/headers.spec.d.ts +2 -0
- package/dist/ts/http/headers.spec.d.ts.map +1 -0
- package/dist/ts/http/request-context.d.ts +17 -0
- package/dist/ts/http/request-context.d.ts.map +1 -0
- package/dist/ts/http/request-context.spec.d.ts +2 -0
- package/dist/ts/http/request-context.spec.d.ts.map +1 -0
- package/dist/ts/http/request.d.ts +31 -0
- package/dist/ts/http/request.d.ts.map +1 -0
- package/dist/ts/http/request.spec.d.ts +2 -0
- package/dist/ts/http/request.spec.d.ts.map +1 -0
- package/dist/ts/http/url.d.ts +9 -0
- package/dist/ts/http/url.d.ts.map +1 -0
- package/dist/ts/http/url.spec.d.ts +2 -0
- package/dist/ts/http/url.spec.d.ts.map +1 -0
- package/dist/ts/index.d.ts +45 -0
- package/dist/ts/index.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/index.d.ts +1 -0
- package/dist/ts/pipelines/index.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/pipeline-action.d.ts +1 -0
- package/dist/ts/pipelines/pipeline-action.d.ts.map +1 -0
- package/dist/ts/pipelines/pipeline-action.test.d.ts +2 -0
- package/dist/ts/pipelines/pipeline-action.test.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/pipeline.d.ts +3 -2
- package/dist/ts/pipelines/pipeline.d.ts.map +1 -0
- package/dist/ts/pipelines/pipeline.test.d.ts +2 -0
- package/dist/ts/pipelines/pipeline.test.d.ts.map +1 -0
- package/dist/ts/schema/entity-schema.test.d.ts +1 -0
- package/dist/ts/schema/entity-schema.test.d.ts.map +1 -0
- package/dist/ts/schema/json-schema.d.ts +4 -0
- package/dist/ts/schema/json-schema.d.ts.map +1 -0
- package/dist/ts/schema/labels.d.ts +14 -0
- package/dist/ts/schema/labels.d.ts.map +1 -0
- package/dist/ts/schema/model-schema.d.ts +75 -0
- package/dist/ts/schema/model-schema.d.ts.map +1 -0
- package/dist/ts/schema/model-schema.test.d.ts +2 -0
- package/dist/ts/schema/model-schema.test.d.ts.map +1 -0
- package/dist/ts/schema/model.d.ts +30 -0
- package/dist/ts/schema/model.d.ts.map +1 -0
- package/dist/ts/schema/schema-mixin.d.ts +24 -0
- package/dist/ts/schema/schema-mixin.d.ts.map +1 -0
- package/dist/ts/schema/test/mock-model.d.ts +8 -0
- package/dist/ts/schema/test/mock-model.d.ts.map +1 -0
- package/dist/ts/scope/index.d.ts +34 -0
- package/dist/ts/scope/index.d.ts.map +1 -0
- package/dist/ts/shared/utils/action-descriptor.d.ts +28 -0
- package/dist/ts/shared/utils/action-descriptor.d.ts.map +1 -0
- package/dist/ts/shared/utils/action-descriptor.test.d.ts +2 -0
- package/dist/ts/shared/utils/action-descriptor.test.d.ts.map +1 -0
- package/dist/{timing.d.ts → ts/timing.d.ts} +1 -0
- package/dist/ts/timing.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/arrays.d.ts +1 -0
- package/dist/ts/typescript/arrays.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/baseModel.d.ts +1 -0
- package/dist/ts/typescript/baseModel.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/classes.d.ts +1 -0
- package/dist/ts/typescript/classes.d.ts.map +1 -0
- package/dist/ts/typescript/constant-manipulation/snake-case.d.ts +23 -0
- package/dist/ts/typescript/constant-manipulation/snake-case.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/errors.d.ts +1 -0
- package/dist/ts/typescript/errors.d.ts.map +1 -0
- package/dist/ts/typescript/fetch.d.ts +3 -0
- package/dist/ts/typescript/fetch.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/generics.d.ts +1 -0
- package/dist/ts/typescript/generics.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/index.d.ts +2 -0
- package/dist/ts/typescript/index.d.ts.map +1 -0
- package/dist/ts/typescript/objects.d.ts +26 -0
- package/dist/ts/typescript/objects.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/promises.d.ts +1 -0
- package/dist/ts/typescript/promises.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/index.d.ts +1 -0
- package/dist/ts/validation/index.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/validation.d.ts +1 -0
- package/dist/ts/validation/validation.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/validator.d.ts +1 -0
- package/dist/ts/validation/validator.d.ts.map +1 -0
- package/dist/ts/validation/validator.test.d.ts +2 -0
- package/dist/ts/validation/validator.test.d.ts.map +1 -0
- package/package.json +44 -14
- package/src/app/app-context.ts +13 -0
- package/src/app/app-lifecycle.ts +15 -0
- package/src/app/app.ts +47 -0
- package/src/app/index.ts +3 -34
- package/src/application/create-request-context.test.ts +351 -0
- package/src/application/create-request-context.ts +19 -0
- package/src/application/use-declaro.ts +19 -0
- package/src/auth/permission-validator.test.ts +445 -0
- package/src/auth/permission-validator.ts +135 -0
- package/src/context/context-consumer.ts +4 -4
- package/src/context/context.test.ts +851 -93
- package/src/context/context.ts +414 -33
- package/src/context/legacy-context.test.ts +141 -0
- package/src/dataflow/objects.test.ts +7 -7
- package/src/dataflow/objects.ts +10 -9
- package/src/errors/errors.ts +89 -0
- package/src/events/event-manager.spec.ts +183 -8
- package/src/events/event-manager.ts +58 -31
- package/src/http/headers.spec.ts +48 -0
- package/src/http/headers.ts +31 -0
- package/src/http/request-context.spec.ts +39 -0
- package/src/http/request-context.ts +54 -0
- package/src/http/request.spec.ts +52 -0
- package/src/http/request.ts +43 -0
- package/src/http/url.spec.ts +87 -0
- package/src/http/url.ts +48 -0
- package/src/index.ts +41 -6
- package/src/pipelines/pipeline.test.ts +11 -9
- package/src/schema/entity-schema.test.ts +0 -0
- package/src/schema/json-schema.ts +3 -0
- package/src/schema/labels.ts +30 -0
- package/src/schema/model-schema.test.ts +128 -0
- package/src/schema/model-schema.ts +197 -0
- package/src/schema/model.ts +112 -0
- package/src/schema/schema-mixin.ts +51 -0
- package/src/schema/test/mock-model.ts +15 -0
- package/src/scope/index.ts +33 -0
- package/src/shared/utils/action-descriptor.test.ts +182 -0
- package/src/shared/utils/action-descriptor.ts +102 -0
- package/src/typescript/constant-manipulation/snake-case.md +496 -0
- package/src/typescript/constant-manipulation/snake-case.ts +76 -0
- package/src/typescript/index.ts +1 -0
- package/src/typescript/objects.ts +39 -5
- package/src/validation/validator.test.ts +12 -20
- package/dist/app/index.d.ts +0 -20
- package/dist/context/context.d.ts +0 -86
- package/dist/context/context.test.d.ts +0 -1
- package/dist/context/index.d.ts +0 -3
- package/dist/dataflow/index.d.ts +0 -1
- package/dist/dataflow/objects.d.ts +0 -5
- package/dist/dataflow/objects.test.d.ts +0 -1
- package/dist/events/event-manager.d.ts +0 -11
- package/dist/events/event-manager.spec.d.ts +0 -1
- package/dist/events/index.d.ts +0 -1
- package/dist/helpers/index.d.ts +0 -1
- package/dist/helpers/ucfirst.d.ts +0 -1
- package/dist/index.d.ts +0 -13
- package/dist/interfaces/IDatastoreProvider.d.ts +0 -16
- package/dist/interfaces/IStore.d.ts +0 -4
- package/dist/interfaces/index.d.ts +0 -2
- package/dist/pipelines/pipeline-action.test.d.ts +0 -1
- package/dist/pipelines/pipeline.test.d.ts +0 -1
- package/dist/pkg.cjs +0 -2
- package/dist/pkg.mjs +0 -358
- package/dist/schema/define-model.d.ts +0 -7
- package/dist/schema/define-model.test.d.ts +0 -1
- package/dist/schema/formats.d.ts +0 -10
- package/dist/schema/index.d.ts +0 -3
- package/dist/schema/supported-types.d.ts +0 -12
- package/dist/schema/supported-types.test.d.ts +0 -1
- package/dist/schema/transform-model.d.ts +0 -4
- package/dist/schema/transform-model.test.d.ts +0 -1
- package/dist/schema/types.d.ts +0 -29
- package/dist/server/index.d.ts +0 -2
- package/dist/typescript/fetch.d.ts +0 -2
- package/dist/typescript/objects.d.ts +0 -6
- package/dist/validation/validator.test.d.ts +0 -1
- package/src/context/index.ts +0 -3
- package/src/helpers/index.ts +0 -1
- package/src/helpers/ucfirst.ts +0 -3
- package/src/interfaces/IDatastoreProvider.ts +0 -23
- package/src/interfaces/IStore.ts +0 -4
- package/src/interfaces/index.ts +0 -2
- package/src/schema/define-model.test.ts +0 -35
- package/src/schema/define-model.ts +0 -19
- package/src/schema/formats.ts +0 -23
- package/src/schema/index.ts +0 -3
- package/src/schema/supported-types.test.ts +0 -20
- package/src/schema/supported-types.ts +0 -15
- package/src/schema/transform-model.test.ts +0 -31
- package/src/schema/transform-model.ts +0 -24
- package/src/schema/types.ts +0 -43
- package/src/server/index.ts +0 -3
- package/tsconfig.json +0 -8
- package/vite.config.ts +0 -24
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Context } from '../context/context'
|
|
2
|
+
import { createRequest } from 'node-mocks-http'
|
|
3
|
+
import { provideRequest, useRequest, useRequestMethod } from './request'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
describe('Http Request', () => {
|
|
7
|
+
it('Should get undefined by default', () => {
|
|
8
|
+
const context = new Context()
|
|
9
|
+
|
|
10
|
+
const request = useRequest(context)
|
|
11
|
+
|
|
12
|
+
expect(request).toBeUndefined()
|
|
13
|
+
})
|
|
14
|
+
it('Should provide a request', () => {
|
|
15
|
+
const context = new Context()
|
|
16
|
+
|
|
17
|
+
const request = createRequest({
|
|
18
|
+
method: 'GET',
|
|
19
|
+
url: '/test',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
'X-Test': 'test',
|
|
23
|
+
Authorization: 'Bearer 123',
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
provideRequest(context, request)
|
|
28
|
+
|
|
29
|
+
const request2 = useRequest(context)
|
|
30
|
+
|
|
31
|
+
expect(request2).toEqual(request)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('Should get the method', () => {
|
|
35
|
+
const context = new Context()
|
|
36
|
+
|
|
37
|
+
const request = createRequest({
|
|
38
|
+
method: 'GET',
|
|
39
|
+
url: '/test',
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
'X-Test': 'test',
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
provideRequest(context, request)
|
|
47
|
+
|
|
48
|
+
const method = useRequestMethod(context)
|
|
49
|
+
|
|
50
|
+
expect(method).toEqual('GET')
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'http'
|
|
2
|
+
import { Context, type DeclaroRequestScope } from '../context/context'
|
|
3
|
+
|
|
4
|
+
export interface Request extends IncomingMessage {}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Provide a request to a context that supports request scope.
|
|
8
|
+
* The context must have all properties required by DeclaroRequestScope.
|
|
9
|
+
*
|
|
10
|
+
* @param context A context that includes DeclaroRequestScope properties
|
|
11
|
+
* @param request The request to provide
|
|
12
|
+
*/
|
|
13
|
+
export function provideRequest<S extends DeclaroRequestScope>(context: Context<S>, request: Request) {
|
|
14
|
+
context.registerValue('request', request)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get the request from the context.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated You can now inject the request directly from Context<RequestScope>.
|
|
21
|
+
* This function will be removed in a future version.
|
|
22
|
+
* @param context The context to use for the request.
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
export function useRequest(context: Context) {
|
|
26
|
+
const request = context.resolve('request')
|
|
27
|
+
|
|
28
|
+
return request
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the HTTP method of the request.
|
|
33
|
+
*
|
|
34
|
+
* @deprecated You can now inject the request directly from Context<RequestScope>.
|
|
35
|
+
* This function will be removed in a future version.
|
|
36
|
+
* @param context The context to use for the request.
|
|
37
|
+
* @returns The HTTP method of the request, or undefined if not available.
|
|
38
|
+
*/
|
|
39
|
+
export function useRequestMethod(context: Context) {
|
|
40
|
+
const request = useRequest(context)
|
|
41
|
+
|
|
42
|
+
return request?.method
|
|
43
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Tests for url.ts:
|
|
2
|
+
// Create tests for the following functions:
|
|
3
|
+
// - useURL: make sure it returns undefined by default, and the URL object if provided
|
|
4
|
+
// - provideURL: make sure you can provide a URL object or a string
|
|
5
|
+
// - useURLString: make sure it returns the stringified URL
|
|
6
|
+
// - useURLDomain: make sure it returns the domain part of the URL provided
|
|
7
|
+
// - useURLPath
|
|
8
|
+
|
|
9
|
+
import { Context } from '../context/context'
|
|
10
|
+
import { useRequestDomain, useRequestPath, useRequestQuery, useRequestURL, useRequestURLString } from './url'
|
|
11
|
+
import { provideRequest } from './request'
|
|
12
|
+
import { createRequest } from 'node-mocks-http'
|
|
13
|
+
import { describe, expect, it } from 'vitest'
|
|
14
|
+
|
|
15
|
+
// - useURLQueryString
|
|
16
|
+
describe('Http URL', () => {
|
|
17
|
+
const testUrlString = 'https://example.com/test?a=1&b=2'
|
|
18
|
+
const testUrlObject = new URL(testUrlString)
|
|
19
|
+
const request = createRequest({
|
|
20
|
+
method: 'GET',
|
|
21
|
+
url: testUrlString,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
'X-Test': 'test',
|
|
25
|
+
Authorization: 'Bearer 123',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('Should get undefined by default', () => {
|
|
30
|
+
const context = new Context()
|
|
31
|
+
|
|
32
|
+
const url = useRequestURL(context)
|
|
33
|
+
|
|
34
|
+
expect(url).toBeUndefined()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('Should get the URL object if provided', () => {
|
|
38
|
+
const context = new Context()
|
|
39
|
+
|
|
40
|
+
provideRequest(context, request)
|
|
41
|
+
|
|
42
|
+
const url2 = useRequestURL(context)
|
|
43
|
+
|
|
44
|
+
expect(url2).toEqual(testUrlObject)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('Should get the stringified URL', () => {
|
|
48
|
+
const context = new Context()
|
|
49
|
+
|
|
50
|
+
provideRequest(context, request)
|
|
51
|
+
|
|
52
|
+
const url2 = useRequestURLString(context)
|
|
53
|
+
|
|
54
|
+
expect(url2).toEqual(testUrlString)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('Should get the domain part of the URL', () => {
|
|
58
|
+
const context = new Context()
|
|
59
|
+
|
|
60
|
+
provideRequest(context, request)
|
|
61
|
+
|
|
62
|
+
const domain = useRequestDomain(context)
|
|
63
|
+
|
|
64
|
+
expect(domain).toEqual('example.com')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('Should get the path part of the URL', () => {
|
|
68
|
+
const context = new Context()
|
|
69
|
+
|
|
70
|
+
provideRequest(context, request)
|
|
71
|
+
|
|
72
|
+
const path = useRequestPath(context)
|
|
73
|
+
|
|
74
|
+
expect(path).toEqual('/test')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('Should get the query string part of the URL', () => {
|
|
78
|
+
const context = new Context()
|
|
79
|
+
|
|
80
|
+
provideRequest(context, request)
|
|
81
|
+
|
|
82
|
+
const query = useRequestQuery(context)
|
|
83
|
+
|
|
84
|
+
expect(query['a']).toEqual('1')
|
|
85
|
+
expect(query['b']).toEqual('2')
|
|
86
|
+
})
|
|
87
|
+
})
|
package/src/http/url.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Context } from '../context/context'
|
|
2
|
+
import { URL } from 'whatwg-url'
|
|
3
|
+
import { useRequest } from './request'
|
|
4
|
+
|
|
5
|
+
export function useRequestURL(context: Context): URL | undefined {
|
|
6
|
+
const request = useRequest(context)
|
|
7
|
+
const url = request?.url && new URL(request?.url)
|
|
8
|
+
|
|
9
|
+
return url as URL
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useRequestURLString(context: Context) {
|
|
13
|
+
const url = useRequestURL(context)
|
|
14
|
+
|
|
15
|
+
return url?.toString()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function useRequestDomain(context: Context) {
|
|
19
|
+
const url = useRequestURL(context)
|
|
20
|
+
|
|
21
|
+
return url?.hostname
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useRequestPath(context: Context) {
|
|
25
|
+
const url = useRequestURL(context)
|
|
26
|
+
|
|
27
|
+
return url?.pathname
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useRequestQuery(context: Context): Record<string, string> {
|
|
31
|
+
const url = useRequestURL(context)
|
|
32
|
+
|
|
33
|
+
const qs = url?.searchParams
|
|
34
|
+
|
|
35
|
+
// convert qs to an object of key value pairs
|
|
36
|
+
const qsMap = [...(qs?.entries() as any)].reduce((qsMap, [key, value]) => {
|
|
37
|
+
qsMap[key] = value
|
|
38
|
+
return qsMap
|
|
39
|
+
}, {} as Record<string, string>)
|
|
40
|
+
|
|
41
|
+
return qsMap
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function useFormattedQueryParam(context: Context, key: string) {
|
|
45
|
+
const qs = useRequestQuery(context)
|
|
46
|
+
|
|
47
|
+
const value = qs[key]
|
|
48
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Import AppScope from '#scope' instead.
|
|
4
|
+
*
|
|
5
|
+
* Migration: Change `import { AppScope } from '@declaro/core'` to `import { AppScope } from '#scope'`
|
|
6
|
+
*
|
|
7
|
+
* The #scope import allows for better type augmentation and module resolution.
|
|
8
|
+
*/
|
|
9
|
+
AppScope,
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Import RequestScope from '#scope' instead.
|
|
12
|
+
*
|
|
13
|
+
* Migration: Change `import { RequestScope } from '@declaro/core'` to `import { RequestScope } from '#scope'`
|
|
14
|
+
*
|
|
15
|
+
* The #scope import allows for better type augmentation and module resolution.
|
|
16
|
+
*/
|
|
17
|
+
RequestScope,
|
|
18
|
+
} from '#scope'
|
|
19
|
+
|
|
20
|
+
export * from '@standard-schema/spec'
|
|
21
|
+
|
|
1
22
|
export * from './typescript'
|
|
2
23
|
export * from './app'
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
24
|
+
export * from './application/create-request-context'
|
|
25
|
+
export * from './application/use-declaro'
|
|
26
|
+
export * from './context/context'
|
|
27
|
+
export * from './context/context-consumer'
|
|
28
|
+
export * from './context/validators'
|
|
5
29
|
export * from './dataflow'
|
|
6
30
|
export * from './events'
|
|
7
31
|
export * from './validation'
|
|
8
32
|
export * from './timing'
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './interfaces'
|
|
12
|
-
export * from './schema/formats'
|
|
33
|
+
export * from './scope'
|
|
34
|
+
export * from './errors/errors'
|
|
13
35
|
export * from './pipelines'
|
|
36
|
+
export * from './http/headers'
|
|
37
|
+
export * from './http/request-context'
|
|
38
|
+
export * from './http/request'
|
|
39
|
+
export * from './http/url'
|
|
40
|
+
export * from './auth/permission-validator'
|
|
41
|
+
export * from './schema/model'
|
|
42
|
+
export * from './schema/json-schema'
|
|
43
|
+
export * from './schema/labels'
|
|
44
|
+
export * from './schema/model-schema'
|
|
45
|
+
export * from './schema/schema-mixin'
|
|
46
|
+
export * from './schema/test/mock-model'
|
|
47
|
+
|
|
48
|
+
export * from './shared/utils/action-descriptor'
|
|
@@ -94,14 +94,16 @@ describe('Pipelines', () => {
|
|
|
94
94
|
number,
|
|
95
95
|
}),
|
|
96
96
|
)
|
|
97
|
-
const message = vi.fn((meta
|
|
98
|
-
meta
|
|
97
|
+
const message = vi.fn((meta: Meta | string): string =>
|
|
98
|
+
typeof meta === 'string'
|
|
99
|
+
? meta
|
|
100
|
+
: meta?.positive
|
|
99
101
|
? `${meta.number} is positive`
|
|
100
|
-
: meta
|
|
102
|
+
: meta?.negative
|
|
101
103
|
? `${meta.number} is negative`
|
|
102
|
-
: meta
|
|
103
|
-
? `${meta
|
|
104
|
-
: `${meta
|
|
104
|
+
: meta?.zero
|
|
105
|
+
? `${meta?.number} is zero`
|
|
106
|
+
: `${meta?.number} is not a number`,
|
|
105
107
|
)
|
|
106
108
|
|
|
107
109
|
const originalPipeline = new Pipeline(initialInput<number>()).pipe(meta)
|
|
@@ -165,11 +167,11 @@ describe('Pipelines', () => {
|
|
|
165
167
|
|
|
166
168
|
return meta?.positive
|
|
167
169
|
? `${meta.number} is positive`
|
|
168
|
-
: meta
|
|
170
|
+
: meta?.negative
|
|
169
171
|
? `${meta.number} is negative`
|
|
170
|
-
: meta
|
|
172
|
+
: meta?.zero
|
|
171
173
|
? `${meta.number} is zero`
|
|
172
|
-
: `${meta
|
|
174
|
+
: `${meta?.number} is not a number`
|
|
173
175
|
})
|
|
174
176
|
|
|
175
177
|
const originalPipeline = new Pipeline(initialInput<number>()).pipe(meta)
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { capitalCase, camelCase, kebabCase, pascalCase, sentenceCase } from 'change-case'
|
|
2
|
+
import pluralize from 'pluralize'
|
|
3
|
+
|
|
4
|
+
export type ModelLabels = {
|
|
5
|
+
singularLabel: string
|
|
6
|
+
pluralLabel: string
|
|
7
|
+
singularSentence: string
|
|
8
|
+
pluralSentence: string
|
|
9
|
+
singularParameter: string
|
|
10
|
+
pluralParameter: string
|
|
11
|
+
singularSlug: string
|
|
12
|
+
pluralSlug: string
|
|
13
|
+
singularEntityName: string
|
|
14
|
+
pluralEntityName: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getLabels(modelName: string, labels: Partial<ModelLabels> = {}): ModelLabels {
|
|
18
|
+
return {
|
|
19
|
+
singularLabel: capitalCase(pluralize(labels.singularLabel ?? modelName, 1)),
|
|
20
|
+
pluralLabel: capitalCase(pluralize(labels.pluralLabel ?? modelName, 10)),
|
|
21
|
+
singularSentence: sentenceCase(pluralize(labels.singularLabel ?? modelName, 1)),
|
|
22
|
+
pluralSentence: sentenceCase(pluralize(labels.pluralLabel ?? modelName, 10)),
|
|
23
|
+
singularParameter: camelCase(pluralize(labels.singularParameter ?? modelName, 1)),
|
|
24
|
+
pluralParameter: camelCase(pluralize(labels.pluralParameter ?? modelName, 10)),
|
|
25
|
+
singularSlug: kebabCase(pluralize(labels.singularSlug ?? modelName, 1)),
|
|
26
|
+
pluralSlug: kebabCase(pluralize(labels.pluralSlug ?? modelName, 10)),
|
|
27
|
+
singularEntityName: pascalCase(pluralize(labels.singularEntityName ?? modelName, 1)),
|
|
28
|
+
pluralEntityName: pascalCase(pluralize(labels.pluralEntityName ?? modelName, 10)),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { z } from 'zod/v4'
|
|
3
|
+
import { ModelSchema, type MergeMixins } from './model-schema'
|
|
4
|
+
import { MockModel } from './test/mock-model'
|
|
5
|
+
import type { InferModelOutput } from './model'
|
|
6
|
+
import type { ShallowMerge, UniqueKeys } from '../typescript'
|
|
7
|
+
|
|
8
|
+
describe('ModelSchema', () => {
|
|
9
|
+
it('should create a ModelSchema instance', () => {
|
|
10
|
+
const schema = ModelSchema.create('TestModel')
|
|
11
|
+
expect(schema).toBeInstanceOf(ModelSchema)
|
|
12
|
+
expect(schema.name).toBe('TestModel')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should support read definitions with MixinFactory', () => {
|
|
16
|
+
const schema = ModelSchema.create('Book').read({
|
|
17
|
+
detail: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
18
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
expect(schema.definition.detail).toBeInstanceOf(MockModel)
|
|
22
|
+
expect(schema.definition.lookup).toBeInstanceOf(MockModel)
|
|
23
|
+
|
|
24
|
+
const X = {} as any as InferModelOutput<(typeof schema)['definition']['lookup']>
|
|
25
|
+
|
|
26
|
+
expect(schema.definition.detail.name).toBe('BookDetail')
|
|
27
|
+
expect(schema.definition.lookup.name).toBe('BookLookup')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should support search definitions with MixinFactory', () => {
|
|
31
|
+
const schema = ModelSchema.create('Book').search({
|
|
32
|
+
filters: (h) =>
|
|
33
|
+
new MockModel(h.name, z.object({ title: z.string().optional(), author: z.string().optional() })),
|
|
34
|
+
summary: (h) => new MockModel(h.name, z.object({ id: z.string(), title: z.string() })),
|
|
35
|
+
sort: (h) =>
|
|
36
|
+
new MockModel(h.name, z.object({ title: z.enum(['asc', 'desc']), author: z.enum(['asc', 'desc']) })),
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(schema.definition.filters).toBeInstanceOf(MockModel)
|
|
40
|
+
expect(schema.definition.summary).toBeInstanceOf(MockModel)
|
|
41
|
+
expect(schema.definition.filters.name).toBe('BookFilters')
|
|
42
|
+
expect(schema.definition.summary.name).toBe('BookSummary')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should support write definitions with MixinFactory', () => {
|
|
46
|
+
const schema = ModelSchema.create('Book').write({
|
|
47
|
+
input: (h) => new MockModel(h.name, z.object({ title: z.string(), author: z.string() })),
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
expect(schema.definition.input).toBeInstanceOf(MockModel)
|
|
51
|
+
expect(schema.definition.input.name).toBe('BookInput')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should define a primary key', () => {
|
|
55
|
+
const schema = ModelSchema.create('Book')
|
|
56
|
+
.read({
|
|
57
|
+
detail: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
58
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
59
|
+
})
|
|
60
|
+
.write({
|
|
61
|
+
input: (h) => new MockModel(h.name, z.object({ id: z.string(), title: z.string() })),
|
|
62
|
+
})
|
|
63
|
+
.entity({
|
|
64
|
+
primaryKey: 'id',
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
expect(schema.getEntityMetadata().primaryKey).toBe('id')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should allow redefinition of types', () => {
|
|
71
|
+
const schema = ModelSchema.create('Book')
|
|
72
|
+
.read({
|
|
73
|
+
detail: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
74
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
75
|
+
})
|
|
76
|
+
.write({
|
|
77
|
+
input: (h) => new MockModel(h.name, z.object({ id: z.string(), title: z.string() })),
|
|
78
|
+
})
|
|
79
|
+
.entity({
|
|
80
|
+
primaryKey: 'id',
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const redefinedSchema = schema.read({
|
|
84
|
+
detail: (h) =>
|
|
85
|
+
new MockModel(
|
|
86
|
+
h.name,
|
|
87
|
+
z.object({ id: z.number(), name: z.string().optional(), age: z.number().optional() }),
|
|
88
|
+
),
|
|
89
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.number() })),
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const patchedSchema = redefinedSchema.custom({
|
|
93
|
+
detail: () =>
|
|
94
|
+
new MockModel(
|
|
95
|
+
'BookDetail',
|
|
96
|
+
z.object({ id: z.string(), name: z.string(), foo: z.string(), bar: z.string() }),
|
|
97
|
+
),
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const detailSchema = redefinedSchema.definition.detail.toJSONSchema()
|
|
101
|
+
const patchedDetailSchema = patchedSchema.definition.detail.toJSONSchema()
|
|
102
|
+
|
|
103
|
+
expect(redefinedSchema.definition.detail).toBeInstanceOf(MockModel)
|
|
104
|
+
expect(Object.keys(detailSchema.properties ?? {})).toEqual(['id', 'name', 'age'])
|
|
105
|
+
|
|
106
|
+
expect(Object.keys(patchedDetailSchema.properties ?? {})).toEqual(['id', 'name', 'foo', 'bar'])
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should be able to redefine schema without changes to the primary key', () => {
|
|
110
|
+
const schema = ModelSchema.create('Book')
|
|
111
|
+
.read({
|
|
112
|
+
detail: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
113
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
114
|
+
})
|
|
115
|
+
.write({
|
|
116
|
+
input: (h) => new MockModel(h.name, z.object({ id: z.string(), title: z.string() })),
|
|
117
|
+
})
|
|
118
|
+
.entity({
|
|
119
|
+
primaryKey: 'id',
|
|
120
|
+
})
|
|
121
|
+
.read({
|
|
122
|
+
detail: (h) => new MockModel(h.name, z.object({ uuid: z.string(), name: z.string() })),
|
|
123
|
+
lookup: (h) => new MockModel(h.name, z.object({ uuid: z.string(), name: z.string() })),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
expect(schema.getEntityMetadata().primaryKey).toBe('id')
|
|
127
|
+
})
|
|
128
|
+
})
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { merge } from '../dataflow'
|
|
2
|
+
import type { Merge, ShallowMerge } from '../typescript'
|
|
3
|
+
import { getLabels, type ModelLabels } from './labels'
|
|
4
|
+
import { type InferModelInput } from './model'
|
|
5
|
+
import {
|
|
6
|
+
buildMixin,
|
|
7
|
+
defineMixin,
|
|
8
|
+
type IAnyMixin,
|
|
9
|
+
type IMixin,
|
|
10
|
+
type IMixinHelper,
|
|
11
|
+
type IMixinHelpers,
|
|
12
|
+
type IMixinInput,
|
|
13
|
+
type InferMixinInput,
|
|
14
|
+
} from './schema-mixin'
|
|
15
|
+
import { MockModel } from './test/mock-model'
|
|
16
|
+
import { z } from 'zod/v4'
|
|
17
|
+
|
|
18
|
+
export type Subset<T> = {
|
|
19
|
+
[K in keyof T]?: T[K]
|
|
20
|
+
}
|
|
21
|
+
export type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
|
22
|
+
|
|
23
|
+
export type MergeMixins<TA extends IAnyMixin | undefined, TB extends IAnyMixin> = Simplify<
|
|
24
|
+
TA extends IAnyMixin ? ShallowMerge<TA, TB> : TB
|
|
25
|
+
>
|
|
26
|
+
|
|
27
|
+
export function getReadHelpers<TName extends Readonly<string>>(h: IMixinHelper<TName>) {
|
|
28
|
+
return {
|
|
29
|
+
detail: { name: h.name },
|
|
30
|
+
lookup: { name: `${h.name}Lookup` as const },
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const readMixin = defineMixin((h) => ({
|
|
35
|
+
detail: {
|
|
36
|
+
name: `${h.name}Detail` as const,
|
|
37
|
+
},
|
|
38
|
+
lookup: {
|
|
39
|
+
name: `${h.name}Lookup` as const,
|
|
40
|
+
},
|
|
41
|
+
}))
|
|
42
|
+
export type ReadMixin<TName extends Readonly<string>> = ReturnType<typeof readMixin<TName>>
|
|
43
|
+
|
|
44
|
+
const defaultMixin = defineMixin((h) => ({}))
|
|
45
|
+
export type DefaultMixin<TName extends Readonly<string>> = ReturnType<typeof defaultMixin<TName>>
|
|
46
|
+
|
|
47
|
+
const searchMixin = defineMixin((h) => ({
|
|
48
|
+
summary: { name: `${h.name}Summary` as const },
|
|
49
|
+
filters: { name: `${h.name}Filters` as const },
|
|
50
|
+
sort: { name: `${h.name}Sort` as const },
|
|
51
|
+
}))
|
|
52
|
+
export type SearchMixin<TName extends Readonly<string>> = ReturnType<typeof searchMixin<TName>>
|
|
53
|
+
|
|
54
|
+
const writeMixin = defineMixin((h) => ({
|
|
55
|
+
input: { name: `${h.name}Input` as const },
|
|
56
|
+
}))
|
|
57
|
+
export type WriteMixin<TName extends Readonly<string>> = ReturnType<typeof writeMixin<TName>>
|
|
58
|
+
|
|
59
|
+
export type IModelNames<T extends object> = {
|
|
60
|
+
[K in keyof T]: Readonly<string>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type InferPKeyBaseType<T extends IAnyMixin | undefined> = T extends IAnyMixin
|
|
64
|
+
? T['lookup'] extends object
|
|
65
|
+
? keyof InferModelInput<T['lookup']> | undefined
|
|
66
|
+
: undefined
|
|
67
|
+
: undefined
|
|
68
|
+
|
|
69
|
+
export interface IModelEntityMetadata {
|
|
70
|
+
primaryKey: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class ModelSchema<
|
|
74
|
+
TName extends Readonly<string> = Readonly<string>,
|
|
75
|
+
T extends IAnyMixin | undefined = undefined,
|
|
76
|
+
TEntityMeta extends IModelEntityMetadata | undefined = undefined,
|
|
77
|
+
> {
|
|
78
|
+
static create<TName extends Readonly<string>>(name: TName): ModelSchema<TName> {
|
|
79
|
+
return new ModelSchema(name)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public readonly definition: Simplify<T>
|
|
83
|
+
public readonly name: TName
|
|
84
|
+
protected readonly entityMetadata: TEntityMeta
|
|
85
|
+
|
|
86
|
+
constructor(name: TName, definition: T = {} as T, entityMetadata?: TEntityMeta) {
|
|
87
|
+
this.definition = definition
|
|
88
|
+
this.name = name
|
|
89
|
+
this.entityMetadata = entityMetadata!
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get labels(): ModelLabels {
|
|
93
|
+
return getLabels(this.name)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get helper(): IMixinHelper<TName> {
|
|
97
|
+
return {
|
|
98
|
+
name: this.name,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
custom<TInput extends IMixinInput>(input: TInput): ModelSchema<TName, MergeMixins<T, IMixin<TInput>>, TEntityMeta> {
|
|
103
|
+
const helpers: IMixinHelpers<TInput> = Object.keys(input).reduce((acc: any, key) => {
|
|
104
|
+
const helper = this.helper
|
|
105
|
+
acc[key] = helper
|
|
106
|
+
return acc
|
|
107
|
+
}, {} as IMixinHelpers<TInput>)
|
|
108
|
+
const definition = buildMixin(helpers, input as any)
|
|
109
|
+
|
|
110
|
+
return new ModelSchema(
|
|
111
|
+
this.name,
|
|
112
|
+
{
|
|
113
|
+
...this.definition,
|
|
114
|
+
...definition,
|
|
115
|
+
},
|
|
116
|
+
this.entityMetadata,
|
|
117
|
+
) as any
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
read<TInput extends InferMixinInput<ReadMixin<TName>>>(
|
|
121
|
+
input: TInput,
|
|
122
|
+
): ModelSchema<TName, MergeMixins<T, IMixin<TInput>>, TEntityMeta> {
|
|
123
|
+
const helpers = readMixin(this.helper)
|
|
124
|
+
const definition = buildMixin(helpers, input)
|
|
125
|
+
|
|
126
|
+
return new ModelSchema(
|
|
127
|
+
this.name,
|
|
128
|
+
{
|
|
129
|
+
...this.definition,
|
|
130
|
+
...definition,
|
|
131
|
+
},
|
|
132
|
+
this.entityMetadata,
|
|
133
|
+
) as any
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
search<TInput extends InferMixinInput<SearchMixin<TName>>>(
|
|
137
|
+
input: TInput,
|
|
138
|
+
): ModelSchema<TName, MergeMixins<T, IMixin<TInput>>> {
|
|
139
|
+
const helpers = searchMixin(this.helper)
|
|
140
|
+
const definition = buildMixin(helpers, input)
|
|
141
|
+
|
|
142
|
+
return new ModelSchema(
|
|
143
|
+
this.name,
|
|
144
|
+
{
|
|
145
|
+
...this.definition,
|
|
146
|
+
...definition,
|
|
147
|
+
},
|
|
148
|
+
this.entityMetadata,
|
|
149
|
+
) as any
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
write<TInput extends InferMixinInput<WriteMixin<TName>>>(
|
|
153
|
+
input: TInput,
|
|
154
|
+
): ModelSchema<TName, MergeMixins<T, IMixin<TInput>>> {
|
|
155
|
+
const helpers = writeMixin(this.helper)
|
|
156
|
+
const definition = buildMixin(helpers, input)
|
|
157
|
+
|
|
158
|
+
return new ModelSchema(
|
|
159
|
+
this.name,
|
|
160
|
+
{
|
|
161
|
+
...this.definition,
|
|
162
|
+
...definition,
|
|
163
|
+
},
|
|
164
|
+
this.entityMetadata,
|
|
165
|
+
) as any
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
entity<
|
|
169
|
+
TEntityMeta extends {
|
|
170
|
+
primaryKey: InferPKeyBaseType<T>
|
|
171
|
+
},
|
|
172
|
+
>(meta: TEntityMeta): ModelSchema<TName, T, TEntityMeta extends IModelEntityMetadata ? TEntityMeta : undefined> {
|
|
173
|
+
const lookupMeta = this.definition?.['lookup']?.toJSONSchema()
|
|
174
|
+
const lookupKeys = Object.keys(lookupMeta?.properties ?? {})
|
|
175
|
+
|
|
176
|
+
const metaIsValid = meta && typeof meta.primaryKey === 'string' && lookupKeys.includes(meta.primaryKey)
|
|
177
|
+
return new ModelSchema<TName, T, TEntityMeta extends IModelEntityMetadata ? TEntityMeta : undefined>(
|
|
178
|
+
this.name,
|
|
179
|
+
this.definition,
|
|
180
|
+
metaIsValid ? (meta as any) : undefined,
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getEntityMetadata(): TEntityMeta {
|
|
185
|
+
return this.entityMetadata
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export type AnyModelSchema = ModelSchema<any, any, any>
|
|
190
|
+
|
|
191
|
+
const test = ModelSchema.create('Test').read({
|
|
192
|
+
detail: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
193
|
+
lookup: (h) => new MockModel(h.name, z.object({ id: z.string(), name: z.string() })),
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const d = test.definition
|
|
197
|
+
const l = {} as any as keyof InferModelInput<typeof test.definition.lookup>
|