@gokiteam/goki-dev 0.2.0
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 +478 -0
- package/bin/goki-dev.js +452 -0
- package/bin/mcp-server.js +16 -0
- package/bin/secrets-cli.js +302 -0
- package/cli/ComposeOverrideGenerator.js +226 -0
- package/cli/ComposeParser.js +73 -0
- package/cli/ConfigGenerator.js +304 -0
- package/cli/ConfigManager.js +46 -0
- package/cli/DatabaseManager.js +94 -0
- package/cli/DevToolsChecker.js +21 -0
- package/cli/DevToolsDir.js +66 -0
- package/cli/DevToolsManager.js +451 -0
- package/cli/DockerManager.js +138 -0
- package/cli/FunctionManager.js +95 -0
- package/cli/HttpProxyRewriter.js +91 -0
- package/cli/Logger.js +10 -0
- package/cli/McpConfigManager.js +123 -0
- package/cli/NgrokManager.js +431 -0
- package/cli/ProjectCLI.js +2322 -0
- package/cli/PubSubManager.js +129 -0
- package/cli/SnapshotManager.js +88 -0
- package/cli/UiFormatter.js +292 -0
- package/cli/WebhookUrlRewriter.js +32 -0
- package/cli/secrets/BiometricAuth.js +125 -0
- package/cli/secrets/SecretInjector.js +47 -0
- package/cli/secrets/SecretsConfig.js +141 -0
- package/cli/secrets/SecretsDoctor.js +384 -0
- package/cli/secrets/SecretsManager.js +255 -0
- package/client/dist/client.d.ts +332 -0
- package/client/dist/client.js +507 -0
- package/client/dist/helpers.d.ts +62 -0
- package/client/dist/helpers.js +122 -0
- package/client/dist/index.d.ts +59 -0
- package/client/dist/index.js +78 -0
- package/client/dist/package.json +1 -0
- package/client/dist/types.d.ts +280 -0
- package/client/dist/types.js +7 -0
- package/config.development +46 -0
- package/config.test +18 -0
- package/guidelines/CodingStyleGuideline.md +148 -0
- package/guidelines/CommentingGuideline.md +10 -0
- package/guidelines/HttpApiImplementationGuideline.md +137 -0
- package/guidelines/NamingGuideline.md +182 -0
- package/package.json +138 -0
- package/patterns/api/[collectionName]/Controllers.md +62 -0
- package/patterns/api/[collectionName]/Logic.md +154 -0
- package/patterns/api/[collectionName]/Permissions.md +81 -0
- package/patterns/api/[collectionName]/Router.md +83 -0
- package/patterns/api/[collectionName]/Schemas.md +197 -0
- package/patterns/configs/Patterns.md +7 -0
- package/patterns/enums/Patterns.md +24 -0
- package/patterns/errorHandling/Patterns.md +185 -0
- package/patterns/testing/Patterns.md +232 -0
- package/src/Server.js +238 -0
- package/src/api/dashboard/Controllers.js +9 -0
- package/src/api/dashboard/Logic.js +76 -0
- package/src/api/dashboard/Router.js +11 -0
- package/src/api/dashboard/Schemas.js +47 -0
- package/src/api/data/Controllers.js +26 -0
- package/src/api/data/Logic.js +188 -0
- package/src/api/data/Router.js +16 -0
- package/src/api/docker/Controllers.js +33 -0
- package/src/api/docker/Logic.js +268 -0
- package/src/api/docker/Router.js +15 -0
- package/src/api/docker/Schemas.js +80 -0
- package/src/api/docs/Controllers.js +15 -0
- package/src/api/docs/Logic.js +85 -0
- package/src/api/docs/Router.js +12 -0
- package/src/api/export/Controllers.js +30 -0
- package/src/api/export/Logic.js +143 -0
- package/src/api/export/Router.js +18 -0
- package/src/api/export/Schemas.js +104 -0
- package/src/api/firestore/Controllers.js +152 -0
- package/src/api/firestore/Logic.js +474 -0
- package/src/api/firestore/Router.js +23 -0
- package/src/api/functions/Controllers.js +261 -0
- package/src/api/functions/Logic.js +710 -0
- package/src/api/functions/Router.js +50 -0
- package/src/api/functions/Schemas.js +193 -0
- package/src/api/gateway/Controllers.js +72 -0
- package/src/api/gateway/Logic.js +74 -0
- package/src/api/gateway/Router.js +10 -0
- package/src/api/gateway/Schemas.js +19 -0
- package/src/api/health/Controllers.js +14 -0
- package/src/api/health/Logic.js +24 -0
- package/src/api/health/Router.js +12 -0
- package/src/api/httpTraffic/Controllers.js +29 -0
- package/src/api/httpTraffic/Logic.js +33 -0
- package/src/api/httpTraffic/Router.js +9 -0
- package/src/api/httpTraffic/Schemas.js +23 -0
- package/src/api/logging/Controllers.js +80 -0
- package/src/api/logging/Logic.js +461 -0
- package/src/api/logging/Router.js +24 -0
- package/src/api/logging/Schemas.js +43 -0
- package/src/api/mqtt/Controllers.js +17 -0
- package/src/api/mqtt/Logic.js +66 -0
- package/src/api/mqtt/Router.js +12 -0
- package/src/api/postgres/Controllers.js +97 -0
- package/src/api/postgres/Logic.js +221 -0
- package/src/api/postgres/Router.js +21 -0
- package/src/api/pubsub/Controllers.js +236 -0
- package/src/api/pubsub/Logic.js +732 -0
- package/src/api/pubsub/Router.js +41 -0
- package/src/api/pubsub/Schemas.js +355 -0
- package/src/api/redis/Controllers.js +63 -0
- package/src/api/redis/Logic.js +239 -0
- package/src/api/redis/Router.js +21 -0
- package/src/api/scheduler/Controllers.js +27 -0
- package/src/api/scheduler/Logic.js +49 -0
- package/src/api/scheduler/Router.js +16 -0
- package/src/api/services/Controllers.js +26 -0
- package/src/api/services/Logic.js +205 -0
- package/src/api/services/Router.js +14 -0
- package/src/api/services/Schemas.js +66 -0
- package/src/api/snapshots/Controllers.js +37 -0
- package/src/api/snapshots/Logic.js +797 -0
- package/src/api/snapshots/Router.js +15 -0
- package/src/api/snapshots/Schemas.js +23 -0
- package/src/api/webhooks/Controllers.js +49 -0
- package/src/api/webhooks/Logic.js +137 -0
- package/src/api/webhooks/Router.js +12 -0
- package/src/api/webhooks/Schemas.js +31 -0
- package/src/configs/Application.js +147 -0
- package/src/configs/Default.js +13 -0
- package/src/consumers/BlackboxLogsConsumer.js +235 -0
- package/src/consumers/DockerLogsConsumer.js +687 -0
- package/src/db/Tables.js +66 -0
- package/src/db/schemas/firestore.js +18 -0
- package/src/db/schemas/functions.js +65 -0
- package/src/db/schemas/httpTraffic.js +43 -0
- package/src/db/schemas/logging.js +74 -0
- package/src/db/schemas/migrations.js +64 -0
- package/src/db/schemas/mqtt.js +56 -0
- package/src/db/schemas/pubsub.js +90 -0
- package/src/db/schemas/pubsubRegistry.js +22 -0
- package/src/db/schemas/webhooks.js +28 -0
- package/src/emulation/awsiot/Controllers.js +91 -0
- package/src/emulation/awsiot/Logic.js +70 -0
- package/src/emulation/awsiot/Router.js +19 -0
- package/src/emulation/awsiot/Server.js +100 -0
- package/src/emulation/firestore/Server.js +136 -0
- package/src/emulation/logging/Controllers.js +212 -0
- package/src/emulation/logging/Logic.js +416 -0
- package/src/emulation/logging/Router.js +36 -0
- package/src/emulation/logging/Schemas.js +82 -0
- package/src/emulation/logging/Server.js +108 -0
- package/src/emulation/pubsub/Controllers.js +279 -0
- package/src/emulation/pubsub/DefaultTopics.js +162 -0
- package/src/emulation/pubsub/Logic.js +427 -0
- package/src/emulation/pubsub/README.md +309 -0
- package/src/emulation/pubsub/Router.js +33 -0
- package/src/emulation/pubsub/Server.js +104 -0
- package/src/emulation/pubsub/ShadowPoller.js +276 -0
- package/src/emulation/pubsub/ShadowSubscriptionManager.js +199 -0
- package/src/enums/ContainerNames.js +106 -0
- package/src/enums/ErrorReason.js +28 -0
- package/src/enums/FunctionStatuses.js +15 -0
- package/src/enums/FunctionTriggerTypes.js +15 -0
- package/src/enums/GatewayState.js +7 -0
- package/src/enums/ServiceNames.js +68 -0
- package/src/jobs/DatabaseMaintenance.js +184 -0
- package/src/jobs/MessageHistoryCleanup.js +152 -0
- package/src/mcp/ApiClient.js +25 -0
- package/src/mcp/Server.js +52 -0
- package/src/mcp/prompts/debugging.js +104 -0
- package/src/mcp/resources/platform.js +118 -0
- package/src/mcp/tools/data.js +84 -0
- package/src/mcp/tools/docker.js +166 -0
- package/src/mcp/tools/firestore.js +162 -0
- package/src/mcp/tools/functions.js +380 -0
- package/src/mcp/tools/httpTraffic.js +69 -0
- package/src/mcp/tools/logging.js +174 -0
- package/src/mcp/tools/mqtt.js +37 -0
- package/src/mcp/tools/postgres.js +130 -0
- package/src/mcp/tools/pubsub.js +316 -0
- package/src/mcp/tools/redis.js +146 -0
- package/src/mcp/tools/services.js +169 -0
- package/src/mcp/tools/snapshots.js +88 -0
- package/src/mcp/tools/webhooks.js +115 -0
- package/src/middleware/DevProxy.js +67 -0
- package/src/middleware/ErrorCatcher.js +35 -0
- package/src/middleware/HttpProxy.js +215 -0
- package/src/middleware/Reply.js +24 -0
- package/src/middleware/TraceId.js +9 -0
- package/src/middleware/WebhookProxy.js +234 -0
- package/src/protocols/mqtt/Broker.js +92 -0
- package/src/protocols/mqtt/Handlers.js +175 -0
- package/src/protocols/mqtt/PubSubBridge.js +162 -0
- package/src/protocols/mqtt/Server.js +116 -0
- package/src/runtime/FunctionRunner.js +179 -0
- package/src/services/AppGatewayService.js +582 -0
- package/src/singletons/FirestoreBroadcaster.js +367 -0
- package/src/singletons/FunctionTriggerDispatcher.js +456 -0
- package/src/singletons/FunctionsService.js +418 -0
- package/src/singletons/HttpProxy.js +224 -0
- package/src/singletons/LogBroadcaster.js +159 -0
- package/src/singletons/Logger.js +49 -0
- package/src/singletons/MemoryJsonStore.js +175 -0
- package/src/singletons/MessageBroadcaster.js +190 -0
- package/src/singletons/PostgresBroadcaster.js +367 -0
- package/src/singletons/PostgresClient.js +180 -0
- package/src/singletons/RedisClient.js +184 -0
- package/src/singletons/SqliteStore.js +480 -0
- package/src/singletons/TickService.js +151 -0
- package/src/singletons/WebhookProxy.js +223 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import KoaRouter from 'koa-router'
|
|
2
|
+
import { publish } from './Controllers.js'
|
|
3
|
+
|
|
4
|
+
const router = new KoaRouter()
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* AWS IoT Core HTTPS API emulation routes
|
|
8
|
+
*
|
|
9
|
+
* Mimics: https://docs.aws.amazon.com/iot/latest/developerguide/mqtt-publish-over-https.html
|
|
10
|
+
*
|
|
11
|
+
* POST /topics/:topicName?qos=1
|
|
12
|
+
* - Publishes a message to the specified MQTT topic
|
|
13
|
+
* - Binary payload in request body
|
|
14
|
+
* - Returns empty 200 response
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
router.post('/topics/:topicName', publish)
|
|
18
|
+
|
|
19
|
+
export { router as Router }
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Koa from 'koa'
|
|
2
|
+
import bodyParser from 'koa-bodyparser'
|
|
3
|
+
import { Application } from '../../configs/Application.js'
|
|
4
|
+
import { Logger } from '../../singletons/Logger.js'
|
|
5
|
+
import { Router } from './Router.js'
|
|
6
|
+
|
|
7
|
+
const { environment, runId, ports } = Application
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Start AWS IoT Core HTTPS API emulation server
|
|
11
|
+
*
|
|
12
|
+
* Mimics AWS IoT Core HTTPS publishing API
|
|
13
|
+
* POST /topics/{topicName}?qos=1
|
|
14
|
+
*
|
|
15
|
+
* This allows backend services (device-simulator, device-native) to publish
|
|
16
|
+
* messages to the MQTT broker using the same HTTPS API they use in production.
|
|
17
|
+
*/
|
|
18
|
+
export const startAwsIotServer = async () => {
|
|
19
|
+
try {
|
|
20
|
+
const app = new Koa()
|
|
21
|
+
|
|
22
|
+
// Error handler
|
|
23
|
+
app.use(async (ctx, next) => {
|
|
24
|
+
try {
|
|
25
|
+
await next()
|
|
26
|
+
} catch (error) {
|
|
27
|
+
Logger.log({
|
|
28
|
+
level: 'error',
|
|
29
|
+
message: 'AWS IoT server error',
|
|
30
|
+
data: { error: error.message, stack: error.stack, path: ctx.path }
|
|
31
|
+
})
|
|
32
|
+
ctx.status = error.status || 500
|
|
33
|
+
ctx.body = {
|
|
34
|
+
error: {
|
|
35
|
+
code: ctx.status,
|
|
36
|
+
message: error.message || 'Internal server error',
|
|
37
|
+
status: 'INTERNAL'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Body parser with raw binary support
|
|
44
|
+
app.use(bodyParser({
|
|
45
|
+
enableTypes: ['json', 'form', 'text'],
|
|
46
|
+
extendTypes: {
|
|
47
|
+
text: ['application/octet-stream']
|
|
48
|
+
},
|
|
49
|
+
// Parse binary payloads as Buffer
|
|
50
|
+
onerror: (err, ctx) => {
|
|
51
|
+
Logger.log({
|
|
52
|
+
level: 'error',
|
|
53
|
+
message: 'Body parser error',
|
|
54
|
+
data: { error: err.message, path: ctx.path }
|
|
55
|
+
})
|
|
56
|
+
ctx.throw(422, 'Body parse error')
|
|
57
|
+
}
|
|
58
|
+
}))
|
|
59
|
+
|
|
60
|
+
// Custom middleware to handle raw binary payloads
|
|
61
|
+
app.use(async (ctx, next) => {
|
|
62
|
+
if (ctx.request.is('application/octet-stream') || ctx.path.startsWith('/topics/')) {
|
|
63
|
+
// Read raw body as Buffer
|
|
64
|
+
const chunks = []
|
|
65
|
+
for await (const chunk of ctx.req) {
|
|
66
|
+
chunks.push(chunk)
|
|
67
|
+
}
|
|
68
|
+
ctx.request.body = Buffer.concat(chunks)
|
|
69
|
+
}
|
|
70
|
+
await next()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Register routes
|
|
74
|
+
app.use(Router.routes())
|
|
75
|
+
app.use(Router.allowedMethods())
|
|
76
|
+
|
|
77
|
+
// Start server
|
|
78
|
+
const server = app.listen(ports.awsIot, () => {
|
|
79
|
+
Logger.log({
|
|
80
|
+
level: 'info',
|
|
81
|
+
message: 'AWS IoT Core HTTPS API emulation server started',
|
|
82
|
+
data: {
|
|
83
|
+
port: ports.awsIot,
|
|
84
|
+
environment,
|
|
85
|
+
runId,
|
|
86
|
+
endpoint: `http://localhost:${ports.awsIot}/topics/:topicName?qos=1`
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return server
|
|
92
|
+
} catch (error) {
|
|
93
|
+
Logger.log({
|
|
94
|
+
level: 'error',
|
|
95
|
+
message: 'Failed to start AWS IoT server',
|
|
96
|
+
data: { error: error.message, stack: error.stack }
|
|
97
|
+
})
|
|
98
|
+
throw error
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { spawn } from 'child_process'
|
|
2
|
+
import { Application } from '../../configs/Application.js'
|
|
3
|
+
import { Logger } from '../../singletons/Logger.js'
|
|
4
|
+
import { SqliteStore } from '../../singletons/SqliteStore.js'
|
|
5
|
+
|
|
6
|
+
class FirestoreEmulatorClass {
|
|
7
|
+
constructor () {
|
|
8
|
+
this.process = null
|
|
9
|
+
this.isRunning = false
|
|
10
|
+
this.port = Application.ports.firestore || 8080
|
|
11
|
+
this.projectId = Application.firestore.projectId
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async start () {
|
|
15
|
+
if (this.isRunning) {
|
|
16
|
+
Logger.log({
|
|
17
|
+
level: 'warn',
|
|
18
|
+
message: 'Firestore emulator already running'
|
|
19
|
+
})
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
this.registerStorageCollections()
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
this.process = spawn('firebase', [
|
|
25
|
+
'emulators:start',
|
|
26
|
+
'--only', 'firestore',
|
|
27
|
+
'--project', this.projectId
|
|
28
|
+
], {
|
|
29
|
+
env: {
|
|
30
|
+
...process.env,
|
|
31
|
+
FIRESTORE_EMULATOR_PORT: this.port
|
|
32
|
+
},
|
|
33
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
34
|
+
})
|
|
35
|
+
const startupTimeout = setTimeout(() => {
|
|
36
|
+
if (!this.isRunning) {
|
|
37
|
+
Logger.log({
|
|
38
|
+
level: 'error',
|
|
39
|
+
message: 'Firestore emulator failed to start within 30 seconds'
|
|
40
|
+
})
|
|
41
|
+
reject(new Error('Firestore emulator startup timeout'))
|
|
42
|
+
}
|
|
43
|
+
}, 30000)
|
|
44
|
+
this.process.stdout.on('data', (data) => {
|
|
45
|
+
const message = data.toString()
|
|
46
|
+
if (message.includes('Firestore Emulator running') || message.includes('All emulators ready')) {
|
|
47
|
+
clearTimeout(startupTimeout)
|
|
48
|
+
this.isRunning = true
|
|
49
|
+
Logger.log({
|
|
50
|
+
level: 'info',
|
|
51
|
+
message: `Firestore emulator started on port ${this.port}`,
|
|
52
|
+
data: { port: this.port, projectId: this.projectId }
|
|
53
|
+
})
|
|
54
|
+
resolve()
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
this.process.stderr.on('data', (data) => {
|
|
58
|
+
const error = data.toString()
|
|
59
|
+
if (!this.isRunning && error.includes('error')) {
|
|
60
|
+
Logger.log({
|
|
61
|
+
level: 'error',
|
|
62
|
+
message: 'Firestore emulator error during startup',
|
|
63
|
+
data: { error }
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
this.process.on('error', (error) => {
|
|
68
|
+
clearTimeout(startupTimeout)
|
|
69
|
+
Logger.log({
|
|
70
|
+
level: 'error',
|
|
71
|
+
message: 'Failed to start Firestore emulator process',
|
|
72
|
+
data: { error: error.message }
|
|
73
|
+
})
|
|
74
|
+
reject(error)
|
|
75
|
+
})
|
|
76
|
+
this.process.on('exit', (code) => {
|
|
77
|
+
this.isRunning = false
|
|
78
|
+
if (code !== 0 && code !== null) {
|
|
79
|
+
Logger.log({
|
|
80
|
+
level: 'error',
|
|
81
|
+
message: 'Firestore emulator process exited unexpectedly',
|
|
82
|
+
data: { exitCode: code }
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
registerStorageCollections () {
|
|
90
|
+
// No-op for SQLite - tables created at DB initialization
|
|
91
|
+
Logger.log({
|
|
92
|
+
level: 'debug',
|
|
93
|
+
message: 'Firestore storage tables ready (SQLite)',
|
|
94
|
+
data: { tables: ['firestore_metadata'] }
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async stop () {
|
|
99
|
+
if (!this.isRunning || !this.process) {
|
|
100
|
+
Logger.log({
|
|
101
|
+
level: 'warn',
|
|
102
|
+
message: 'Firestore emulator not running'
|
|
103
|
+
})
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
this.process.on('close', () => {
|
|
108
|
+
this.isRunning = false
|
|
109
|
+
Logger.log({
|
|
110
|
+
level: 'info',
|
|
111
|
+
message: 'Firestore emulator stopped'
|
|
112
|
+
})
|
|
113
|
+
resolve()
|
|
114
|
+
})
|
|
115
|
+
this.process.kill('SIGTERM')
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
if (this.process && !this.process.killed) {
|
|
118
|
+
this.process.kill('SIGKILL')
|
|
119
|
+
resolve()
|
|
120
|
+
}
|
|
121
|
+
}, 5000)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
getStatus () {
|
|
126
|
+
return {
|
|
127
|
+
running: this.isRunning,
|
|
128
|
+
port: this.port,
|
|
129
|
+
projectId: this.projectId
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const FirestoreEmulator = new FirestoreEmulatorClass()
|
|
135
|
+
export const start = () => FirestoreEmulator.start()
|
|
136
|
+
export const stop = () => FirestoreEmulator.stop()
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { Logic } from './Logic.js'
|
|
2
|
+
import {
|
|
3
|
+
WriteEntriesRequestSchema,
|
|
4
|
+
ListEntriesRequestSchema,
|
|
5
|
+
DeleteLogRequestSchema,
|
|
6
|
+
ListLogsRequestSchema
|
|
7
|
+
} from './Schemas.js'
|
|
8
|
+
import { Logger } from '../../singletons/Logger.js'
|
|
9
|
+
|
|
10
|
+
export const Controllers = {
|
|
11
|
+
/**
|
|
12
|
+
* POST /v2/entries:write
|
|
13
|
+
* Write log entries
|
|
14
|
+
*/
|
|
15
|
+
async writeEntries (ctx) {
|
|
16
|
+
const { traceId } = ctx.state
|
|
17
|
+
|
|
18
|
+
// Validate request body
|
|
19
|
+
const { error, value } = WriteEntriesRequestSchema.validate(ctx.request.body)
|
|
20
|
+
if (error) {
|
|
21
|
+
ctx.status = 400
|
|
22
|
+
ctx.body = {
|
|
23
|
+
error: {
|
|
24
|
+
code: 400,
|
|
25
|
+
message: 'Invalid request',
|
|
26
|
+
status: 'INVALID_ARGUMENT',
|
|
27
|
+
details: error.details.map(d => d.message)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const result = await Logic.writeEntries({
|
|
35
|
+
traceId,
|
|
36
|
+
...value
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
ctx.status = 200
|
|
40
|
+
ctx.body = result
|
|
41
|
+
} catch (error) {
|
|
42
|
+
Logger.log({
|
|
43
|
+
level: 'error',
|
|
44
|
+
message: 'Failed to write entries',
|
|
45
|
+
data: { traceId, error: error.message, stack: error.stack }
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
ctx.status = 500
|
|
49
|
+
ctx.body = {
|
|
50
|
+
error: {
|
|
51
|
+
code: 500,
|
|
52
|
+
message: 'Internal server error',
|
|
53
|
+
status: 'INTERNAL'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* POST /v2/entries:list
|
|
61
|
+
* List log entries
|
|
62
|
+
*/
|
|
63
|
+
async listEntries (ctx) {
|
|
64
|
+
const { traceId } = ctx.state
|
|
65
|
+
|
|
66
|
+
// Validate request body
|
|
67
|
+
const { error, value } = ListEntriesRequestSchema.validate(ctx.request.body)
|
|
68
|
+
if (error) {
|
|
69
|
+
ctx.status = 400
|
|
70
|
+
ctx.body = {
|
|
71
|
+
error: {
|
|
72
|
+
code: 400,
|
|
73
|
+
message: 'Invalid request',
|
|
74
|
+
status: 'INVALID_ARGUMENT',
|
|
75
|
+
details: error.details.map(d => d.message)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const result = await Logic.listEntries({
|
|
83
|
+
traceId,
|
|
84
|
+
...value
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
ctx.status = 200
|
|
88
|
+
ctx.body = result
|
|
89
|
+
} catch (error) {
|
|
90
|
+
Logger.log({
|
|
91
|
+
level: 'error',
|
|
92
|
+
message: 'Failed to list entries',
|
|
93
|
+
data: { traceId, error: error.message, stack: error.stack }
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
ctx.status = 500
|
|
97
|
+
ctx.body = {
|
|
98
|
+
error: {
|
|
99
|
+
code: 500,
|
|
100
|
+
message: 'Internal server error',
|
|
101
|
+
status: 'INTERNAL'
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* GET /v2/projects/{project}/logs
|
|
109
|
+
* List all logs for a project
|
|
110
|
+
*/
|
|
111
|
+
async listLogs (ctx) {
|
|
112
|
+
const { traceId } = ctx.state
|
|
113
|
+
const { project } = ctx.params
|
|
114
|
+
const { pageSize, pageToken } = ctx.query
|
|
115
|
+
|
|
116
|
+
// Validate request
|
|
117
|
+
const { error, value } = ListLogsRequestSchema.validate({
|
|
118
|
+
project,
|
|
119
|
+
pageSize: pageSize ? parseInt(pageSize) : undefined,
|
|
120
|
+
pageToken
|
|
121
|
+
})
|
|
122
|
+
if (error) {
|
|
123
|
+
ctx.status = 400
|
|
124
|
+
ctx.body = {
|
|
125
|
+
error: {
|
|
126
|
+
code: 400,
|
|
127
|
+
message: 'Invalid request',
|
|
128
|
+
status: 'INVALID_ARGUMENT',
|
|
129
|
+
details: error.details.map(d => d.message)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const result = await Logic.listLogs({
|
|
137
|
+
traceId,
|
|
138
|
+
...value
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
ctx.status = 200
|
|
142
|
+
ctx.body = result
|
|
143
|
+
} catch (error) {
|
|
144
|
+
Logger.log({
|
|
145
|
+
level: 'error',
|
|
146
|
+
message: 'Failed to list logs',
|
|
147
|
+
data: { traceId, error: error.message, stack: error.stack }
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
ctx.status = 500
|
|
151
|
+
ctx.body = {
|
|
152
|
+
error: {
|
|
153
|
+
code: 500,
|
|
154
|
+
message: 'Internal server error',
|
|
155
|
+
status: 'INTERNAL'
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* DELETE /v2/projects/{project}/logs/{logId}
|
|
163
|
+
* Delete a log
|
|
164
|
+
*/
|
|
165
|
+
async deleteLog (ctx) {
|
|
166
|
+
const { traceId } = ctx.state
|
|
167
|
+
const { project, logId } = ctx.params
|
|
168
|
+
|
|
169
|
+
// Validate request
|
|
170
|
+
const { error, value } = DeleteLogRequestSchema.validate({
|
|
171
|
+
project,
|
|
172
|
+
logId: decodeURIComponent(logId) // Log IDs may be URL-encoded
|
|
173
|
+
})
|
|
174
|
+
if (error) {
|
|
175
|
+
ctx.status = 400
|
|
176
|
+
ctx.body = {
|
|
177
|
+
error: {
|
|
178
|
+
code: 400,
|
|
179
|
+
message: 'Invalid request',
|
|
180
|
+
status: 'INVALID_ARGUMENT',
|
|
181
|
+
details: error.details.map(d => d.message)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const result = await Logic.deleteLog({
|
|
189
|
+
traceId,
|
|
190
|
+
...value
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
ctx.status = 200
|
|
194
|
+
ctx.body = result
|
|
195
|
+
} catch (error) {
|
|
196
|
+
Logger.log({
|
|
197
|
+
level: 'error',
|
|
198
|
+
message: 'Failed to delete log',
|
|
199
|
+
data: { traceId, error: error.message, stack: error.stack }
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
ctx.status = 500
|
|
203
|
+
ctx.body = {
|
|
204
|
+
error: {
|
|
205
|
+
code: 500,
|
|
206
|
+
message: 'Internal server error',
|
|
207
|
+
status: 'INTERNAL'
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|