@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.
Files changed (205) hide show
  1. package/README.md +478 -0
  2. package/bin/goki-dev.js +452 -0
  3. package/bin/mcp-server.js +16 -0
  4. package/bin/secrets-cli.js +302 -0
  5. package/cli/ComposeOverrideGenerator.js +226 -0
  6. package/cli/ComposeParser.js +73 -0
  7. package/cli/ConfigGenerator.js +304 -0
  8. package/cli/ConfigManager.js +46 -0
  9. package/cli/DatabaseManager.js +94 -0
  10. package/cli/DevToolsChecker.js +21 -0
  11. package/cli/DevToolsDir.js +66 -0
  12. package/cli/DevToolsManager.js +451 -0
  13. package/cli/DockerManager.js +138 -0
  14. package/cli/FunctionManager.js +95 -0
  15. package/cli/HttpProxyRewriter.js +91 -0
  16. package/cli/Logger.js +10 -0
  17. package/cli/McpConfigManager.js +123 -0
  18. package/cli/NgrokManager.js +431 -0
  19. package/cli/ProjectCLI.js +2322 -0
  20. package/cli/PubSubManager.js +129 -0
  21. package/cli/SnapshotManager.js +88 -0
  22. package/cli/UiFormatter.js +292 -0
  23. package/cli/WebhookUrlRewriter.js +32 -0
  24. package/cli/secrets/BiometricAuth.js +125 -0
  25. package/cli/secrets/SecretInjector.js +47 -0
  26. package/cli/secrets/SecretsConfig.js +141 -0
  27. package/cli/secrets/SecretsDoctor.js +384 -0
  28. package/cli/secrets/SecretsManager.js +255 -0
  29. package/client/dist/client.d.ts +332 -0
  30. package/client/dist/client.js +507 -0
  31. package/client/dist/helpers.d.ts +62 -0
  32. package/client/dist/helpers.js +122 -0
  33. package/client/dist/index.d.ts +59 -0
  34. package/client/dist/index.js +78 -0
  35. package/client/dist/package.json +1 -0
  36. package/client/dist/types.d.ts +280 -0
  37. package/client/dist/types.js +7 -0
  38. package/config.development +46 -0
  39. package/config.test +18 -0
  40. package/guidelines/CodingStyleGuideline.md +148 -0
  41. package/guidelines/CommentingGuideline.md +10 -0
  42. package/guidelines/HttpApiImplementationGuideline.md +137 -0
  43. package/guidelines/NamingGuideline.md +182 -0
  44. package/package.json +138 -0
  45. package/patterns/api/[collectionName]/Controllers.md +62 -0
  46. package/patterns/api/[collectionName]/Logic.md +154 -0
  47. package/patterns/api/[collectionName]/Permissions.md +81 -0
  48. package/patterns/api/[collectionName]/Router.md +83 -0
  49. package/patterns/api/[collectionName]/Schemas.md +197 -0
  50. package/patterns/configs/Patterns.md +7 -0
  51. package/patterns/enums/Patterns.md +24 -0
  52. package/patterns/errorHandling/Patterns.md +185 -0
  53. package/patterns/testing/Patterns.md +232 -0
  54. package/src/Server.js +238 -0
  55. package/src/api/dashboard/Controllers.js +9 -0
  56. package/src/api/dashboard/Logic.js +76 -0
  57. package/src/api/dashboard/Router.js +11 -0
  58. package/src/api/dashboard/Schemas.js +47 -0
  59. package/src/api/data/Controllers.js +26 -0
  60. package/src/api/data/Logic.js +188 -0
  61. package/src/api/data/Router.js +16 -0
  62. package/src/api/docker/Controllers.js +33 -0
  63. package/src/api/docker/Logic.js +268 -0
  64. package/src/api/docker/Router.js +15 -0
  65. package/src/api/docker/Schemas.js +80 -0
  66. package/src/api/docs/Controllers.js +15 -0
  67. package/src/api/docs/Logic.js +85 -0
  68. package/src/api/docs/Router.js +12 -0
  69. package/src/api/export/Controllers.js +30 -0
  70. package/src/api/export/Logic.js +143 -0
  71. package/src/api/export/Router.js +18 -0
  72. package/src/api/export/Schemas.js +104 -0
  73. package/src/api/firestore/Controllers.js +152 -0
  74. package/src/api/firestore/Logic.js +474 -0
  75. package/src/api/firestore/Router.js +23 -0
  76. package/src/api/functions/Controllers.js +261 -0
  77. package/src/api/functions/Logic.js +710 -0
  78. package/src/api/functions/Router.js +50 -0
  79. package/src/api/functions/Schemas.js +193 -0
  80. package/src/api/gateway/Controllers.js +72 -0
  81. package/src/api/gateway/Logic.js +74 -0
  82. package/src/api/gateway/Router.js +10 -0
  83. package/src/api/gateway/Schemas.js +19 -0
  84. package/src/api/health/Controllers.js +14 -0
  85. package/src/api/health/Logic.js +24 -0
  86. package/src/api/health/Router.js +12 -0
  87. package/src/api/httpTraffic/Controllers.js +29 -0
  88. package/src/api/httpTraffic/Logic.js +33 -0
  89. package/src/api/httpTraffic/Router.js +9 -0
  90. package/src/api/httpTraffic/Schemas.js +23 -0
  91. package/src/api/logging/Controllers.js +80 -0
  92. package/src/api/logging/Logic.js +461 -0
  93. package/src/api/logging/Router.js +24 -0
  94. package/src/api/logging/Schemas.js +43 -0
  95. package/src/api/mqtt/Controllers.js +17 -0
  96. package/src/api/mqtt/Logic.js +66 -0
  97. package/src/api/mqtt/Router.js +12 -0
  98. package/src/api/postgres/Controllers.js +97 -0
  99. package/src/api/postgres/Logic.js +221 -0
  100. package/src/api/postgres/Router.js +21 -0
  101. package/src/api/pubsub/Controllers.js +236 -0
  102. package/src/api/pubsub/Logic.js +732 -0
  103. package/src/api/pubsub/Router.js +41 -0
  104. package/src/api/pubsub/Schemas.js +355 -0
  105. package/src/api/redis/Controllers.js +63 -0
  106. package/src/api/redis/Logic.js +239 -0
  107. package/src/api/redis/Router.js +21 -0
  108. package/src/api/scheduler/Controllers.js +27 -0
  109. package/src/api/scheduler/Logic.js +49 -0
  110. package/src/api/scheduler/Router.js +16 -0
  111. package/src/api/services/Controllers.js +26 -0
  112. package/src/api/services/Logic.js +205 -0
  113. package/src/api/services/Router.js +14 -0
  114. package/src/api/services/Schemas.js +66 -0
  115. package/src/api/snapshots/Controllers.js +37 -0
  116. package/src/api/snapshots/Logic.js +797 -0
  117. package/src/api/snapshots/Router.js +15 -0
  118. package/src/api/snapshots/Schemas.js +23 -0
  119. package/src/api/webhooks/Controllers.js +49 -0
  120. package/src/api/webhooks/Logic.js +137 -0
  121. package/src/api/webhooks/Router.js +12 -0
  122. package/src/api/webhooks/Schemas.js +31 -0
  123. package/src/configs/Application.js +147 -0
  124. package/src/configs/Default.js +13 -0
  125. package/src/consumers/BlackboxLogsConsumer.js +235 -0
  126. package/src/consumers/DockerLogsConsumer.js +687 -0
  127. package/src/db/Tables.js +66 -0
  128. package/src/db/schemas/firestore.js +18 -0
  129. package/src/db/schemas/functions.js +65 -0
  130. package/src/db/schemas/httpTraffic.js +43 -0
  131. package/src/db/schemas/logging.js +74 -0
  132. package/src/db/schemas/migrations.js +64 -0
  133. package/src/db/schemas/mqtt.js +56 -0
  134. package/src/db/schemas/pubsub.js +90 -0
  135. package/src/db/schemas/pubsubRegistry.js +22 -0
  136. package/src/db/schemas/webhooks.js +28 -0
  137. package/src/emulation/awsiot/Controllers.js +91 -0
  138. package/src/emulation/awsiot/Logic.js +70 -0
  139. package/src/emulation/awsiot/Router.js +19 -0
  140. package/src/emulation/awsiot/Server.js +100 -0
  141. package/src/emulation/firestore/Server.js +136 -0
  142. package/src/emulation/logging/Controllers.js +212 -0
  143. package/src/emulation/logging/Logic.js +416 -0
  144. package/src/emulation/logging/Router.js +36 -0
  145. package/src/emulation/logging/Schemas.js +82 -0
  146. package/src/emulation/logging/Server.js +108 -0
  147. package/src/emulation/pubsub/Controllers.js +279 -0
  148. package/src/emulation/pubsub/DefaultTopics.js +162 -0
  149. package/src/emulation/pubsub/Logic.js +427 -0
  150. package/src/emulation/pubsub/README.md +309 -0
  151. package/src/emulation/pubsub/Router.js +33 -0
  152. package/src/emulation/pubsub/Server.js +104 -0
  153. package/src/emulation/pubsub/ShadowPoller.js +276 -0
  154. package/src/emulation/pubsub/ShadowSubscriptionManager.js +199 -0
  155. package/src/enums/ContainerNames.js +106 -0
  156. package/src/enums/ErrorReason.js +28 -0
  157. package/src/enums/FunctionStatuses.js +15 -0
  158. package/src/enums/FunctionTriggerTypes.js +15 -0
  159. package/src/enums/GatewayState.js +7 -0
  160. package/src/enums/ServiceNames.js +68 -0
  161. package/src/jobs/DatabaseMaintenance.js +184 -0
  162. package/src/jobs/MessageHistoryCleanup.js +152 -0
  163. package/src/mcp/ApiClient.js +25 -0
  164. package/src/mcp/Server.js +52 -0
  165. package/src/mcp/prompts/debugging.js +104 -0
  166. package/src/mcp/resources/platform.js +118 -0
  167. package/src/mcp/tools/data.js +84 -0
  168. package/src/mcp/tools/docker.js +166 -0
  169. package/src/mcp/tools/firestore.js +162 -0
  170. package/src/mcp/tools/functions.js +380 -0
  171. package/src/mcp/tools/httpTraffic.js +69 -0
  172. package/src/mcp/tools/logging.js +174 -0
  173. package/src/mcp/tools/mqtt.js +37 -0
  174. package/src/mcp/tools/postgres.js +130 -0
  175. package/src/mcp/tools/pubsub.js +316 -0
  176. package/src/mcp/tools/redis.js +146 -0
  177. package/src/mcp/tools/services.js +169 -0
  178. package/src/mcp/tools/snapshots.js +88 -0
  179. package/src/mcp/tools/webhooks.js +115 -0
  180. package/src/middleware/DevProxy.js +67 -0
  181. package/src/middleware/ErrorCatcher.js +35 -0
  182. package/src/middleware/HttpProxy.js +215 -0
  183. package/src/middleware/Reply.js +24 -0
  184. package/src/middleware/TraceId.js +9 -0
  185. package/src/middleware/WebhookProxy.js +234 -0
  186. package/src/protocols/mqtt/Broker.js +92 -0
  187. package/src/protocols/mqtt/Handlers.js +175 -0
  188. package/src/protocols/mqtt/PubSubBridge.js +162 -0
  189. package/src/protocols/mqtt/Server.js +116 -0
  190. package/src/runtime/FunctionRunner.js +179 -0
  191. package/src/services/AppGatewayService.js +582 -0
  192. package/src/singletons/FirestoreBroadcaster.js +367 -0
  193. package/src/singletons/FunctionTriggerDispatcher.js +456 -0
  194. package/src/singletons/FunctionsService.js +418 -0
  195. package/src/singletons/HttpProxy.js +224 -0
  196. package/src/singletons/LogBroadcaster.js +159 -0
  197. package/src/singletons/Logger.js +49 -0
  198. package/src/singletons/MemoryJsonStore.js +175 -0
  199. package/src/singletons/MessageBroadcaster.js +190 -0
  200. package/src/singletons/PostgresBroadcaster.js +367 -0
  201. package/src/singletons/PostgresClient.js +180 -0
  202. package/src/singletons/RedisClient.js +184 -0
  203. package/src/singletons/SqliteStore.js +480 -0
  204. package/src/singletons/TickService.js +151 -0
  205. package/src/singletons/WebhookProxy.js +223 -0
