nitro-graphql 2.0.0-beta.72 → 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 +6 -29
- package/dist/cli/commands/generate.mjs +2 -2
- package/dist/cli/config.d.mts +4 -5
- package/dist/cli/config.mjs +3 -1
- package/dist/cli/index.d.mts +3 -6
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/server/graphql-handler.mjs +2 -1
- package/dist/cli/server/watcher.mjs +1 -1
- package/dist/core/codegen/client.d.mts +4 -27
- package/dist/core/codegen/client.mjs +26 -445
- 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 -5
- package/dist/core/codegen/{runtime.d.mts → runtime-generator.d.mts} +1 -1
- package/dist/core/codegen/{runtime.mjs → runtime-generator.mjs} +1 -1
- package/dist/core/codegen/schema-loader.d.mts +2 -7
- package/dist/core/codegen/schema-loader.mjs +65 -70
- 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 -105
- package/dist/core/codegen/subscription-extractor.d.mts +20 -0
- package/dist/core/codegen/subscription-extractor.mjs +30 -0
- 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 -54
- 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 -2
- package/dist/core/debug/template.d.mts +1 -5
- package/dist/core/debug/template.mjs +1 -1
- package/dist/core/extend/loader.d.mts +0 -1
- package/dist/core/extend/loader.mjs +59 -89
- package/dist/core/index.d.mts +22 -17
- package/dist/core/index.mjs +19 -15
- package/dist/core/manifest.mjs +3 -1
- package/dist/core/pubsub/index.d.mts +2 -109
- package/dist/core/pubsub/index.mjs +1 -145
- 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 +4 -2
- package/dist/core/scanning/directives.mjs +2 -3
- package/dist/core/scanning/documents.d.mts +4 -3
- package/dist/core/scanning/documents.mjs +1 -1
- package/dist/core/scanning/{common.d.mts → file-scanner.d.mts} +1 -1
- package/dist/core/scanning/{common.mjs → file-scanner.mjs} +2 -10
- package/dist/core/scanning/index.d.mts +3 -3
- package/dist/core/scanning/index.mjs +3 -3
- package/dist/core/scanning/resolvers.mjs +8 -9
- package/dist/core/scanning/schemas.d.mts +1 -5
- package/dist/core/scanning/schemas.mjs +2 -24
- package/dist/core/schema/builder.d.mts +4 -2
- package/dist/core/schema/builder.mjs +4 -2
- package/dist/core/schema/index.d.mts +2 -2
- package/dist/core/schema/index.mjs +2 -2
- 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 -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 -13
- package/dist/core/types/adapter.d.mts +4 -39
- package/dist/core/types/codegen.d.mts +22 -45
- package/dist/core/types/config.d.mts +33 -121
- package/dist/core/types/define.d.mts +8 -5
- package/dist/core/types/index.d.mts +5 -4
- package/dist/core/types/scanning.d.mts +4 -1
- package/dist/core/types/standard-schema.d.mts +64 -0
- package/dist/core/utils/directive-parser.d.mts +8 -63
- package/dist/core/utils/directive-parser.mjs +114 -166
- package/dist/core/utils/file-io.d.mts +1 -5
- package/dist/core/utils/file-io.mjs +1 -11
- package/dist/core/utils/index.d.mts +5 -4
- package/dist/core/utils/index.mjs +6 -5
- package/dist/core/utils/logger.d.mts +1 -10
- package/dist/core/utils/logger.mjs +1 -19
- package/dist/core/utils/ofetch-templates.mjs +3 -4
- package/dist/core/utils/runtime.d.mts +1 -30
- package/dist/core/utils/runtime.mjs +2 -44
- package/dist/core/utils/string.d.mts +10 -0
- package/dist/core/utils/string.mjs +12 -0
- 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 +1 -139
- package/dist/define.d.mts +4 -2
- package/dist/define.mjs +7 -6
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +1 -1
- package/dist/nitro/adapter.d.mts +6 -10
- package/dist/nitro/adapter.mjs +12 -42
- 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 +1 -1
- package/dist/nitro/paths.d.mts +3 -2
- package/dist/nitro/paths.mjs +13 -9
- package/dist/nitro/rollup.mjs +4 -3
- package/dist/nitro/routes/_ws-handler.d.mts +6 -0
- package/dist/nitro/routes/_ws-handler.mjs +49 -0
- package/dist/nitro/routes/apollo-server-ws.d.mts +1 -1
- package/dist/nitro/routes/apollo-server-ws.mjs +9 -44
- package/dist/nitro/routes/apollo-server.d.mts +1 -1
- package/dist/nitro/routes/apollo-server.mjs +16 -55
- package/dist/nitro/routes/debug.d.mts +1 -1
- package/dist/nitro/routes/debug.mjs +1 -0
- package/dist/nitro/routes/graphql-yoga-ws.d.mts +1 -1
- package/dist/nitro/routes/graphql-yoga-ws.mjs +6 -44
- package/dist/nitro/routes/graphql-yoga.mjs +7 -5
- package/dist/nitro/routes/health.mjs +22 -24
- package/dist/nitro/setup/extend-loader.d.mts +6 -5
- package/dist/nitro/setup/extend-loader.mjs +30 -58
- package/dist/nitro/setup/file-watcher.mjs +6 -4
- package/dist/nitro/setup/logging.d.mts +1 -8
- package/dist/nitro/setup/logging.mjs +7 -22
- package/dist/nitro/setup/rollup-integration.mjs +32 -1
- package/dist/nitro/setup/scanner.d.mts +8 -43
- package/dist/nitro/setup/scanner.mjs +56 -58
- package/dist/nitro/setup/security.d.mts +10 -0
- package/dist/nitro/setup/security.mjs +17 -0
- 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 +87 -74
- 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 +0 -5
- 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/native/index.js +52 -52
- package/package.json +15 -15
- package/dist/cli/commands/index.d.mts +0 -5
- package/dist/cli/commands/index.mjs +0 -5
- package/dist/core/codegen/plugin.d.mts +0 -19
- package/dist/core/codegen/plugin.mjs +0 -29
- package/dist/core/config.d.mts +0 -45
- package/dist/core/config.mjs +0 -76
- package/dist/nitro/codegen.d.mts +0 -18
- package/dist/nitro/codegen.mjs +0 -171
- package/dist/nitro/config.d.mts +0 -50
- package/dist/nitro/config.mjs +0 -55
- package/dist/nitro/types.d.mts +0 -549
- package/dist/nitro/virtual/generators.d.mts +0 -38
- package/dist/nitro/virtual/generators.mjs +0 -190
- /package/dist/{nitro/types.mjs → core/types/standard-schema.mjs} +0 -0
|
@@ -1,146 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/core/pubsub/index.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
|
|
1
|
+
import { createPubSub, mapAsyncIterator, withFilter } from "./memory-pubsub.mjs";
|
|
146
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,5 +1,6 @@
|
|
|
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
|
//#region src/core/scanning/ast-scanner.ts
|
|
@@ -66,7 +67,8 @@ async function parseSingleFile(filePath, parseCall) {
|
|
|
66
67
|
});
|
|
67
68
|
if (result.resolver.imports.length > 0) return result.resolver;
|
|
68
69
|
return null;
|
|
69
|
-
} catch {
|
|
70
|
+
} catch (error) {
|
|
71
|
+
consola.debug(`[nitro-graphql] Failed to parse file ${filePath}:`, error);
|
|
70
72
|
return null;
|
|
71
73
|
}
|
|
72
74
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { DIRECTIVE_GLOB_PATTERN } from "../constants.mjs";
|
|
2
2
|
import { scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { getImportId } from "../utils/imports.mjs";
|
|
4
4
|
//#region src/core/scanning/directives.ts
|
|
5
|
-
const HYPHEN_RE = /-/g;
|
|
6
5
|
/**
|
|
7
6
|
* Parse a defineDirective call and return the import info
|
|
8
7
|
*/
|
|
@@ -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
|
/**
|
|
@@ -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,5 +1,5 @@
|
|
|
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
4
|
//#region src/core/scanning/documents.ts
|
|
5
5
|
const REGEX_SPECIAL_CHARS_RE = /[.*+?^${}()|[\]\\]/g;
|
|
@@ -1,15 +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
|
-
//#region src/core/scanning/
|
|
5
|
-
const DEFAULT_IGNORE_PATTERNS = [
|
|
6
|
-
"**/node_modules/**",
|
|
7
|
-
"**/.git/**",
|
|
8
|
-
"**/.output/**",
|
|
9
|
-
"**/.nitro/**",
|
|
10
|
-
"**/.nuxt/**",
|
|
11
|
-
"**/.graphql/**"
|
|
12
|
-
];
|
|
4
|
+
//#region src/core/scanning/file-scanner.ts
|
|
13
5
|
/**
|
|
14
6
|
* Scan a directory for files matching a glob pattern
|
|
15
7
|
*/
|
|
@@ -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,7 +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
|
-
export { deduplicateFiles, extractPaths, filterByExtension, parseDirectiveCall, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore,
|
|
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 {
|
|
3
|
+
import { getImportId } from "../utils/imports.mjs";
|
|
4
4
|
//#region src/core/scanning/resolvers.ts
|
|
5
|
-
const HYPHEN_RE = /-/g;
|
|
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
|
}
|
|
@@ -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,5 +1,5 @@
|
|
|
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
4
|
//#region src/core/scanning/schemas.ts
|
|
5
5
|
/**
|
|
@@ -24,27 +24,5 @@ async function scanSchemasCore(ctx) {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Scan for GraphQL files (.graphql, .gql) in server directory
|
|
29
|
-
*/
|
|
30
|
-
async function scanGraphqlCore(ctx) {
|
|
31
|
-
const warnings = [];
|
|
32
|
-
const errors = [];
|
|
33
|
-
try {
|
|
34
|
-
const serverDirRelative = relative(ctx.rootDir, ctx.serverDir);
|
|
35
|
-
return {
|
|
36
|
-
items: extractPaths(await scanDirectory(ctx, ctx.rootDir, serverDirRelative, "**/*.{graphql,gql}")),
|
|
37
|
-
warnings,
|
|
38
|
-
errors
|
|
39
|
-
};
|
|
40
|
-
} catch (error) {
|
|
41
|
-
errors.push(`GraphQL scanning error: ${error}`);
|
|
42
|
-
return {
|
|
43
|
-
items: [],
|
|
44
|
-
warnings,
|
|
45
|
-
errors
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
27
|
//#endregion
|
|
50
|
-
export {
|
|
28
|
+
export { scanSchemasCore };
|
|
@@ -46,9 +46,11 @@ declare function createMergedSchema(options: CreateMergedSchemaOptions): Promise
|
|
|
46
46
|
/**
|
|
47
47
|
* Base schema with empty Query and Mutation types.
|
|
48
48
|
* Required for 'extend type Query' syntax to work.
|
|
49
|
-
* Shared between CLI and
|
|
49
|
+
* Shared between CLI, Yoga, and Apollo routes.
|
|
50
50
|
*/
|
|
51
51
|
declare const BASE_SCHEMA = "type Query { _empty: String }\ntype Mutation { _empty: String }";
|
|
52
|
+
/** BASE_SCHEMA wrapped as a SchemaDefinition for virtual module usage */
|
|
53
|
+
declare const BASE_SCHEMA_DEF: SchemaDefinition;
|
|
52
54
|
/**
|
|
53
55
|
* Build a GraphQL schema from file paths (CLI usage)
|
|
54
56
|
* Reads schema files, merges them, and builds an executable schema
|
|
@@ -56,4 +58,4 @@ declare const BASE_SCHEMA = "type Query { _empty: String }\ntype Mutation { _emp
|
|
|
56
58
|
*/
|
|
57
59
|
declare function buildGraphQLSchema(schemaPaths: string[]): Promise<GraphQLSchema | null>;
|
|
58
60
|
//#endregion
|
|
59
|
-
export { BASE_SCHEMA, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate };
|
|
61
|
+
export { BASE_SCHEMA, BASE_SCHEMA_DEF, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate };
|
|
@@ -49,10 +49,12 @@ async function createMergedSchema(options) {
|
|
|
49
49
|
/**
|
|
50
50
|
* Base schema with empty Query and Mutation types.
|
|
51
51
|
* Required for 'extend type Query' syntax to work.
|
|
52
|
-
* Shared between CLI and
|
|
52
|
+
* Shared between CLI, Yoga, and Apollo routes.
|
|
53
53
|
*/
|
|
54
54
|
const BASE_SCHEMA = `type Query { _empty: String }
|
|
55
55
|
type Mutation { _empty: String }`;
|
|
56
|
+
/** BASE_SCHEMA wrapped as a SchemaDefinition for virtual module usage */
|
|
57
|
+
const BASE_SCHEMA_DEF = { def: BASE_SCHEMA };
|
|
56
58
|
/**
|
|
57
59
|
* Build a GraphQL schema from file paths (CLI usage)
|
|
58
60
|
* Reads schema files, merges them, and builds an executable schema
|
|
@@ -73,4 +75,4 @@ async function buildGraphQLSchema(schemaPaths) {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
//#endregion
|
|
76
|
-
export { BASE_SCHEMA, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate };
|
|
78
|
+
export { BASE_SCHEMA, BASE_SCHEMA_DEF, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { BASE_SCHEMA, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate } from "./builder.mjs";
|
|
1
|
+
import { BASE_SCHEMA, BASE_SCHEMA_DEF, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate } from "./builder.mjs";
|
|
2
2
|
import { loadFederationSupport, resetFederationCache, warnFederationUnavailable } from "./federation.mjs";
|
|
3
|
-
export { BASE_SCHEMA, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, loadFederationSupport, parse, resetFederationCache, subscribe, validate, warnFederationUnavailable };
|
|
3
|
+
export { BASE_SCHEMA, BASE_SCHEMA_DEF, CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema, loadFederationSupport, parse, resetFederationCache, subscribe, validate, warnFederationUnavailable };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { loadFederationSupport, resetFederationCache, warnFederationUnavailable } from "./federation.mjs";
|
|
2
|
-
import { BASE_SCHEMA, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate } from "./builder.mjs";
|
|
3
|
-
export { BASE_SCHEMA, buildGraphQLSchema, createMergedSchema, loadFederationSupport, parse, resetFederationCache, subscribe, validate, warnFederationUnavailable };
|
|
2
|
+
import { BASE_SCHEMA, BASE_SCHEMA_DEF, buildGraphQLSchema, createMergedSchema, parse, subscribe, validate } from "./builder.mjs";
|
|
3
|
+
export { BASE_SCHEMA, BASE_SCHEMA_DEF, buildGraphQLSchema, createMergedSchema, loadFederationSupport, parse, resetFederationCache, subscribe, validate, warnFederationUnavailable };
|