@0xobelisk/graphql-server 1.2.0-pre.24
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/Dockerfile +31 -0
- package/EXPRESS_MIGRATION.md +176 -0
- package/LICENSE +92 -0
- package/README.md +908 -0
- package/dist/config/subscription-config.d.ts +47 -0
- package/dist/config/subscription-config.d.ts.map +1 -0
- package/dist/config/subscription-config.js +133 -0
- package/dist/config/subscription-config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +217 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/all-fields-filter-plugin.d.ts +4 -0
- package/dist/plugins/all-fields-filter-plugin.d.ts.map +1 -0
- package/dist/plugins/all-fields-filter-plugin.js +132 -0
- package/dist/plugins/all-fields-filter-plugin.js.map +1 -0
- package/dist/plugins/database-introspector.d.ts +23 -0
- package/dist/plugins/database-introspector.d.ts.map +1 -0
- package/dist/plugins/database-introspector.js +96 -0
- package/dist/plugins/database-introspector.js.map +1 -0
- package/dist/plugins/enhanced-playground.d.ts +9 -0
- package/dist/plugins/enhanced-playground.d.ts.map +1 -0
- package/dist/plugins/enhanced-playground.js +97 -0
- package/dist/plugins/enhanced-playground.js.map +1 -0
- package/dist/plugins/enhanced-server-manager.d.ts +28 -0
- package/dist/plugins/enhanced-server-manager.d.ts.map +1 -0
- package/dist/plugins/enhanced-server-manager.js +232 -0
- package/dist/plugins/enhanced-server-manager.js.map +1 -0
- package/dist/plugins/index.d.ts +9 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +26 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/postgraphile-config.d.ts +94 -0
- package/dist/plugins/postgraphile-config.d.ts.map +1 -0
- package/dist/plugins/postgraphile-config.js +183 -0
- package/dist/plugins/postgraphile-config.js.map +1 -0
- package/dist/plugins/query-filter.d.ts +4 -0
- package/dist/plugins/query-filter.d.ts.map +1 -0
- package/dist/plugins/query-filter.js +42 -0
- package/dist/plugins/query-filter.js.map +1 -0
- package/dist/plugins/simple-naming.d.ts +4 -0
- package/dist/plugins/simple-naming.d.ts.map +1 -0
- package/dist/plugins/simple-naming.js +79 -0
- package/dist/plugins/simple-naming.js.map +1 -0
- package/dist/plugins/welcome-page.d.ts +11 -0
- package/dist/plugins/welcome-page.d.ts.map +1 -0
- package/dist/plugins/welcome-page.js +203 -0
- package/dist/plugins/welcome-page.js.map +1 -0
- package/dist/universal-subscriptions.d.ts +32 -0
- package/dist/universal-subscriptions.d.ts.map +1 -0
- package/dist/universal-subscriptions.js +318 -0
- package/dist/universal-subscriptions.js.map +1 -0
- package/dist/utils/logger/index.d.ts +80 -0
- package/dist/utils/logger/index.d.ts.map +1 -0
- package/dist/utils/logger/index.js +232 -0
- package/dist/utils/logger/index.js.map +1 -0
- package/docker-compose.yml +87 -0
- package/package.json +71 -0
- package/server.log +62 -0
- package/src/config/subscription-config.ts +186 -0
- package/src/index.ts +239 -0
- package/src/plugins/README.md +123 -0
- package/src/plugins/all-fields-filter-plugin.ts +158 -0
- package/src/plugins/database-introspector.ts +126 -0
- package/src/plugins/enhanced-playground.ts +105 -0
- package/src/plugins/enhanced-server-manager.ts +282 -0
- package/src/plugins/index.ts +9 -0
- package/src/plugins/postgraphile-config.ts +226 -0
- package/src/plugins/query-filter.ts +50 -0
- package/src/plugins/simple-naming.ts +105 -0
- package/src/plugins/welcome-page.ts +218 -0
- package/src/universal-subscriptions.ts +397 -0
- package/src/utils/logger/README.md +193 -0
- package/src/utils/logger/index.ts +315 -0
- package/sui-indexer-schema.graphql +1004 -0
- package/test-express.js +124 -0
- package/test_listen_subscription.js +121 -0
- package/test_notification.js +63 -0
- package/tsconfig.json +28 -0
package/test-express.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Express服务器测试脚本
|
|
5
|
+
* 测试各个端点是否正常工作
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const http = require('http');
|
|
9
|
+
|
|
10
|
+
const PORT = process.env.PORT || 4000;
|
|
11
|
+
const HOST = 'localhost';
|
|
12
|
+
|
|
13
|
+
// 测试端点列表
|
|
14
|
+
const endpoints = [
|
|
15
|
+
{ path: '/', description: '主页' },
|
|
16
|
+
{ path: '/health', description: '健康检查' },
|
|
17
|
+
{ path: '/playground', description: 'GraphQL Playground' },
|
|
18
|
+
{ path: '/subscription-config', description: '订阅配置' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// 发送HTTP请求的辅助函数
|
|
22
|
+
function makeRequest(path) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const options = {
|
|
25
|
+
hostname: HOST,
|
|
26
|
+
port: PORT,
|
|
27
|
+
path: path,
|
|
28
|
+
method: 'GET',
|
|
29
|
+
timeout: 5000,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const req = http.request(options, (res) => {
|
|
33
|
+
let data = '';
|
|
34
|
+
res.on('data', (chunk) => {
|
|
35
|
+
data += chunk;
|
|
36
|
+
});
|
|
37
|
+
res.on('end', () => {
|
|
38
|
+
resolve({
|
|
39
|
+
statusCode: res.statusCode,
|
|
40
|
+
headers: res.headers,
|
|
41
|
+
data: data.substring(0, 200), // 只显示前200个字符
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
req.on('error', (err) => {
|
|
47
|
+
reject(err);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
req.on('timeout', () => {
|
|
51
|
+
req.destroy();
|
|
52
|
+
reject(new Error('请求超时'));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
req.end();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 主测试函数
|
|
60
|
+
async function testServer() {
|
|
61
|
+
console.log(`🧪 开始测试Express服务器 (${HOST}:${PORT})`);
|
|
62
|
+
console.log('='.repeat(60));
|
|
63
|
+
|
|
64
|
+
let passedTests = 0;
|
|
65
|
+
let totalTests = endpoints.length;
|
|
66
|
+
|
|
67
|
+
for (const endpoint of endpoints) {
|
|
68
|
+
try {
|
|
69
|
+
console.log(`🔍 测试 ${endpoint.path} (${endpoint.description})`);
|
|
70
|
+
|
|
71
|
+
const result = await makeRequest(endpoint.path);
|
|
72
|
+
|
|
73
|
+
if (result.statusCode === 200) {
|
|
74
|
+
console.log(`✅ ${endpoint.path} - 状态码: ${result.statusCode}`);
|
|
75
|
+
console.log(` 内容类型: ${result.headers['content-type']}`);
|
|
76
|
+
if (endpoint.path === '/health' || endpoint.path === '/subscription-config') {
|
|
77
|
+
// 对于JSON端点,尝试解析响应
|
|
78
|
+
try {
|
|
79
|
+
const jsonData = JSON.parse(result.data);
|
|
80
|
+
console.log(` 响应: ${JSON.stringify(jsonData, null, 2).substring(0, 150)}...`);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.log(` 响应: ${result.data.substring(0, 100)}...`);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
console.log(` 响应长度: ${result.data.length} 字符`);
|
|
86
|
+
}
|
|
87
|
+
passedTests++;
|
|
88
|
+
} else {
|
|
89
|
+
console.log(`❌ ${endpoint.path} - 状态码: ${result.statusCode}`);
|
|
90
|
+
console.log(` 响应: ${result.data}`);
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.log(`❌ ${endpoint.path} - 错误: ${error.message}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(''); // 空行分隔
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('='.repeat(60));
|
|
100
|
+
console.log(`📊 测试结果: ${passedTests}/${totalTests} 通过`);
|
|
101
|
+
|
|
102
|
+
if (passedTests === totalTests) {
|
|
103
|
+
console.log('🎉 所有测试通过!Express服务器运行正常');
|
|
104
|
+
process.exit(0);
|
|
105
|
+
} else {
|
|
106
|
+
console.log('⚠️ 部分测试失败,请检查服务器状态');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 检查服务器是否在运行
|
|
112
|
+
console.log('正在检查Express服务器是否启动...');
|
|
113
|
+
makeRequest('/health')
|
|
114
|
+
.then(() => {
|
|
115
|
+
console.log('✅ 服务器正在运行,开始测试\n');
|
|
116
|
+
testServer();
|
|
117
|
+
})
|
|
118
|
+
.catch((error) => {
|
|
119
|
+
console.log(`❌ 无法连接到服务器: ${error.message}`);
|
|
120
|
+
console.log(`请确保Express服务器正在 ${HOST}:${PORT} 上运行`);
|
|
121
|
+
console.log('可以使用以下命令启动服务器:');
|
|
122
|
+
console.log(' pnpm dev');
|
|
123
|
+
process.exit(1);
|
|
124
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const WebSocket = require('ws');
|
|
2
|
+
const { createClient } = require('graphql-ws');
|
|
3
|
+
const { Pool } = require('pg');
|
|
4
|
+
|
|
5
|
+
// 数据库连接
|
|
6
|
+
const pgPool = new Pool({
|
|
7
|
+
connectionString: 'postgres://postgres:postgres@127.0.0.1:5432/postgres'
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// 使用PostGraphile的listen订阅
|
|
11
|
+
const LISTEN_SUBSCRIPTION = `
|
|
12
|
+
subscription TestListenSubscription {
|
|
13
|
+
listen(topic: "store_encounter") {
|
|
14
|
+
relatedNodeId
|
|
15
|
+
relatedNode {
|
|
16
|
+
nodeId
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
async function testListenSubscription() {
|
|
23
|
+
console.log('🧪 测试 PostGraphile Listen 订阅功能');
|
|
24
|
+
console.log('');
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// 1. 建立WebSocket连接
|
|
28
|
+
const client = createClient({
|
|
29
|
+
url: 'ws://localhost:4000/graphql',
|
|
30
|
+
webSocketImpl: WebSocket,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let updateCount = 0;
|
|
34
|
+
let firstDataReceived = false;
|
|
35
|
+
|
|
36
|
+
console.log('📡 开始监听 Listen 订阅...');
|
|
37
|
+
|
|
38
|
+
// 2. 订阅listen
|
|
39
|
+
const dispose = client.subscribe(
|
|
40
|
+
{ query: LISTEN_SUBSCRIPTION },
|
|
41
|
+
{
|
|
42
|
+
next: (data) => {
|
|
43
|
+
updateCount++;
|
|
44
|
+
console.log(`\n✅ 收到 Listen 更新 #${updateCount}:`);
|
|
45
|
+
console.log(JSON.stringify(data, null, 2));
|
|
46
|
+
|
|
47
|
+
if (!firstDataReceived) {
|
|
48
|
+
firstDataReceived = true;
|
|
49
|
+
console.log(' 开始监听通知...');
|
|
50
|
+
|
|
51
|
+
// 等待2秒后进行数据库更新测试
|
|
52
|
+
setTimeout(testDatabaseUpdate, 2000);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(' 🎉 收到实时通知!Listen订阅工作正常!');
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
error: (error) => {
|
|
58
|
+
console.error('❌ Listen 订阅错误:', error);
|
|
59
|
+
if (error.find && error.find(e => e.message.includes('Cannot query field "listen"'))) {
|
|
60
|
+
console.error(' 🔍 PostGraphile没有启用simpleSubscriptions功能');
|
|
61
|
+
console.error(' 💡 需要在配置中添加 simpleSubscriptions: true');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// 3. 测试数据库更新和通知
|
|
68
|
+
async function testDatabaseUpdate() {
|
|
69
|
+
console.log('\n🔧 现在测试手动通知...');
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const client = await pgPool.connect();
|
|
73
|
+
|
|
74
|
+
// 发送PostGraphile格式的通知
|
|
75
|
+
console.log(' 发送 postgraphile:store_encounter 通知...');
|
|
76
|
+
await client.query(`SELECT pg_notify('postgraphile:store_encounter', '{}')`);
|
|
77
|
+
|
|
78
|
+
console.log(' 等待订阅响应...');
|
|
79
|
+
|
|
80
|
+
// 10秒后检查结果
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (updateCount <= 1) {
|
|
83
|
+
console.log('\n❌ 10秒内没有收到实时更新');
|
|
84
|
+
console.log(' 这说明PostGraphile的Listen订阅没有正确配置');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('\n📊 测试总结:');
|
|
88
|
+
console.log(` 收到更新次数: ${updateCount}`);
|
|
89
|
+
console.log(` Listen订阅: ${updateCount > 1 ? '✅ 工作正常' : '❌ 未工作'}`);
|
|
90
|
+
|
|
91
|
+
client.release();
|
|
92
|
+
dispose();
|
|
93
|
+
clientWs.dispose();
|
|
94
|
+
pgPool.end();
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}, 10000);
|
|
97
|
+
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('❌ 通知发送失败:', error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const clientWs = client;
|
|
104
|
+
|
|
105
|
+
// 手动退出处理
|
|
106
|
+
process.on('SIGINT', () => {
|
|
107
|
+
console.log('\n用户取消测试');
|
|
108
|
+
dispose();
|
|
109
|
+
clientWs.dispose();
|
|
110
|
+
pgPool.end();
|
|
111
|
+
process.exit(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('❌ 测试失败:', error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log('🔍 测试PostGraphile Listen订阅...');
|
|
121
|
+
testListenSubscription();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const { Pool } = require('pg');
|
|
2
|
+
|
|
3
|
+
const pgPool = new Pool({
|
|
4
|
+
connectionString: 'postgres://postgres:postgres@127.0.0.1:5432/postgres'
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
async function testDirectNotifications() {
|
|
8
|
+
console.log('🔍 测试PostgreSQL通知机制');
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const client = await pgPool.connect();
|
|
12
|
+
|
|
13
|
+
// 监听各种可能的通知频道
|
|
14
|
+
const channels = [
|
|
15
|
+
'postgraphile:store_encounter',
|
|
16
|
+
'postgraphile:ddl',
|
|
17
|
+
'table_change_store_encounter',
|
|
18
|
+
'table:store_encounter:change',
|
|
19
|
+
'store:all'
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
for (const channel of channels) {
|
|
23
|
+
await client.query(`LISTEN "${channel}"`);
|
|
24
|
+
console.log(`📡 监听频道: ${channel}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 设置通知监听器
|
|
28
|
+
client.on('notification', (msg) => {
|
|
29
|
+
console.log(`\n✅ 收到通知:`);
|
|
30
|
+
console.log(` 频道: ${msg.channel}`);
|
|
31
|
+
console.log(` 载荷: ${msg.payload}`);
|
|
32
|
+
try {
|
|
33
|
+
const data = JSON.parse(msg.payload);
|
|
34
|
+
console.log(` 解析数据:`, data);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.log(` (载荷不是JSON格式)`);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log('\n⏰ 正在监听通知...');
|
|
41
|
+
console.log('💡 在另一个终端中插入数据到store_encounter表来测试');
|
|
42
|
+
console.log('💡 或运行: psql postgres://postgres:postgres@127.0.0.1:5432/postgres');
|
|
43
|
+
console.log('💡 然后执行: INSERT INTO store_encounter (player, monster, exists, catch_attempts) VALUES (\'test\', \'test\', true, 0);');
|
|
44
|
+
console.log('\n按 Ctrl+C 停止监听');
|
|
45
|
+
|
|
46
|
+
// 保持连接
|
|
47
|
+
process.on('SIGINT', () => {
|
|
48
|
+
console.log('\n📴 停止监听通知');
|
|
49
|
+
client.release();
|
|
50
|
+
pgPool.end();
|
|
51
|
+
process.exit(0);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// 防止程序退出
|
|
55
|
+
await new Promise(() => {});
|
|
56
|
+
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('❌ 测试失败:', error);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
testDirectNotifications();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"removeComments": false,
|
|
17
|
+
"noImplicitAny": true,
|
|
18
|
+
"strictNullChecks": true,
|
|
19
|
+
"strictFunctionTypes": true,
|
|
20
|
+
"noImplicitReturns": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
"exactOptionalPropertyTypes": false,
|
|
24
|
+
"allowSyntheticDefaultImports": true
|
|
25
|
+
},
|
|
26
|
+
"include": ["src/**/*"],
|
|
27
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
|
28
|
+
}
|