nitro-graphql 2.0.0-beta.70 → 2.0.0-beta.73
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 +1 -1
- package/dist/cli/adapter.d.mts +0 -3
- package/dist/cli/adapter.mjs +7 -32
- package/dist/cli/commands/build.d.mts +2 -2
- package/dist/cli/commands/build.mjs +1 -3
- package/dist/cli/commands/dev.d.mts +2 -2
- package/dist/cli/commands/dev.mjs +1 -3
- package/dist/cli/commands/generate.mjs +10 -10
- package/dist/cli/commands/init.mjs +4 -4
- package/dist/cli/commands/validate.mjs +1 -3
- package/dist/cli/completions.mjs +1 -3
- package/dist/cli/config.d.mts +4 -5
- package/dist/cli/config.mjs +4 -3
- package/dist/cli/index.d.mts +3 -6
- package/dist/cli/index.mjs +2 -4
- package/dist/cli/server/debug-handler.mjs +2 -5
- package/dist/cli/server/dev-server.mjs +1 -3
- package/dist/cli/server/graphql-handler.mjs +3 -4
- package/dist/cli/server/health-handler.mjs +1 -2
- package/dist/cli/server/loader.mjs +1 -3
- package/dist/cli/server/sandbox-handler.mjs +1 -3
- package/dist/cli/server/watcher.mjs +2 -4
- package/dist/cli/server/ws-handler.mjs +1 -3
- package/dist/config.mjs +1 -2
- package/dist/core/codegen/client.d.mts +4 -27
- package/dist/core/codegen/client.mjs +26 -447
- package/dist/core/codegen/document-loader.mjs +1 -3
- package/dist/core/codegen/file-header.d.mts +7 -0
- package/dist/core/codegen/file-header.mjs +12 -0
- package/dist/core/codegen/index.d.mts +7 -5
- package/dist/core/codegen/index.mjs +7 -6
- package/dist/core/codegen/{runtime.d.mts → runtime-generator.d.mts} +1 -3
- package/dist/core/codegen/{runtime.mjs → runtime-generator.mjs} +7 -6
- package/dist/core/codegen/schema-loader.d.mts +2 -7
- package/dist/core/codegen/schema-loader.mjs +66 -73
- package/dist/core/codegen/server-type-helpers.d.mts +14 -0
- package/dist/core/codegen/server-type-helpers.mjs +76 -0
- package/dist/core/codegen/server.d.mts +1 -15
- package/dist/core/codegen/server.mjs +15 -107
- package/dist/core/codegen/subscription-extractor.d.mts +20 -0
- package/dist/core/codegen/subscription-extractor.mjs +30 -0
- package/dist/core/codegen/validation.mjs +1 -3
- package/dist/core/codegen/vue-subscription-builder.d.mts +10 -0
- package/dist/core/codegen/vue-subscription-builder.mjs +351 -0
- package/dist/core/constants.d.mts +5 -53
- package/dist/core/constants.mjs +13 -56
- package/dist/core/create-config.d.mts +31 -0
- package/dist/core/create-config.mjs +42 -0
- package/dist/core/debug/index.d.mts +2 -2
- package/dist/core/debug/index.mjs +2 -3
- package/dist/core/debug/template.d.mts +1 -5
- package/dist/core/debug/template.mjs +5 -4
- package/dist/core/extend/index.mjs +1 -2
- package/dist/core/extend/loader.d.mts +0 -1
- package/dist/core/extend/loader.mjs +60 -92
- package/dist/core/index.d.mts +22 -21
- package/dist/core/index.mjs +19 -16
- package/dist/core/manifest.mjs +4 -4
- package/dist/core/pubsub/index.d.mts +2 -109
- package/dist/core/pubsub/index.mjs +2 -148
- package/dist/core/pubsub/memory-pubsub.d.mts +109 -0
- package/dist/core/pubsub/memory-pubsub.mjs +146 -0
- package/dist/core/scanning/ast-scanner.mjs +5 -5
- package/dist/core/scanning/directives.mjs +3 -5
- package/dist/core/scanning/documents.d.mts +4 -3
- package/dist/core/scanning/documents.mjs +4 -5
- package/dist/core/scanning/{common.d.mts → file-scanner.d.mts} +1 -1
- package/dist/core/scanning/{common.mjs → file-scanner.mjs} +3 -13
- package/dist/core/scanning/index.d.mts +3 -3
- package/dist/core/scanning/index.mjs +3 -4
- package/dist/core/scanning/resolvers.mjs +9 -11
- package/dist/core/scanning/schemas.d.mts +1 -5
- package/dist/core/scanning/schemas.mjs +2 -26
- package/dist/core/schema/builder.d.mts +4 -2
- package/dist/core/schema/builder.mjs +4 -4
- package/dist/core/schema/federation.mjs +1 -3
- package/dist/core/schema/index.d.mts +2 -2
- package/dist/core/schema/index.mjs +2 -3
- package/dist/core/server/apollo.d.mts +20 -0
- package/dist/core/server/apollo.mjs +54 -0
- package/dist/core/server/index.d.mts +4 -2
- package/dist/core/server/index.mjs +3 -3
- package/dist/core/server/sandbox.mjs +1 -2
- package/dist/core/server/types.d.mts +7 -14
- package/dist/core/server/types.mjs +15 -1
- package/dist/core/server/yoga.d.mts +1 -7
- package/dist/core/server/yoga.mjs +4 -15
- package/dist/core/types/adapter.d.mts +3 -40
- package/dist/core/types/adapter.mjs +1 -1
- package/dist/core/types/codegen.d.mts +22 -45
- package/dist/core/types/codegen.mjs +1 -1
- package/dist/core/types/config.d.mts +33 -121
- package/dist/core/types/config.mjs +1 -1
- package/dist/core/types/define.d.mts +8 -5
- package/dist/core/types/define.mjs +1 -1
- package/dist/core/types/index.d.mts +5 -4
- package/dist/core/types/index.mjs +1 -1
- package/dist/core/types/scanning.d.mts +4 -1
- package/dist/core/types/scanning.mjs +1 -1
- package/dist/core/types/standard-schema.d.mts +64 -0
- package/dist/core/types/standard-schema.mjs +1 -0
- package/dist/core/utils/directive-parser.d.mts +8 -63
- package/dist/core/utils/directive-parser.mjs +114 -167
- package/dist/core/utils/errors.mjs +1 -3
- package/dist/core/utils/file-io.d.mts +1 -5
- package/dist/core/utils/file-io.mjs +1 -13
- package/dist/core/utils/imports.mjs +3 -4
- package/dist/core/utils/index.d.mts +5 -4
- package/dist/core/utils/index.mjs +6 -6
- package/dist/core/utils/logger.d.mts +1 -10
- package/dist/core/utils/logger.mjs +1 -21
- package/dist/core/utils/ofetch-templates.mjs +4 -6
- package/dist/core/utils/runtime.d.mts +1 -30
- package/dist/core/utils/runtime.mjs +2 -46
- package/dist/core/utils/string.d.mts +10 -0
- package/dist/core/utils/string.mjs +12 -0
- package/dist/core/utils/subscribe-templates.mjs +1 -2
- package/dist/core/validation/external-services.mjs +3 -3
- package/dist/core/validation/index.mjs +1 -2
- package/dist/core/watcher/create-watcher.d.mts +103 -0
- package/dist/core/watcher/create-watcher.mjs +143 -0
- package/dist/core/watcher/index.d.mts +2 -107
- package/dist/core/watcher/index.mjs +2 -141
- package/dist/define.d.mts +4 -2
- package/dist/define.mjs +8 -9
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +3 -4
- package/dist/nitro/adapter.d.mts +6 -11
- package/dist/nitro/adapter.mjs +12 -45
- package/dist/nitro/apollo.mjs +1 -3
- package/dist/nitro/codegen/client-types.d.mts +12 -0
- package/dist/nitro/codegen/client-types.mjs +73 -0
- package/dist/nitro/codegen/external-types.d.mts +8 -0
- package/dist/nitro/codegen/external-types.mjs +47 -0
- package/dist/nitro/codegen/index.d.mts +4 -0
- package/dist/nitro/codegen/index.mjs +4 -0
- package/dist/nitro/codegen/server-types.d.mts +12 -0
- package/dist/nitro/codegen/server-types.mjs +81 -0
- package/dist/nitro/defaults.d.mts +28 -0
- package/dist/nitro/defaults.mjs +34 -0
- package/dist/nitro/index.d.mts +11 -3
- package/dist/nitro/index.mjs +4 -6
- package/dist/nitro/paths.d.mts +3 -2
- package/dist/nitro/paths.mjs +14 -5
- package/dist/nitro/rollup.mjs +8 -8
- package/dist/nitro/routes/_ws-handler.d.mts +6 -0
- package/dist/nitro/routes/_ws-handler.mjs +49 -0
- package/dist/nitro/routes/apollo-sandbox-script.d.mts +2 -2
- package/dist/nitro/routes/apollo-sandbox-script.mjs +1 -3
- package/dist/nitro/routes/apollo-server-ws.d.mts +1 -1
- package/dist/nitro/routes/apollo-server-ws.mjs +10 -48
- package/dist/nitro/routes/apollo-server.d.mts +2 -2
- package/dist/nitro/routes/apollo-server.mjs +17 -58
- package/dist/nitro/routes/debug.d.mts +2 -2
- package/dist/nitro/routes/debug.mjs +4 -7
- package/dist/nitro/routes/graphql-yoga-ws.d.mts +3 -3
- package/dist/nitro/routes/graphql-yoga-ws.mjs +7 -48
- package/dist/nitro/routes/graphql-yoga.d.mts +2 -2
- package/dist/nitro/routes/graphql-yoga.mjs +8 -8
- package/dist/nitro/routes/health.d.mts +2 -2
- package/dist/nitro/routes/health.mjs +23 -27
- package/dist/nitro/setup/extend-loader.d.mts +6 -5
- package/dist/nitro/setup/extend-loader.mjs +31 -61
- package/dist/nitro/setup/file-watcher.mjs +9 -8
- package/dist/nitro/setup/logging.d.mts +1 -8
- package/dist/nitro/setup/logging.mjs +7 -24
- package/dist/nitro/setup/rollup-integration.mjs +36 -4
- package/dist/nitro/setup/routes.mjs +1 -3
- package/dist/nitro/setup/scanner.d.mts +8 -43
- package/dist/nitro/setup/scanner.mjs +56 -60
- package/dist/nitro/setup/security.d.mts +10 -0
- package/dist/nitro/setup/security.mjs +17 -0
- package/dist/nitro/setup/ts-config.mjs +1 -3
- package/dist/nitro/setup/type-generation.d.mts +13 -0
- package/dist/nitro/setup/type-generation.mjs +16 -0
- package/dist/nitro/setup.d.mts +4 -3
- package/dist/nitro/setup.mjs +88 -77
- package/dist/nitro/state.d.mts +32 -0
- package/dist/nitro/state.mjs +58 -0
- package/dist/nitro/types/augmentation.d.mts +59 -0
- package/dist/nitro/types/augmentation.mjs +1 -0
- package/dist/nitro/types/config.d.mts +327 -0
- package/dist/nitro/types/config.mjs +1 -0
- package/dist/nitro/types/define.d.mts +13 -0
- package/dist/nitro/types/define.mjs +1 -0
- package/dist/nitro/types/index.d.mts +10 -0
- package/dist/nitro/types/index.mjs +1 -0
- package/dist/nitro/virtual/debug-info.d.mts +9 -0
- package/dist/nitro/virtual/debug-info.mjs +35 -0
- package/dist/nitro/virtual/graphql-config.d.mts +9 -0
- package/dist/nitro/virtual/graphql-config.mjs +33 -0
- package/dist/nitro/virtual/index.d.mts +25 -0
- package/dist/nitro/virtual/index.mjs +45 -0
- package/dist/nitro/virtual/module-config.d.mts +9 -0
- package/dist/nitro/virtual/module-config.mjs +10 -0
- package/dist/nitro/virtual/pubsub.d.mts +9 -0
- package/dist/nitro/virtual/pubsub.mjs +17 -0
- package/dist/nitro/virtual/server-directives.d.mts +9 -0
- package/dist/nitro/virtual/server-directives.mjs +12 -0
- package/dist/nitro/virtual/server-resolvers.d.mts +9 -0
- package/dist/nitro/virtual/server-resolvers.mjs +17 -0
- package/dist/nitro/virtual/server-schemas.d.mts +9 -0
- package/dist/nitro/virtual/server-schemas.mjs +31 -0
- package/dist/nitro/virtual/stubs.d.mts +42 -10
- package/dist/nitro/virtual/stubs.mjs +1 -7
- package/dist/nitro/virtual/utils.d.mts +15 -0
- package/dist/nitro/virtual/utils.mjs +26 -0
- package/dist/nitro/virtual/validation-schemas.d.mts +9 -0
- package/dist/nitro/virtual/validation-schemas.mjs +33 -0
- package/dist/nuxt.mjs +4 -5
- package/dist/stubs/index.mjs +1 -1
- package/dist/subscribe/index.mjs +3 -4
- package/native/index.js +52 -52
- package/package.json +41 -41
- package/dist/cli/commands/index.d.mts +0 -5
- package/dist/cli/commands/index.mjs +0 -6
- package/dist/core/codegen/plugin.d.mts +0 -19
- package/dist/core/codegen/plugin.mjs +0 -30
- package/dist/core/config.d.mts +0 -45
- package/dist/core/config.mjs +0 -78
- package/dist/nitro/codegen.d.mts +0 -18
- package/dist/nitro/codegen.mjs +0 -173
- package/dist/nitro/config.d.mts +0 -50
- package/dist/nitro/config.mjs +0 -57
- package/dist/nitro/types.d.mts +0 -549
- package/dist/nitro/types.mjs +0 -1
- package/dist/nitro/virtual/generators.d.mts +0 -38
- package/dist/nitro/virtual/generators.mjs +0 -192
|
@@ -1,148 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/core/pubsub/index.ts
|
|
4
|
-
/**
|
|
5
|
-
* Built-in PubSub implementation for GraphQL Subscriptions
|
|
6
|
-
* Simple EventEmitter-based implementation for single-instance deployments
|
|
7
|
-
*
|
|
8
|
-
* For multi-instance deployments, use external PubSub solutions like:
|
|
9
|
-
* - Redis (with ioredis)
|
|
10
|
-
* - Kafka
|
|
11
|
-
* - RabbitMQ
|
|
12
|
-
* - Cloud Pub/Sub services
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Create a simple in-memory PubSub instance
|
|
16
|
-
*
|
|
17
|
-
* This implementation uses EventEmitter for lightweight pub/sub functionality.
|
|
18
|
-
* Suitable for:
|
|
19
|
-
* - Development environments
|
|
20
|
-
* - Single-instance production deployments
|
|
21
|
-
* - Testing
|
|
22
|
-
*
|
|
23
|
-
* NOT suitable for:
|
|
24
|
-
* - Multi-instance/clustered deployments (events won't propagate across instances)
|
|
25
|
-
* - High-throughput scenarios (consider Redis-based PubSub)
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* // Define your topic types
|
|
30
|
-
* interface MyTopics {
|
|
31
|
-
* 'user:created': { id: string; name: string }
|
|
32
|
-
* 'message:sent': { channelId: string; content: string }
|
|
33
|
-
* }
|
|
34
|
-
*
|
|
35
|
-
* // Create typed PubSub instance
|
|
36
|
-
* const pubsub = createPubSub<MyTopics>()
|
|
37
|
-
*
|
|
38
|
-
* // Publish events
|
|
39
|
-
* await pubsub.publish('user:created', { id: '123', name: 'John' })
|
|
40
|
-
*
|
|
41
|
-
* // Subscribe to events (in a resolver)
|
|
42
|
-
* export const userSubscriptions = defineSubscription({
|
|
43
|
-
* userCreated: {
|
|
44
|
-
* subscribe: async function* () {
|
|
45
|
-
* yield* pubsub.subscribe('user:created')
|
|
46
|
-
* }
|
|
47
|
-
* }
|
|
48
|
-
* })
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
function createPubSub() {
|
|
52
|
-
const emitter = new EventEmitter();
|
|
53
|
-
emitter.setMaxListeners(0);
|
|
54
|
-
return {
|
|
55
|
-
async publish(topic, payload) {
|
|
56
|
-
emitter.emit(String(topic), payload);
|
|
57
|
-
},
|
|
58
|
-
subscribe(topic) {
|
|
59
|
-
const topicStr = String(topic);
|
|
60
|
-
return { [Symbol.asyncIterator]() {
|
|
61
|
-
const queue = [];
|
|
62
|
-
let resolve = null;
|
|
63
|
-
let done = false;
|
|
64
|
-
const listener = (payload) => {
|
|
65
|
-
if (resolve) {
|
|
66
|
-
resolve({
|
|
67
|
-
value: payload,
|
|
68
|
-
done: false
|
|
69
|
-
});
|
|
70
|
-
resolve = null;
|
|
71
|
-
} else queue.push(payload);
|
|
72
|
-
};
|
|
73
|
-
emitter.on(topicStr, listener);
|
|
74
|
-
return {
|
|
75
|
-
next() {
|
|
76
|
-
if (done) return Promise.resolve({
|
|
77
|
-
value: void 0,
|
|
78
|
-
done: true
|
|
79
|
-
});
|
|
80
|
-
if (queue.length > 0) return Promise.resolve({
|
|
81
|
-
value: queue.shift(),
|
|
82
|
-
done: false
|
|
83
|
-
});
|
|
84
|
-
return new Promise((r) => {
|
|
85
|
-
resolve = r;
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
return() {
|
|
89
|
-
done = true;
|
|
90
|
-
emitter.off(topicStr, listener);
|
|
91
|
-
return Promise.resolve({
|
|
92
|
-
value: void 0,
|
|
93
|
-
done: true
|
|
94
|
-
});
|
|
95
|
-
},
|
|
96
|
-
throw(error) {
|
|
97
|
-
done = true;
|
|
98
|
-
emitter.off(topicStr, listener);
|
|
99
|
-
return Promise.reject(error);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
} };
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Filter subscription events based on a predicate
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```typescript
|
|
111
|
-
* export const chatSubscriptions = defineSubscription({
|
|
112
|
-
* messageAdded: {
|
|
113
|
-
* subscribe: async function* (_, { channelId }) {
|
|
114
|
-
* yield* withFilter(
|
|
115
|
-
* pubsub.subscribe('message:added'),
|
|
116
|
-
* (message) => message.channelId === channelId
|
|
117
|
-
* )
|
|
118
|
-
* }
|
|
119
|
-
* }
|
|
120
|
-
* })
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
async function* withFilter(asyncIterable, filter) {
|
|
124
|
-
for await (const value of asyncIterable) if (await filter(value)) yield value;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Map subscription events to a different shape
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```typescript
|
|
131
|
-
* export const chatSubscriptions = defineSubscription({
|
|
132
|
-
* messageAdded: {
|
|
133
|
-
* subscribe: async function* () {
|
|
134
|
-
* yield* mapAsyncIterator(
|
|
135
|
-
* pubsub.subscribe('message:added'),
|
|
136
|
-
* (event) => ({ messageAdded: event.message })
|
|
137
|
-
* )
|
|
138
|
-
* }
|
|
139
|
-
* }
|
|
140
|
-
* })
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
async function* mapAsyncIterator(asyncIterable, mapper) {
|
|
144
|
-
for await (const value of asyncIterable) yield await mapper(value);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
//#endregion
|
|
148
|
-
export { createPubSub, mapAsyncIterator, withFilter };
|
|
1
|
+
import { createPubSub, mapAsyncIterator, withFilter } from "./memory-pubsub.mjs";
|
|
2
|
+
export { createPubSub, mapAsyncIterator, withFilter };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
//#region src/core/pubsub/memory-pubsub.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Built-in PubSub implementation for GraphQL Subscriptions
|
|
4
|
+
* Simple EventEmitter-based implementation for single-instance deployments
|
|
5
|
+
*
|
|
6
|
+
* For multi-instance deployments, use external PubSub solutions like:
|
|
7
|
+
* - Redis (with ioredis)
|
|
8
|
+
* - Kafka
|
|
9
|
+
* - RabbitMQ
|
|
10
|
+
* - Cloud Pub/Sub services
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Generic PubSub engine interface
|
|
14
|
+
* Compatible with various PubSub implementations
|
|
15
|
+
*/
|
|
16
|
+
interface PubSubEngine<Topics extends Record<string, unknown> = Record<string, unknown>> {
|
|
17
|
+
/**
|
|
18
|
+
* Publish an event to a topic
|
|
19
|
+
* @param topic - Topic name to publish to
|
|
20
|
+
* @param payload - Event payload
|
|
21
|
+
*/
|
|
22
|
+
publish: <K extends keyof Topics>(topic: K, payload: Topics[K]) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Subscribe to a topic
|
|
25
|
+
* @param topic - Topic name to subscribe to
|
|
26
|
+
* @returns AsyncIterable that yields events
|
|
27
|
+
*/
|
|
28
|
+
subscribe: <K extends keyof Topics>(topic: K) => AsyncIterable<Topics[K]>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Type alias for typed PubSub instances
|
|
32
|
+
*/
|
|
33
|
+
type TypedPubSub<Topics extends Record<string, unknown>> = PubSubEngine<Topics>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a simple in-memory PubSub instance
|
|
36
|
+
*
|
|
37
|
+
* This implementation uses EventEmitter for lightweight pub/sub functionality.
|
|
38
|
+
* Suitable for:
|
|
39
|
+
* - Development environments
|
|
40
|
+
* - Single-instance production deployments
|
|
41
|
+
* - Testing
|
|
42
|
+
*
|
|
43
|
+
* NOT suitable for:
|
|
44
|
+
* - Multi-instance/clustered deployments (events won't propagate across instances)
|
|
45
|
+
* - High-throughput scenarios (consider Redis-based PubSub)
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Define your topic types
|
|
50
|
+
* interface MyTopics {
|
|
51
|
+
* 'user:created': { id: string; name: string }
|
|
52
|
+
* 'message:sent': { channelId: string; content: string }
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* // Create typed PubSub instance
|
|
56
|
+
* const pubsub = createPubSub<MyTopics>()
|
|
57
|
+
*
|
|
58
|
+
* // Publish events
|
|
59
|
+
* await pubsub.publish('user:created', { id: '123', name: 'John' })
|
|
60
|
+
*
|
|
61
|
+
* // Subscribe to events (in a resolver)
|
|
62
|
+
* export const userSubscriptions = defineSubscription({
|
|
63
|
+
* userCreated: {
|
|
64
|
+
* subscribe: async function* () {
|
|
65
|
+
* yield* pubsub.subscribe('user:created')
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare function createPubSub<Topics extends Record<string, unknown> = Record<string, unknown>>(): PubSubEngine<Topics>;
|
|
72
|
+
/**
|
|
73
|
+
* Filter subscription events based on a predicate
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* export const chatSubscriptions = defineSubscription({
|
|
78
|
+
* messageAdded: {
|
|
79
|
+
* subscribe: async function* (_, { channelId }) {
|
|
80
|
+
* yield* withFilter(
|
|
81
|
+
* pubsub.subscribe('message:added'),
|
|
82
|
+
* (message) => message.channelId === channelId
|
|
83
|
+
* )
|
|
84
|
+
* }
|
|
85
|
+
* }
|
|
86
|
+
* })
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
declare function withFilter<T>(asyncIterable: AsyncIterable<T>, filter: (value: T) => boolean | Promise<boolean>): AsyncIterable<T>;
|
|
90
|
+
/**
|
|
91
|
+
* Map subscription events to a different shape
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* export const chatSubscriptions = defineSubscription({
|
|
96
|
+
* messageAdded: {
|
|
97
|
+
* subscribe: async function* () {
|
|
98
|
+
* yield* mapAsyncIterator(
|
|
99
|
+
* pubsub.subscribe('message:added'),
|
|
100
|
+
* (event) => ({ messageAdded: event.message })
|
|
101
|
+
* )
|
|
102
|
+
* }
|
|
103
|
+
* }
|
|
104
|
+
* })
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function mapAsyncIterator<T, U>(asyncIterable: AsyncIterable<T>, mapper: (value: T) => U | Promise<U>): AsyncIterable<U>;
|
|
108
|
+
//#endregion
|
|
109
|
+
export { PubSubEngine, TypedPubSub, createPubSub, mapAsyncIterator, withFilter };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
//#region src/core/pubsub/memory-pubsub.ts
|
|
3
|
+
/**
|
|
4
|
+
* Built-in PubSub implementation for GraphQL Subscriptions
|
|
5
|
+
* Simple EventEmitter-based implementation for single-instance deployments
|
|
6
|
+
*
|
|
7
|
+
* For multi-instance deployments, use external PubSub solutions like:
|
|
8
|
+
* - Redis (with ioredis)
|
|
9
|
+
* - Kafka
|
|
10
|
+
* - RabbitMQ
|
|
11
|
+
* - Cloud Pub/Sub services
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Create a simple in-memory PubSub instance
|
|
15
|
+
*
|
|
16
|
+
* This implementation uses EventEmitter for lightweight pub/sub functionality.
|
|
17
|
+
* Suitable for:
|
|
18
|
+
* - Development environments
|
|
19
|
+
* - Single-instance production deployments
|
|
20
|
+
* - Testing
|
|
21
|
+
*
|
|
22
|
+
* NOT suitable for:
|
|
23
|
+
* - Multi-instance/clustered deployments (events won't propagate across instances)
|
|
24
|
+
* - High-throughput scenarios (consider Redis-based PubSub)
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Define your topic types
|
|
29
|
+
* interface MyTopics {
|
|
30
|
+
* 'user:created': { id: string; name: string }
|
|
31
|
+
* 'message:sent': { channelId: string; content: string }
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* // Create typed PubSub instance
|
|
35
|
+
* const pubsub = createPubSub<MyTopics>()
|
|
36
|
+
*
|
|
37
|
+
* // Publish events
|
|
38
|
+
* await pubsub.publish('user:created', { id: '123', name: 'John' })
|
|
39
|
+
*
|
|
40
|
+
* // Subscribe to events (in a resolver)
|
|
41
|
+
* export const userSubscriptions = defineSubscription({
|
|
42
|
+
* userCreated: {
|
|
43
|
+
* subscribe: async function* () {
|
|
44
|
+
* yield* pubsub.subscribe('user:created')
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
function createPubSub() {
|
|
51
|
+
const emitter = new EventEmitter();
|
|
52
|
+
emitter.setMaxListeners(0);
|
|
53
|
+
return {
|
|
54
|
+
async publish(topic, payload) {
|
|
55
|
+
emitter.emit(String(topic), payload);
|
|
56
|
+
},
|
|
57
|
+
subscribe(topic) {
|
|
58
|
+
const topicStr = String(topic);
|
|
59
|
+
return { [Symbol.asyncIterator]() {
|
|
60
|
+
const queue = [];
|
|
61
|
+
let resolve = null;
|
|
62
|
+
let done = false;
|
|
63
|
+
const listener = (payload) => {
|
|
64
|
+
if (resolve) {
|
|
65
|
+
resolve({
|
|
66
|
+
value: payload,
|
|
67
|
+
done: false
|
|
68
|
+
});
|
|
69
|
+
resolve = null;
|
|
70
|
+
} else queue.push(payload);
|
|
71
|
+
};
|
|
72
|
+
emitter.on(topicStr, listener);
|
|
73
|
+
return {
|
|
74
|
+
next() {
|
|
75
|
+
if (done) return Promise.resolve({
|
|
76
|
+
value: void 0,
|
|
77
|
+
done: true
|
|
78
|
+
});
|
|
79
|
+
if (queue.length > 0) return Promise.resolve({
|
|
80
|
+
value: queue.shift(),
|
|
81
|
+
done: false
|
|
82
|
+
});
|
|
83
|
+
return new Promise((r) => {
|
|
84
|
+
resolve = r;
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
return() {
|
|
88
|
+
done = true;
|
|
89
|
+
emitter.off(topicStr, listener);
|
|
90
|
+
return Promise.resolve({
|
|
91
|
+
value: void 0,
|
|
92
|
+
done: true
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
throw(error) {
|
|
96
|
+
done = true;
|
|
97
|
+
emitter.off(topicStr, listener);
|
|
98
|
+
return Promise.reject(error);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
} };
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Filter subscription events based on a predicate
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* export const chatSubscriptions = defineSubscription({
|
|
111
|
+
* messageAdded: {
|
|
112
|
+
* subscribe: async function* (_, { channelId }) {
|
|
113
|
+
* yield* withFilter(
|
|
114
|
+
* pubsub.subscribe('message:added'),
|
|
115
|
+
* (message) => message.channelId === channelId
|
|
116
|
+
* )
|
|
117
|
+
* }
|
|
118
|
+
* }
|
|
119
|
+
* })
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
async function* withFilter(asyncIterable, filter) {
|
|
123
|
+
for await (const value of asyncIterable) if (await filter(value)) yield value;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Map subscription events to a different shape
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* export const chatSubscriptions = defineSubscription({
|
|
131
|
+
* messageAdded: {
|
|
132
|
+
* subscribe: async function* () {
|
|
133
|
+
* yield* mapAsyncIterator(
|
|
134
|
+
* pubsub.subscribe('message:added'),
|
|
135
|
+
* (event) => ({ messageAdded: event.message })
|
|
136
|
+
* )
|
|
137
|
+
* }
|
|
138
|
+
* }
|
|
139
|
+
* })
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
async function* mapAsyncIterator(asyncIterable, mapper) {
|
|
143
|
+
for await (const value of asyncIterable) yield await mapper(value);
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { createPubSub, mapAsyncIterator, withFilter };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { scanDirectory } from "./
|
|
1
|
+
import { scanDirectory } from "./file-scanner.mjs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
+
import consola from "consola";
|
|
3
4
|
import { basename, relative } from "pathe";
|
|
4
5
|
import { parseSync } from "oxc-parser";
|
|
5
|
-
|
|
6
6
|
//#region src/core/scanning/ast-scanner.ts
|
|
7
7
|
/**
|
|
8
8
|
* Scan files matching a pattern and parse their exports using AST
|
|
@@ -67,7 +67,8 @@ async function parseSingleFile(filePath, parseCall) {
|
|
|
67
67
|
});
|
|
68
68
|
if (result.resolver.imports.length > 0) return result.resolver;
|
|
69
69
|
return null;
|
|
70
|
-
} catch {
|
|
70
|
+
} catch (error) {
|
|
71
|
+
consola.debug(`[nitro-graphql] Failed to parse file ${filePath}:`, error);
|
|
71
72
|
return null;
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -111,6 +112,5 @@ function parseExports(filePath, program, config) {
|
|
|
111
112
|
warnings
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
|
-
|
|
115
115
|
//#endregion
|
|
116
|
-
export { parseSingleFile, scanWithAST };
|
|
116
|
+
export { parseSingleFile, scanWithAST };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DIRECTIVE_GLOB_PATTERN } from "../constants.mjs";
|
|
2
2
|
import { scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { getImportId } from "../utils/imports.mjs";
|
|
5
4
|
//#region src/core/scanning/directives.ts
|
|
6
5
|
/**
|
|
7
6
|
* Parse a defineDirective call and return the import info
|
|
@@ -11,7 +10,7 @@ function parseDirectiveCall(calleeName, exportName, filePath) {
|
|
|
11
10
|
return {
|
|
12
11
|
name: exportName,
|
|
13
12
|
type: "directive",
|
|
14
|
-
as:
|
|
13
|
+
as: getImportId(exportName + filePath)
|
|
15
14
|
};
|
|
16
15
|
}
|
|
17
16
|
/**
|
|
@@ -24,6 +23,5 @@ function scanDirectivesCore(ctx) {
|
|
|
24
23
|
emitWarnings: false
|
|
25
24
|
});
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
//#endregion
|
|
29
|
-
export { parseDirectiveCall, scanDirectivesCore };
|
|
27
|
+
export { parseDirectiveCall, scanDirectivesCore };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { CoreExternalService } from "../types/config.mjs";
|
|
2
1
|
import { ScanContext, ScanResult } from "../types/scanning.mjs";
|
|
3
2
|
|
|
4
3
|
//#region src/core/scanning/documents.d.ts
|
|
@@ -6,8 +5,10 @@ import { ScanContext, ScanResult } from "../types/scanning.mjs";
|
|
|
6
5
|
* Options for scanning documents
|
|
7
6
|
*/
|
|
8
7
|
interface ScanDocumentsOptions {
|
|
9
|
-
/** External services to exclude from main scan */
|
|
10
|
-
externalServices?:
|
|
8
|
+
/** External services to exclude from main scan (only documents field is used) */
|
|
9
|
+
externalServices?: Array<{
|
|
10
|
+
documents?: string[];
|
|
11
|
+
}>;
|
|
11
12
|
/** Client directory relative path */
|
|
12
13
|
clientDirRelative?: string;
|
|
13
14
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { GRAPHQL_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
-
import { scanDirectory } from "./
|
|
2
|
+
import { scanDirectory } from "./file-scanner.mjs";
|
|
3
3
|
import { relative } from "pathe";
|
|
4
|
-
|
|
5
4
|
//#region src/core/scanning/documents.ts
|
|
5
|
+
const REGEX_SPECIAL_CHARS_RE = /[.*+?^${}()|[\]\\]/g;
|
|
6
6
|
/**
|
|
7
7
|
* Scan for GraphQL client documents (.graphql, .gql) in client directory
|
|
8
8
|
* Excludes files from external service directories
|
|
@@ -17,7 +17,7 @@ async function scanDocumentsCore(ctx, options = {}) {
|
|
|
17
17
|
return {
|
|
18
18
|
items: allFiles.filter((f) => !f.path.startsWith("external/")).filter((f) => {
|
|
19
19
|
const relativePath = f.path;
|
|
20
|
-
for (const pattern of externalPatterns) if (pattern.replace(new RegExp(`^${clientDirRelative.replace(
|
|
20
|
+
for (const pattern of externalPatterns) if (pattern.replace(new RegExp(`^${clientDirRelative.replace(REGEX_SPECIAL_CHARS_RE, "\\$&")}/`), "").split("/")[0] === relativePath.split("/")[0]) return false;
|
|
21
21
|
return true;
|
|
22
22
|
}).map((f) => f.fullPath),
|
|
23
23
|
warnings,
|
|
@@ -32,6 +32,5 @@ async function scanDocumentsCore(ctx, options = {}) {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
36
35
|
//#endregion
|
|
37
|
-
export { scanDocumentsCore };
|
|
36
|
+
export { scanDocumentsCore };
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { GLOB_SCAN_PATTERN } from "../constants.mjs";
|
|
1
|
+
import { DEFAULT_IGNORE_PATTERNS, GLOB_SCAN_PATTERN } from "../constants.mjs";
|
|
2
2
|
import { join, relative } from "pathe";
|
|
3
3
|
import { glob } from "tinyglobby";
|
|
4
|
-
|
|
5
|
-
//#region src/core/scanning/common.ts
|
|
6
|
-
const DEFAULT_IGNORE_PATTERNS = [
|
|
7
|
-
"**/node_modules/**",
|
|
8
|
-
"**/.git/**",
|
|
9
|
-
"**/.output/**",
|
|
10
|
-
"**/.nitro/**",
|
|
11
|
-
"**/.nuxt/**",
|
|
12
|
-
"**/.graphql/**"
|
|
13
|
-
];
|
|
4
|
+
//#region src/core/scanning/file-scanner.ts
|
|
14
5
|
/**
|
|
15
6
|
* Scan a directory for files matching a glob pattern
|
|
16
7
|
*/
|
|
@@ -54,6 +45,5 @@ function filterByExtension(files, extensions) {
|
|
|
54
45
|
function extractPaths(files) {
|
|
55
46
|
return files.map((f) => f.fullPath);
|
|
56
47
|
}
|
|
57
|
-
|
|
58
48
|
//#endregion
|
|
59
|
-
export { deduplicateFiles, extractPaths, filterByExtension, scanDirectory };
|
|
49
|
+
export { deduplicateFiles, extractPaths, filterByExtension, scanDirectory };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ASTScanConfig, parseSingleFile, scanWithAST } from "./ast-scanner.mjs";
|
|
2
|
-
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./common.mjs";
|
|
3
2
|
import { parseDirectiveCall, scanDirectivesCore } from "./directives.mjs";
|
|
4
3
|
import { ScanDocumentsOptions, scanDocumentsCore } from "./documents.mjs";
|
|
4
|
+
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./file-scanner.mjs";
|
|
5
5
|
import { parseResolverCall, scanResolversCore } from "./resolvers.mjs";
|
|
6
|
-
import {
|
|
7
|
-
export { type ASTScanConfig, type ScanDocumentsOptions, deduplicateFiles, extractPaths, filterByExtension, parseDirectiveCall, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore,
|
|
6
|
+
import { scanSchemasCore } from "./schemas.mjs";
|
|
7
|
+
export { type ASTScanConfig, type ScanDocumentsOptions, deduplicateFiles, extractPaths, filterByExtension, parseDirectiveCall, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore, scanResolversCore, scanSchemasCore, scanWithAST };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./
|
|
1
|
+
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./file-scanner.mjs";
|
|
2
2
|
import { parseSingleFile, scanWithAST } from "./ast-scanner.mjs";
|
|
3
3
|
import { parseDirectiveCall, scanDirectivesCore } from "./directives.mjs";
|
|
4
4
|
import { scanDocumentsCore } from "./documents.mjs";
|
|
5
5
|
import { parseResolverCall, scanResolversCore } from "./resolvers.mjs";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export { deduplicateFiles, extractPaths, filterByExtension, parseDirectiveCall, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore, scanGraphqlCore, scanResolversCore, scanSchemasCore, scanWithAST };
|
|
6
|
+
import { scanSchemasCore } from "./schemas.mjs";
|
|
7
|
+
export { deduplicateFiles, extractPaths, filterByExtension, parseDirectiveCall, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore, scanResolversCore, scanSchemasCore, scanWithAST };
|
|
@@ -1,44 +1,43 @@
|
|
|
1
1
|
import { DEFINE_FUNCTIONS, RESOLVER_GLOB_PATTERN } from "../constants.mjs";
|
|
2
2
|
import { scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { getImportId } from "../utils/imports.mjs";
|
|
5
4
|
//#region src/core/scanning/resolvers.ts
|
|
6
5
|
/**
|
|
7
6
|
* Parse a define* function call and return the import info
|
|
8
7
|
* Exported for use by manifest loader
|
|
9
8
|
*/
|
|
10
9
|
function parseResolverCall(calleeName, exportName, filePath) {
|
|
11
|
-
const
|
|
10
|
+
const alias = getImportId(exportName + filePath);
|
|
12
11
|
switch (calleeName) {
|
|
13
12
|
case "defineResolver": return {
|
|
14
13
|
name: exportName,
|
|
15
14
|
type: "resolver",
|
|
16
|
-
as:
|
|
15
|
+
as: alias
|
|
17
16
|
};
|
|
18
17
|
case "defineQuery": return {
|
|
19
18
|
name: exportName,
|
|
20
19
|
type: "query",
|
|
21
|
-
as:
|
|
20
|
+
as: alias
|
|
22
21
|
};
|
|
23
22
|
case "defineMutation": return {
|
|
24
23
|
name: exportName,
|
|
25
24
|
type: "mutation",
|
|
26
|
-
as:
|
|
25
|
+
as: alias
|
|
27
26
|
};
|
|
28
27
|
case "defineField": return {
|
|
29
28
|
name: exportName,
|
|
30
29
|
type: "type",
|
|
31
|
-
as:
|
|
30
|
+
as: alias
|
|
32
31
|
};
|
|
33
32
|
case "defineSubscription": return {
|
|
34
33
|
name: exportName,
|
|
35
34
|
type: "subscription",
|
|
36
|
-
as:
|
|
35
|
+
as: alias
|
|
37
36
|
};
|
|
38
37
|
case "defineDirective": return {
|
|
39
38
|
name: exportName,
|
|
40
39
|
type: "directive",
|
|
41
|
-
as:
|
|
40
|
+
as: alias
|
|
42
41
|
};
|
|
43
42
|
default: return null;
|
|
44
43
|
}
|
|
@@ -54,6 +53,5 @@ function scanResolversCore(ctx) {
|
|
|
54
53
|
validFunctions: DEFINE_FUNCTIONS
|
|
55
54
|
});
|
|
56
55
|
}
|
|
57
|
-
|
|
58
56
|
//#endregion
|
|
59
|
-
export { parseResolverCall, scanResolversCore };
|
|
57
|
+
export { parseResolverCall, scanResolversCore };
|
|
@@ -5,9 +5,5 @@ import { ScanContext, ScanResult } from "../types/scanning.mjs";
|
|
|
5
5
|
* Scan for GraphQL schema files (.graphql, .gql) in server directory
|
|
6
6
|
*/
|
|
7
7
|
declare function scanSchemasCore(ctx: ScanContext): Promise<ScanResult<string>>;
|
|
8
|
-
/**
|
|
9
|
-
* Scan for GraphQL files (.graphql, .gql) in server directory
|
|
10
|
-
*/
|
|
11
|
-
declare function scanGraphqlCore(ctx: ScanContext): Promise<ScanResult<string>>;
|
|
12
8
|
//#endregion
|
|
13
|
-
export {
|
|
9
|
+
export { scanSchemasCore };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { GRAPHQL_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
-
import { extractPaths, scanDirectory } from "./
|
|
2
|
+
import { extractPaths, scanDirectory } from "./file-scanner.mjs";
|
|
3
3
|
import { relative } from "pathe";
|
|
4
|
-
|
|
5
4
|
//#region src/core/scanning/schemas.ts
|
|
6
5
|
/**
|
|
7
6
|
* Scan for GraphQL schema files (.graphql, .gql) in server directory
|
|
@@ -25,28 +24,5 @@ async function scanSchemasCore(ctx) {
|
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Scan for GraphQL files (.graphql, .gql) in server directory
|
|
30
|
-
*/
|
|
31
|
-
async function scanGraphqlCore(ctx) {
|
|
32
|
-
const warnings = [];
|
|
33
|
-
const errors = [];
|
|
34
|
-
try {
|
|
35
|
-
const serverDirRelative = relative(ctx.rootDir, ctx.serverDir);
|
|
36
|
-
return {
|
|
37
|
-
items: extractPaths(await scanDirectory(ctx, ctx.rootDir, serverDirRelative, "**/*.{graphql,gql}")),
|
|
38
|
-
warnings,
|
|
39
|
-
errors
|
|
40
|
-
};
|
|
41
|
-
} catch (error) {
|
|
42
|
-
errors.push(`GraphQL scanning error: ${error}`);
|
|
43
|
-
return {
|
|
44
|
-
items: [],
|
|
45
|
-
warnings,
|
|
46
|
-
errors
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
27
|
//#endregion
|
|
52
|
-
export {
|
|
28
|
+
export { scanSchemasCore };
|