@@ -0,0 +1,116 @@
1
+ import net from 'net'
2
+ import Moment from 'moment'
3
+ import { Application } from '../../configs/Application.js'
4
+ import { Logger } from '../../singletons/Logger.js'
5
+ import { SqliteStore } from '../../singletons/SqliteStore.js'
6
+ import { MQTT_CLIENTS } from '../../db/Tables.js'
7
+ import { Broker } from './Broker.js'
8
+
9
+ class MqttServerClass {
10
+ constructor () {
11
+ this.server = null
12
+ this.isRunning = false
13
+ }
14
+
15
+ start () {
16
+ if (this.isRunning) {
17
+ Logger.log({
18
+ level: 'warn',
19
+ message: 'MQTT Server already running'
20
+ })
21
+ return
22
+ }
23
+
24
+ // Register storage collections
25
+ this.registerStorageCollections()
26
+
27
+ // Mark all previously connected clients as disconnected on server restart
28
+ this.cleanupStaleConnections()
29
+
30
+ // Initialize broker
31
+ const broker = Broker.initialize()
32
+
33
+ // Create TCP server
34
+ this.server = net.createServer(broker.handle)
35
+
36
+ // Handle server errors
37
+ this.server.on('error', (error) => {
38
+ Logger.log({
39
+ level: 'error',
40
+ message: 'MQTT Server error',
41
+ data: { error: error.message, stack: error.stack }
42
+ })
43
+ })
44
+
45
+ // Start listening
46
+ const port = Application.ports.mqtt
47
+ this.server.listen(port, () => {
48
+ this.isRunning = true
49
+ Logger.log({
50
+ level: 'info',
51
+ message: `MQTT Server started on port ${port}`,
52
+ data: { port, protocol: 'MQTT' }
53
+ })
54
+ })
55
+
56
+ return this.server
57
+ }
58
+
59
+ registerStorageCollections () {
60
+ // No-op for SQLite - tables created at DB initialization
61
+ Logger.log({
62
+ level: 'debug',
63
+ message: 'MQTT storage tables ready (SQLite)',
64
+ data: { tables: ['mqtt_clients', 'mqtt_messages', 'mqtt_subscriptions'] }
65
+ })
66
+ }
67
+
68
+ cleanupStaleConnections () {
69
+ try {
70
+ const staleClients = SqliteStore.find(MQTT_CLIENTS, { disconnectedAt: null })
71
+ if (staleClients.length > 0) {
72
+ const now = Moment().toISOString()
73
+ staleClients.forEach(client => {
74
+ SqliteStore.update(MQTT_CLIENTS, client.clientId, { disconnectedAt: now }, 'clientId')
75
+ })
76
+ Logger.log({
77
+ level: 'info',
78
+ message: 'Marked stale MQTT connections as disconnected',
79
+ data: { count: staleClients.length }
80
+ })
81
+ }
82
+ } catch (error) {
83
+ Logger.log({
84
+ level: 'error',
85
+ message: 'Failed to cleanup stale connections',
86
+ data: { error: error.message }
87
+ })
88
+ }
89
+ }
90
+
91
+ stop () {
92
+ if (!this.isRunning) {
93
+ Logger.log({
94
+ level: 'warn',
95
+ message: 'MQTT Server not running'
96
+ })
97
+ return
98
+ }
99
+
100
+ // Close broker
101
+ Broker.shutdown()
102
+
103
+ // Close server
104
+ if (this.server) {
105
+ this.server.close(() => {
106
+ this.isRunning = false
107
+ Logger.log({
108
+ level: 'info',
109
+ message: 'MQTT Server stopped'
110
+ })
111
+ })
112
+ }
113
+ }
114
+ }
115
+
116
+ export const MqttServer = new MqttServerClass()
@@ -0,0 +1,179 @@
1
+ import { spawn } from 'child_process'
2
+ import path from 'path'
3
+ import { fileURLToPath } from 'url'
4
+ import { Logger } from '../singletons/Logger.js'
5
+ import { FunctionStatuses } from '../enums/FunctionStatuses.js'
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
+ const PROJECT_ROOT = path.resolve(__dirname, '..', '..')
9
+ const FRAMEWORK_BIN = path.join(PROJECT_ROOT, 'node_modules', '.bin', 'functions-framework')
10
+
11
+ /**
12
+ * Manages a single Cloud Function's child process.
13
+ * Spawns functions-framework as a subprocess and monitors its lifecycle.
14
+ */
15
+ export class FunctionRunner {
16
+ constructor (config) {
17
+ this.name = config.name
18
+ this.source = config.source
19
+ this.sourcePath = config.sourcePath
20
+ this.entryPoint = config.entryPoint
21
+ this.port = config.port
22
+ this.signatureType = config.signatureType || 'cloudevent'
23
+ this.env = config.env || {}
24
+ this.timeoutSeconds = config.timeoutSeconds || 60
25
+ this.process = null
26
+ this.status = FunctionStatuses.STOPPED
27
+ this.startedAt = null
28
+ this.onLog = null
29
+ this.onStatusChange = null
30
+ }
31
+
32
+ async start () {
33
+ if (this.status === FunctionStatuses.RUNNING) return
34
+ this.status = FunctionStatuses.STARTING
35
+ this.notifyStatusChange()
36
+ const args = [
37
+ `--target=${this.entryPoint}`,
38
+ `--source=${this.source}`,
39
+ `--port=${this.port}`,
40
+ `--signature-type=${this.signatureType}`
41
+ ]
42
+ const childEnv = { ...process.env, ...this.env }
43
+ try {
44
+ this.process = spawn(FRAMEWORK_BIN, args, {
45
+ cwd: this.sourcePath,
46
+ env: childEnv,
47
+ stdio: ['ignore', 'pipe', 'pipe']
48
+ })
49
+ this.process.stdout.on('data', (data) => {
50
+ if (this.onLog) this.onLog(this.name, 'stdout', data.toString())
51
+ })
52
+ this.process.stderr.on('data', (data) => {
53
+ if (this.onLog) this.onLog(this.name, 'stderr', data.toString())
54
+ })
55
+ this.process.on('exit', (code, signal) => {
56
+ const wasRunning = this.status === FunctionStatuses.RUNNING
57
+ this.status = code === 0 || signal === 'SIGTERM'
58
+ ? FunctionStatuses.STOPPED
59
+ : FunctionStatuses.ERROR
60
+ this.process = null
61
+ this.notifyStatusChange()
62
+ Logger.log({
63
+ level: wasRunning ? 'warn' : 'debug',
64
+ message: `Function process exited: ${this.name}`,
65
+ data: { code, signal, status: this.status }
66
+ })
67
+ })
68
+ this.process.on('error', (err) => {
69
+ this.status = FunctionStatuses.ERROR
70
+ this.process = null
71
+ this.notifyStatusChange()
72
+ Logger.log({
73
+ level: 'error',
74
+ message: `Function process error: ${this.name}`,
75
+ data: { error: err.message }
76
+ })
77
+ })
78
+ await this.waitForReady()
79
+ this.status = FunctionStatuses.RUNNING
80
+ this.startedAt = Date.now()
81
+ this.notifyStatusChange()
82
+ Logger.log({
83
+ level: 'info',
84
+ message: `Function started: ${this.name}`,
85
+ data: { port: this.port, entryPoint: this.entryPoint }
86
+ })
87
+ } catch (error) {
88
+ this.status = FunctionStatuses.ERROR
89
+ this.notifyStatusChange()
90
+ if (this.process) {
91
+ this.process.kill('SIGKILL')
92
+ this.process = null
93
+ }
94
+ throw error
95
+ }
96
+ }
97
+
98
+ async waitForReady () {
99
+ const maxWaitMs = 15000
100
+ const pollIntervalMs = 500
101
+ const startTime = Date.now()
102
+ while (Date.now() - startTime < maxWaitMs) {
103
+ try {
104
+ const response = await fetch(`http://localhost:${this.port}/`, {
105
+ method: 'GET',
106
+ signal: AbortSignal.timeout(2000)
107
+ })
108
+ if (response) return
109
+ } catch {
110
+ // Not ready yet
111
+ }
112
+ if (!this.process || this.process.exitCode !== null) {
113
+ throw new Error(`Function process exited before becoming ready: ${this.name}`)
114
+ }
115
+ await new Promise(resolve => setTimeout(resolve, pollIntervalMs))
116
+ }
117
+ throw new Error(`Function failed to become ready within ${maxWaitMs}ms: ${this.name}`)
118
+ }
119
+
120
+ async stop () {
121
+ if (!this.process) {
122
+ this.status = FunctionStatuses.STOPPED
123
+ return
124
+ }
125
+ return new Promise((resolve) => {
126
+ const killTimeout = setTimeout(() => {
127
+ if (this.process) {
128
+ this.process.kill('SIGKILL')
129
+ }
130
+ }, 5000)
131
+ this.process.once('exit', () => {
132
+ clearTimeout(killTimeout)
133
+ this.status = FunctionStatuses.STOPPED
134
+ this.process = null
135
+ this.notifyStatusChange()
136
+ resolve()
137
+ })
138
+ this.process.kill('SIGTERM')
139
+ })
140
+ }
141
+
142
+ async restart () {
143
+ await this.stop()
144
+ await this.start()
145
+ }
146
+
147
+ async healthCheck () {
148
+ if (!this.process || this.status !== FunctionStatuses.RUNNING) {
149
+ return { healthy: false, status: this.status }
150
+ }
151
+ try {
152
+ const response = await fetch(`http://localhost:${this.port}/`, {
153
+ method: 'GET',
154
+ signal: AbortSignal.timeout(3000)
155
+ })
156
+ return { healthy: response.ok || response.status < 500, status: this.status }
157
+ } catch {
158
+ return { healthy: false, status: this.status }
159
+ }
160
+ }
161
+
162
+ getStatus () {
163
+ return {
164
+ name: this.name,
165
+ status: this.status,
166
+ port: this.port,
167
+ pid: this.process?.pid || null,
168
+ uptime: this.startedAt && this.status === FunctionStatuses.RUNNING
169
+ ? Date.now() - this.startedAt
170
+ : null
171
+ }
172
+ }
173
+
174
+ notifyStatusChange () {
175
+ if (this.onStatusChange) {
176
+ this.onStatusChange(this.name, this.status)
177
+ }
178
+ }
179
+ }