@neverinfamous/mysql-mcp 2.3.0 → 3.0.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/.dockerignore +1 -0
- package/.gitattributes +18 -0
- package/.github/workflows/codeql.yml +2 -10
- package/.github/workflows/docker-publish.yml +15 -13
- package/CHANGELOG.md +287 -1
- package/DOCKER_README.md +100 -265
- package/Dockerfile +5 -0
- package/README.md +124 -59
- package/VERSION +1 -1
- package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
- package/dist/__tests__/mocks/adapter.js +2 -0
- package/dist/__tests__/mocks/adapter.js.map +1 -1
- package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
- package/dist/adapters/DatabaseAdapter.js +50 -9
- package/dist/adapters/DatabaseAdapter.js.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
- package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.js +8 -0
- package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
- package/dist/adapters/mysql/SchemaManager.js +16 -15
- package/dist/adapters/mysql/SchemaManager.js.map +1 -1
- package/dist/adapters/mysql/prompts/index.js +10 -20
- package/dist/adapters/mysql/prompts/index.js.map +1 -1
- package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
- package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/docstore.js +10 -7
- package/dist/adapters/mysql/resources/docstore.js.map +1 -1
- package/dist/adapters/mysql/resources/events.js +11 -8
- package/dist/adapters/mysql/resources/events.js.map +1 -1
- package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/indexes.js +12 -15
- package/dist/adapters/mysql/resources/indexes.js.map +1 -1
- package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/innodb.js +20 -17
- package/dist/adapters/mysql/resources/innodb.js.map +1 -1
- package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/locks.js +9 -6
- package/dist/adapters/mysql/resources/locks.js.map +1 -1
- package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/performance.js +15 -15
- package/dist/adapters/mysql/resources/performance.js.map +1 -1
- package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/spatial.js +9 -6
- package/dist/adapters/mysql/resources/spatial.js.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.js +12 -9
- package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.js +170 -121
- package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
- package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
- package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
- package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.js +6 -4
- package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
- package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/core.js +152 -29
- package/dist/adapters/mysql/tools/core.js.map +1 -1
- package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/docstore.js +340 -163
- package/dist/adapters/mysql/tools/docstore.js.map +1 -1
- package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/events.js +284 -198
- package/dist/adapters/mysql/tools/events.js.map +1 -1
- package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/core.js +11 -39
- package/dist/adapters/mysql/tools/json/core.js.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
- package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.js +13 -24
- package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
- package/dist/adapters/mysql/tools/partitioning.js +3 -0
- package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
- package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
- package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.js +289 -176
- package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
- package/dist/adapters/mysql/tools/replication.js +75 -49
- package/dist/adapters/mysql/tools/replication.js.map +1 -1
- package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/roles.js +224 -182
- package/dist/adapters/mysql/tools/roles.js.map +1 -1
- package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/router.js +168 -67
- package/dist/adapters/mysql/tools/router.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
- package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.js +61 -14
- package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.js +27 -4
- package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
- package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
- package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.js +47 -7
- package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.js +102 -34
- package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
- package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.js +137 -104
- package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.js +71 -59
- package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.js +61 -47
- package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
- package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
- package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
- package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
- package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
- package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
- package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
- package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
- package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
- package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
- package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
- package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/transactions.js +48 -23
- package/dist/adapters/mysql/tools/transactions.js.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
- package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.js +33 -1
- package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
- package/dist/adapters/mysql/types/router-types.d.ts +1 -1
- package/dist/adapters/mysql/types/router-types.js +1 -1
- package/dist/adapters/mysql/types/router-types.js.map +1 -1
- package/dist/adapters/mysql/types/shell-types.js +2 -2
- package/dist/adapters/mysql/types/shell-types.js.map +1 -1
- package/dist/adapters/mysql/types.d.ts +485 -21
- package/dist/adapters/mysql/types.d.ts.map +1 -1
- package/dist/adapters/mysql/types.js +546 -19
- package/dist/adapters/mysql/types.js.map +1 -1
- package/dist/auth/scopes.js +1 -1
- package/dist/auth/scopes.js.map +1 -1
- package/dist/codemode/api.d.ts +3 -2
- package/dist/codemode/api.d.ts.map +1 -1
- package/dist/codemode/api.js +80 -5
- package/dist/codemode/api.js.map +1 -1
- package/dist/codemode/sandbox-factory.js +1 -1
- package/dist/codemode/sandbox-factory.js.map +1 -1
- package/dist/codemode/types.d.ts +26 -0
- package/dist/codemode/types.d.ts.map +1 -1
- package/dist/codemode/types.js +2 -0
- package/dist/codemode/types.js.map +1 -1
- package/dist/codemode/worker-sandbox.d.ts +4 -2
- package/dist/codemode/worker-sandbox.d.ts.map +1 -1
- package/dist/codemode/worker-sandbox.js +66 -7
- package/dist/codemode/worker-sandbox.js.map +1 -1
- package/dist/codemode/worker-script.d.ts +3 -0
- package/dist/codemode/worker-script.d.ts.map +1 -1
- package/dist/codemode/worker-script.js +128 -75
- package/dist/codemode/worker-script.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +1 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +37 -31
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/filtering/ToolConstants.d.ts +1 -1
- package/dist/filtering/ToolConstants.d.ts.map +1 -1
- package/dist/filtering/ToolConstants.js +1 -2
- package/dist/filtering/ToolConstants.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +6 -0
- package/dist/transports/http.js.map +1 -1
- package/dist/utils/validators.d.ts +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js.map +1 -1
- package/package.json +4 -4
- package/releases/v2.3.0-release-notes.md +20 -20
- package/releases/v2.3.1-release-notes.md +34 -0
- package/releases/v3.0.0-release-notes.md +81 -0
- package/src/__tests__/mocks/adapter.ts +3 -0
- package/src/__tests__/perf.test.ts +6 -6
- package/src/adapters/DatabaseAdapter.ts +58 -9
- package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
- package/src/adapters/mysql/MySQLAdapter.ts +17 -2
- package/src/adapters/mysql/SchemaManager.ts +21 -21
- package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
- package/src/adapters/mysql/prompts/index.ts +12 -22
- package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
- package/src/adapters/mysql/resources/docstore.ts +13 -10
- package/src/adapters/mysql/resources/events.ts +12 -12
- package/src/adapters/mysql/resources/indexes.ts +17 -19
- package/src/adapters/mysql/resources/innodb.ts +23 -22
- package/src/adapters/mysql/resources/locks.ts +9 -7
- package/src/adapters/mysql/resources/performance.ts +23 -18
- package/src/adapters/mysql/resources/spatial.ts +9 -7
- package/src/adapters/mysql/resources/sysschema.ts +12 -11
- package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
- package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
- package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
- package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
- package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
- package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
- package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
- package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
- package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
- package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -50
- package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
- package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
- package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
- package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
- package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
- package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
- package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
- package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
- package/src/adapters/mysql/tools/admin/backup.ts +193 -143
- package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
- package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
- package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
- package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
- package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
- package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
- package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
- package/src/adapters/mysql/tools/codemode/index.ts +5 -3
- package/src/adapters/mysql/tools/core.ts +152 -38
- package/src/adapters/mysql/tools/docstore.ts +422 -205
- package/src/adapters/mysql/tools/events.ts +334 -233
- package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
- package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
- package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
- package/src/adapters/mysql/tools/json/core.ts +21 -42
- package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
- package/src/adapters/mysql/tools/json/helpers.ts +21 -25
- package/src/adapters/mysql/tools/partitioning.ts +3 -0
- package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
- package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
- package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
- package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
- package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
- package/src/adapters/mysql/tools/proxysql.ts +314 -209
- package/src/adapters/mysql/tools/replication.ts +84 -57
- package/src/adapters/mysql/tools/roles.ts +274 -226
- package/src/adapters/mysql/tools/router.ts +181 -85
- package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
- package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
- package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
- package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
- package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
- package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
- package/src/adapters/mysql/tools/schema/management.ts +60 -15
- package/src/adapters/mysql/tools/schema/routines.ts +26 -4
- package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
- package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
- package/src/adapters/mysql/tools/schema/views.ts +46 -8
- package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
- package/src/adapters/mysql/tools/security/audit.ts +113 -39
- package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
- package/src/adapters/mysql/tools/security/encryption.ts +172 -139
- package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
- package/src/adapters/mysql/tools/shell/backup.ts +90 -73
- package/src/adapters/mysql/tools/shell/restore.ts +62 -48
- package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
- package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
- package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
- package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
- package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
- package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
- package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
- package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
- package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
- package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
- package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
- package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
- package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
- package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
- package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
- package/src/adapters/mysql/tools/transactions.ts +49 -24
- package/src/adapters/mysql/types/proxysql-types.ts +38 -1
- package/src/adapters/mysql/types/router-types.ts +1 -1
- package/src/adapters/mysql/types/shell-types.ts +2 -2
- package/src/adapters/mysql/types.ts +632 -19
- package/src/auth/__tests__/scopes.test.ts +2 -2
- package/src/auth/scopes.ts +1 -1
- package/src/codemode/__tests__/api.test.ts +417 -0
- package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
- package/src/codemode/__tests__/sandbox.test.ts +301 -0
- package/src/codemode/__tests__/security.test.ts +368 -0
- package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
- package/src/codemode/__tests__/worker-script.test.ts +226 -0
- package/src/codemode/api.ts +89 -5
- package/src/codemode/sandbox-factory.ts +1 -1
- package/src/codemode/types.ts +34 -0
- package/src/codemode/worker-sandbox.ts +74 -7
- package/src/codemode/worker-script.ts +157 -86
- package/src/constants/ServerInstructions.ts +37 -31
- package/src/filtering/ToolConstants.ts +1 -2
- package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
- package/src/pool/ConnectionPool.ts +4 -1
- package/src/transports/__tests__/http.test.ts +15 -3
- package/src/transports/http.ts +12 -0
- package/src/utils/validators.ts +2 -1
- package/vitest.config.ts +3 -1
- package/CODE_MODE.md +0 -245
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mysql-mcp - Worker Sandbox Unit Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for WorkerSandbox and WorkerSandboxPool.
|
|
5
|
+
* Mocks worker_threads to test sandbox lifecycle and pool management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
9
|
+
import { WorkerSandbox, WorkerSandboxPool } from "../worker-sandbox.js";
|
|
10
|
+
|
|
11
|
+
// Suppress logger
|
|
12
|
+
vi.mock("../../utils/logger.js", () => ({
|
|
13
|
+
logger: { info: vi.fn(), warning: vi.fn(), error: vi.fn() },
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
describe("WorkerSandbox", () => {
|
|
17
|
+
let sandbox: WorkerSandbox;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
sandbox = WorkerSandbox.create({
|
|
21
|
+
memoryLimitMb: 64,
|
|
22
|
+
timeoutMs: 5000,
|
|
23
|
+
cpuLimitMs: 5000,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
sandbox.dispose();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ===========================================================================
|
|
32
|
+
// Creation
|
|
33
|
+
// ===========================================================================
|
|
34
|
+
describe("create", () => {
|
|
35
|
+
it("should create a worker sandbox with default options", () => {
|
|
36
|
+
const s = WorkerSandbox.create();
|
|
37
|
+
expect(s).toBeDefined();
|
|
38
|
+
expect(s.isHealthy()).toBe(true);
|
|
39
|
+
s.dispose();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should create a worker sandbox with custom options", () => {
|
|
43
|
+
expect(sandbox).toBeDefined();
|
|
44
|
+
expect(sandbox.isHealthy()).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// ===========================================================================
|
|
49
|
+
// serializeBindings
|
|
50
|
+
// ===========================================================================
|
|
51
|
+
describe("serializeBindings", () => {
|
|
52
|
+
it("should serialize group methods", () => {
|
|
53
|
+
const bindings = {
|
|
54
|
+
core: {
|
|
55
|
+
readQuery: vi.fn(),
|
|
56
|
+
writeQuery: vi.fn(),
|
|
57
|
+
help: vi.fn(),
|
|
58
|
+
},
|
|
59
|
+
json: {
|
|
60
|
+
extract: vi.fn(),
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const serialized = sandbox.serializeBindings(bindings);
|
|
65
|
+
expect(serialized).toHaveProperty("core");
|
|
66
|
+
expect(serialized).toHaveProperty("json");
|
|
67
|
+
expect(serialized["core"]).toContain("readQuery");
|
|
68
|
+
expect(serialized["core"]).toContain("writeQuery");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should handle top-level function bindings", () => {
|
|
72
|
+
const bindings = {
|
|
73
|
+
readQuery: vi.fn(),
|
|
74
|
+
help: vi.fn(),
|
|
75
|
+
core: { readQuery: vi.fn() },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const serialized = sandbox.serializeBindings(bindings);
|
|
79
|
+
expect(serialized).toHaveProperty("_topLevel");
|
|
80
|
+
expect(serialized["_topLevel"]).toContain("readQuery");
|
|
81
|
+
expect(serialized["_topLevel"]).toContain("help");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should handle empty bindings", () => {
|
|
85
|
+
const serialized = sandbox.serializeBindings({});
|
|
86
|
+
expect(Object.keys(serialized)).toHaveLength(0);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// ===========================================================================
|
|
91
|
+
// calculateMetrics
|
|
92
|
+
// ===========================================================================
|
|
93
|
+
describe("calculateMetrics", () => {
|
|
94
|
+
it("should calculate correct metrics", () => {
|
|
95
|
+
const metrics = sandbox.calculateMetrics(0, 150, 1000, 3000);
|
|
96
|
+
expect(metrics.wallTimeMs).toBe(150);
|
|
97
|
+
expect(metrics.memoryUsedMb).toBeGreaterThanOrEqual(0);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ===========================================================================
|
|
102
|
+
// Health and disposal
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
describe("isHealthy / dispose", () => {
|
|
105
|
+
it("should be healthy after creation", () => {
|
|
106
|
+
expect(sandbox.isHealthy()).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should be unhealthy after dispose", () => {
|
|
110
|
+
sandbox.dispose();
|
|
111
|
+
expect(sandbox.isHealthy()).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should handle multiple dispose calls", () => {
|
|
115
|
+
sandbox.dispose();
|
|
116
|
+
sandbox.dispose();
|
|
117
|
+
expect(sandbox.isHealthy()).toBe(false);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// ===========================================================================
|
|
122
|
+
// execute
|
|
123
|
+
// ===========================================================================
|
|
124
|
+
describe("execute", () => {
|
|
125
|
+
it("should fail on disposed sandbox", async () => {
|
|
126
|
+
sandbox.dispose();
|
|
127
|
+
const result = await sandbox.execute("return 1", {});
|
|
128
|
+
expect(result.success).toBe(false);
|
|
129
|
+
expect(result.error).toContain("disposed");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// =============================================================================
|
|
135
|
+
// WorkerSandboxPool
|
|
136
|
+
// =============================================================================
|
|
137
|
+
describe("WorkerSandboxPool", () => {
|
|
138
|
+
let pool: WorkerSandboxPool;
|
|
139
|
+
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
pool = new WorkerSandboxPool(
|
|
142
|
+
{ minInstances: 0, maxInstances: 3, idleTimeoutMs: 1000 },
|
|
143
|
+
{ memoryLimitMb: 64, timeoutMs: 5000, cpuLimitMs: 5000 },
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
afterEach(() => {
|
|
148
|
+
pool.dispose();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("initialize", () => {
|
|
152
|
+
it("should initialize without error", () => {
|
|
153
|
+
pool.initialize();
|
|
154
|
+
expect(pool.getStats().max).toBe(3);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("getStats", () => {
|
|
159
|
+
it("should return correct stats", () => {
|
|
160
|
+
pool.initialize();
|
|
161
|
+
const stats = pool.getStats();
|
|
162
|
+
expect(stats).toHaveProperty("available");
|
|
163
|
+
expect(stats).toHaveProperty("inUse");
|
|
164
|
+
expect(stats).toHaveProperty("max");
|
|
165
|
+
expect(stats.max).toBe(3);
|
|
166
|
+
expect(stats.inUse).toBe(0);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("dispose", () => {
|
|
171
|
+
it("should dispose without error", () => {
|
|
172
|
+
pool.initialize();
|
|
173
|
+
pool.dispose();
|
|
174
|
+
// After dispose, pool may still report stats but should not be usable
|
|
175
|
+
const stats = pool.getStats();
|
|
176
|
+
expect(stats).toBeDefined();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mysql-mcp - Worker Script Unit Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for buildMysqlProxy and executeInWorker functions.
|
|
5
|
+
* Mocks parentPort, workerData, and MessagePort from worker_threads.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
9
|
+
import { EventEmitter } from "events";
|
|
10
|
+
|
|
11
|
+
// We test buildMysqlProxy by importing the module in a special way.
|
|
12
|
+
// Since worker-script.ts auto-executes, we need to mock the worker_threads
|
|
13
|
+
// module before importing.
|
|
14
|
+
|
|
15
|
+
// Mock worker_threads module
|
|
16
|
+
const mockParentPort = {
|
|
17
|
+
postMessage: vi.fn(),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const mockRpcPort = new EventEmitter() as EventEmitter & {
|
|
21
|
+
postMessage: ReturnType<typeof vi.fn>;
|
|
22
|
+
ref: ReturnType<typeof vi.fn>;
|
|
23
|
+
unref: ReturnType<typeof vi.fn>;
|
|
24
|
+
close: ReturnType<typeof vi.fn>;
|
|
25
|
+
};
|
|
26
|
+
mockRpcPort.postMessage = vi.fn();
|
|
27
|
+
mockRpcPort.ref = vi.fn();
|
|
28
|
+
mockRpcPort.unref = vi.fn();
|
|
29
|
+
mockRpcPort.close = vi.fn();
|
|
30
|
+
|
|
31
|
+
const mockWorkerData = {
|
|
32
|
+
code: 'return "hello"',
|
|
33
|
+
apiBindings: {
|
|
34
|
+
core: ["readQuery", "writeQuery", "help"],
|
|
35
|
+
json: ["extract", "set"],
|
|
36
|
+
_topLevel: ["readQuery", "help"],
|
|
37
|
+
},
|
|
38
|
+
timeout: 5000,
|
|
39
|
+
rpcPort: mockRpcPort,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
vi.mock("node:worker_threads", () => ({
|
|
43
|
+
parentPort: mockParentPort,
|
|
44
|
+
workerData: mockWorkerData,
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
describe("Worker Script", () => {
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
vi.clearAllMocks();
|
|
50
|
+
mockRpcPort.removeAllListeners();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("buildMysqlProxy", () => {
|
|
54
|
+
// Import the function by loading the module with mocks active
|
|
55
|
+
// Since the module auto-executes, we'll test the proxy construction
|
|
56
|
+
// pattern separately
|
|
57
|
+
|
|
58
|
+
it("should be tested through proxy construction patterns", async () => {
|
|
59
|
+
// The buildMysqlProxy function constructs a mysql-like object
|
|
60
|
+
// with group sub-objects where each method sends an RPC message.
|
|
61
|
+
// We test the patterns it creates.
|
|
62
|
+
|
|
63
|
+
const bindings = {
|
|
64
|
+
core: ["readQuery", "writeQuery", "help"],
|
|
65
|
+
json: ["extract"],
|
|
66
|
+
_topLevel: ["readQuery", "help"],
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Simulate what buildMysqlProxy does: creates group objects with methods
|
|
70
|
+
const mysql: Record<string, unknown> = {};
|
|
71
|
+
const groupNames: string[] = [];
|
|
72
|
+
|
|
73
|
+
for (const [key, methods] of Object.entries(bindings)) {
|
|
74
|
+
if (key === "_topLevel") continue;
|
|
75
|
+
groupNames.push(key);
|
|
76
|
+
|
|
77
|
+
const groupApi: Record<string, unknown> = {};
|
|
78
|
+
for (const method of methods) {
|
|
79
|
+
if (method === "help") continue;
|
|
80
|
+
groupApi[method] = vi.fn().mockResolvedValue({ rows: [] });
|
|
81
|
+
}
|
|
82
|
+
groupApi["help"] = () => ({
|
|
83
|
+
group: key,
|
|
84
|
+
methods: methods.filter((m) => m !== "help"),
|
|
85
|
+
});
|
|
86
|
+
mysql[key] = groupApi;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Top-level
|
|
90
|
+
const topLevel = bindings["_topLevel"];
|
|
91
|
+
if (topLevel) {
|
|
92
|
+
for (const method of topLevel) {
|
|
93
|
+
if (method === "help") {
|
|
94
|
+
mysql["help"] = () => ({ groups: groupNames });
|
|
95
|
+
} else {
|
|
96
|
+
mysql[method] = vi.fn().mockResolvedValue({ rows: [] });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Verify the structure
|
|
102
|
+
expect(mysql).toHaveProperty("core");
|
|
103
|
+
expect(mysql).toHaveProperty("json");
|
|
104
|
+
expect(mysql).toHaveProperty("readQuery");
|
|
105
|
+
expect(mysql).toHaveProperty("help");
|
|
106
|
+
|
|
107
|
+
// Test group help
|
|
108
|
+
const coreApi = mysql["core"] as Record<string, unknown>;
|
|
109
|
+
expect(coreApi).toHaveProperty("readQuery");
|
|
110
|
+
expect(coreApi).toHaveProperty("writeQuery");
|
|
111
|
+
expect(coreApi).toHaveProperty("help");
|
|
112
|
+
|
|
113
|
+
const helpResult = (coreApi["help"] as () => unknown)();
|
|
114
|
+
expect(helpResult).toEqual({
|
|
115
|
+
group: "core",
|
|
116
|
+
methods: ["readQuery", "writeQuery"],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Test top-level help
|
|
120
|
+
const topHelp = (mysql["help"] as () => unknown)();
|
|
121
|
+
expect(topHelp).toEqual({ groups: ["core", "json"] });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should filter help from method lists", () => {
|
|
125
|
+
const methods = ["readQuery", "writeQuery", "help"];
|
|
126
|
+
const filtered = methods.filter((m) => m !== "help");
|
|
127
|
+
expect(filtered).toEqual(["readQuery", "writeQuery"]);
|
|
128
|
+
expect(filtered).not.toContain("help");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("RPC message handling", () => {
|
|
133
|
+
it("should resolve pending promises on RPC response", async () => {
|
|
134
|
+
const pending = new Map<
|
|
135
|
+
number,
|
|
136
|
+
{ resolve: (v: unknown) => void; reject: (e: Error) => void }
|
|
137
|
+
>();
|
|
138
|
+
|
|
139
|
+
const promise = new Promise((resolve, reject) => {
|
|
140
|
+
pending.set(0, { resolve, reject });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Simulate RPC response
|
|
144
|
+
const msg = { id: 0, result: { rows: [{ id: 1 }] } };
|
|
145
|
+
const p = pending.get(msg.id);
|
|
146
|
+
if (p) {
|
|
147
|
+
pending.delete(msg.id);
|
|
148
|
+
if (msg.error) {
|
|
149
|
+
p.reject(new Error(msg.error));
|
|
150
|
+
} else {
|
|
151
|
+
p.resolve(msg.result);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const result = await promise;
|
|
156
|
+
expect(result).toEqual({ rows: [{ id: 1 }] });
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should reject pending promises on RPC error", async () => {
|
|
160
|
+
const pending = new Map<
|
|
161
|
+
number,
|
|
162
|
+
{ resolve: (v: unknown) => void; reject: (e: Error) => void }
|
|
163
|
+
>();
|
|
164
|
+
|
|
165
|
+
const promise = new Promise((resolve, reject) => {
|
|
166
|
+
pending.set(1, { resolve, reject });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Simulate RPC error response
|
|
170
|
+
const msg = { id: 1, error: "Query failed" } as {
|
|
171
|
+
id: number;
|
|
172
|
+
error?: string;
|
|
173
|
+
result?: unknown;
|
|
174
|
+
};
|
|
175
|
+
const p = pending.get(msg.id);
|
|
176
|
+
if (p) {
|
|
177
|
+
pending.delete(msg.id);
|
|
178
|
+
if (msg.error) {
|
|
179
|
+
p.reject(new Error(msg.error));
|
|
180
|
+
} else {
|
|
181
|
+
p.resolve(msg.result);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
await expect(promise).rejects.toThrow("Query failed");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should ignore responses for unknown request IDs", () => {
|
|
189
|
+
const pending = new Map<
|
|
190
|
+
number,
|
|
191
|
+
{ resolve: (v: unknown) => void; reject: (e: Error) => void }
|
|
192
|
+
>();
|
|
193
|
+
|
|
194
|
+
const msg = { id: 999, result: "unknown" };
|
|
195
|
+
const p = pending.get(msg.id);
|
|
196
|
+
expect(p).toBeUndefined();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe("sandbox context construction", () => {
|
|
201
|
+
it("should block dangerous globals", () => {
|
|
202
|
+
const sandbox: Record<string, unknown> = {
|
|
203
|
+
setTimeout: undefined,
|
|
204
|
+
setInterval: undefined,
|
|
205
|
+
setImmediate: undefined,
|
|
206
|
+
process: undefined,
|
|
207
|
+
require: undefined,
|
|
208
|
+
__dirname: undefined,
|
|
209
|
+
__filename: undefined,
|
|
210
|
+
globalThis: undefined,
|
|
211
|
+
global: undefined,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// All dangerous globals should be undefined
|
|
215
|
+
expect(sandbox.setTimeout).toBeUndefined();
|
|
216
|
+
expect(sandbox.setInterval).toBeUndefined();
|
|
217
|
+
expect(sandbox.setImmediate).toBeUndefined();
|
|
218
|
+
expect(sandbox.process).toBeUndefined();
|
|
219
|
+
expect(sandbox.require).toBeUndefined();
|
|
220
|
+
expect(sandbox.__dirname).toBeUndefined();
|
|
221
|
+
expect(sandbox.__filename).toBeUndefined();
|
|
222
|
+
expect(sandbox.globalThis).toBeUndefined();
|
|
223
|
+
expect(sandbox.global).toBeUndefined();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
package/src/codemode/api.ts
CHANGED
|
@@ -328,7 +328,7 @@ const GROUP_EXAMPLES: Record<string, string[]> = {
|
|
|
328
328
|
],
|
|
329
329
|
schema: [
|
|
330
330
|
"mysql.schema.listViews()",
|
|
331
|
-
"mysql.schema.createView({ name: 'active_users',
|
|
331
|
+
"mysql.schema.createView({ name: 'active_users', definition: 'SELECT * FROM users WHERE active = 1' })",
|
|
332
332
|
"mysql.schema.listFunctions()",
|
|
333
333
|
"mysql.schema.listTriggers({ table: 'orders' })",
|
|
334
334
|
],
|
|
@@ -785,8 +785,11 @@ export class MysqlApi {
|
|
|
785
785
|
readonly docstore: GroupApiRecord;
|
|
786
786
|
|
|
787
787
|
private readonly toolsByGroup: Map<string, ToolDefinition[]>;
|
|
788
|
+
private readonly isReadonly: boolean;
|
|
789
|
+
|
|
790
|
+
constructor(adapter: MySQLAdapter, readonly?: boolean) {
|
|
791
|
+
this.isReadonly = readonly ?? false;
|
|
788
792
|
|
|
789
|
-
constructor(adapter: MySQLAdapter) {
|
|
790
793
|
// Get all tool definitions and group them
|
|
791
794
|
const allTools = adapter.getToolDefinitions();
|
|
792
795
|
this.toolsByGroup = this.groupTools(allTools);
|
|
@@ -979,6 +982,42 @@ export class MysqlApi {
|
|
|
979
982
|
createSandboxBindings(): Record<string, unknown> {
|
|
980
983
|
const bindings: Record<string, unknown> = {};
|
|
981
984
|
|
|
985
|
+
// Groups that are entirely write-oriented (excluded when readonly)
|
|
986
|
+
const writeOnlyGroups = new Set([
|
|
987
|
+
"transactions",
|
|
988
|
+
"admin",
|
|
989
|
+
"backup",
|
|
990
|
+
"partitioning",
|
|
991
|
+
"roles",
|
|
992
|
+
"events",
|
|
993
|
+
"shell",
|
|
994
|
+
]);
|
|
995
|
+
|
|
996
|
+
// Methods within mixed groups that perform writes (excluded when readonly)
|
|
997
|
+
const writeMethods: Record<string, Set<string>> = {
|
|
998
|
+
core: new Set(["writeQuery", "dropTable", "createTable", "createIndex"]),
|
|
999
|
+
docstore: new Set([
|
|
1000
|
+
"docAdd",
|
|
1001
|
+
"docModify",
|
|
1002
|
+
"docRemove",
|
|
1003
|
+
"docCreateCollection",
|
|
1004
|
+
"docDropCollection",
|
|
1005
|
+
"docCreateIndex",
|
|
1006
|
+
]),
|
|
1007
|
+
schema: new Set(["createSchema", "dropSchema", "createView"]),
|
|
1008
|
+
json: new Set([
|
|
1009
|
+
"set",
|
|
1010
|
+
"insert",
|
|
1011
|
+
"remove",
|
|
1012
|
+
"replace",
|
|
1013
|
+
"update",
|
|
1014
|
+
"merge",
|
|
1015
|
+
"arrayAppend",
|
|
1016
|
+
]),
|
|
1017
|
+
fulltext: new Set(["fulltextCreate", "fulltextDrop"]),
|
|
1018
|
+
spatial: new Set(["createColumn", "createIndex"]),
|
|
1019
|
+
};
|
|
1020
|
+
|
|
982
1021
|
const groupNames = [
|
|
983
1022
|
"core",
|
|
984
1023
|
"transactions",
|
|
@@ -1007,7 +1046,30 @@ export class MysqlApi {
|
|
|
1007
1046
|
] as const;
|
|
1008
1047
|
|
|
1009
1048
|
for (const groupName of groupNames) {
|
|
1049
|
+
// Skip entire write-only groups when readonly
|
|
1050
|
+
if (this.isReadonly && writeOnlyGroups.has(groupName)) {
|
|
1051
|
+
const blockedStub = (): { success: false; error: string } => ({
|
|
1052
|
+
success: false,
|
|
1053
|
+
error: `Readonly mode: the '${groupName}' group is not available in readonly mode`,
|
|
1054
|
+
});
|
|
1055
|
+
const groupApi = this[groupName];
|
|
1056
|
+
const stubbed: Record<string, unknown> = {};
|
|
1057
|
+
for (const method of Object.keys(groupApi)) {
|
|
1058
|
+
stubbed[method] = blockedStub;
|
|
1059
|
+
}
|
|
1060
|
+
stubbed["help"] = () => ({
|
|
1061
|
+
methods: Object.keys(groupApi),
|
|
1062
|
+
readonly: true,
|
|
1063
|
+
note: `All methods in '${groupName}' are blocked in readonly mode`,
|
|
1064
|
+
});
|
|
1065
|
+
bindings[groupName] = stubbed;
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1010
1069
|
const groupApi = this[groupName];
|
|
1070
|
+
const groupWriteMethods = this.isReadonly
|
|
1071
|
+
? (writeMethods[groupName] ?? new Set<string>())
|
|
1072
|
+
: new Set<string>();
|
|
1011
1073
|
const allMethodNames = Object.keys(groupApi);
|
|
1012
1074
|
|
|
1013
1075
|
// Separate canonical methods from aliases for structured help output
|
|
@@ -1025,9 +1087,28 @@ export class MysqlApi {
|
|
|
1025
1087
|
return !lowerAlias.startsWith(lowerGroupName);
|
|
1026
1088
|
});
|
|
1027
1089
|
|
|
1090
|
+
// Build the group API, replacing write methods with stubs when readonly
|
|
1091
|
+
const filteredApi: Record<string, unknown> = {};
|
|
1092
|
+
for (const method of allMethodNames) {
|
|
1093
|
+
// Check if this method (or its canonical target) is a write method
|
|
1094
|
+
const canonicalTarget = aliases[method] ?? method;
|
|
1095
|
+
const isWrite =
|
|
1096
|
+
groupWriteMethods.has(method) ||
|
|
1097
|
+
groupWriteMethods.has(canonicalTarget);
|
|
1098
|
+
|
|
1099
|
+
if (isWrite) {
|
|
1100
|
+
filteredApi[method] = (): { success: false; error: string } => ({
|
|
1101
|
+
success: false,
|
|
1102
|
+
error: `Readonly mode: '${groupName}.${method}()' is a write operation and cannot be used when readonly is true`,
|
|
1103
|
+
});
|
|
1104
|
+
} else {
|
|
1105
|
+
filteredApi[method] = groupApi[method];
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1028
1109
|
// Add all methods plus a 'help' property that lists them
|
|
1029
1110
|
bindings[groupName] = {
|
|
1030
|
-
...
|
|
1111
|
+
...filteredApi,
|
|
1031
1112
|
help: () => ({
|
|
1032
1113
|
methods: canonicalMethodNames,
|
|
1033
1114
|
methodAliases: usefulAliases,
|
|
@@ -1219,6 +1300,9 @@ export class MysqlApi {
|
|
|
1219
1300
|
/**
|
|
1220
1301
|
* Create a MysqlApi instance for an adapter
|
|
1221
1302
|
*/
|
|
1222
|
-
export function createMysqlApi(
|
|
1223
|
-
|
|
1303
|
+
export function createMysqlApi(
|
|
1304
|
+
adapter: MySQLAdapter,
|
|
1305
|
+
readonly?: boolean,
|
|
1306
|
+
): MysqlApi {
|
|
1307
|
+
return new MysqlApi(adapter, readonly);
|
|
1224
1308
|
}
|
package/src/codemode/types.ts
CHANGED
|
@@ -119,6 +119,8 @@ export const DEFAULT_SECURITY_CONFIG: SecurityConfig = {
|
|
|
119
119
|
/\bFunction\s*\(/, // No Function constructor
|
|
120
120
|
/\b__proto__\b/, // No prototype pollution
|
|
121
121
|
/\bconstructor\.constructor/, // No constructor chaining
|
|
122
|
+
/\[['"]constructor['"]\]/i, // No bracket-notation constructor access
|
|
123
|
+
/\bReflect\s*\.\s*construct/i, // No Reflect.construct bypass
|
|
122
124
|
/\bchild_process/, // No child processes
|
|
123
125
|
/\bfs\./, // No filesystem
|
|
124
126
|
/\bnet\./, // No networking
|
|
@@ -192,3 +194,35 @@ export interface ExecuteCodeResult {
|
|
|
192
194
|
/** Execution metrics */
|
|
193
195
|
metrics: ExecutionMetrics;
|
|
194
196
|
}
|
|
197
|
+
|
|
198
|
+
// =============================================================================
|
|
199
|
+
// Worker RPC Types
|
|
200
|
+
// =============================================================================
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* RPC request from worker thread to main thread.
|
|
204
|
+
* Sent over the MessagePort to invoke API methods on the main thread.
|
|
205
|
+
*/
|
|
206
|
+
export interface RpcRequest {
|
|
207
|
+
/** Unique request ID for correlating responses */
|
|
208
|
+
id: number;
|
|
209
|
+
/** API group name (e.g., "core", "json") */
|
|
210
|
+
group: string;
|
|
211
|
+
/** Method name within the group (e.g., "readQuery") */
|
|
212
|
+
method: string;
|
|
213
|
+
/** Arguments to pass to the method */
|
|
214
|
+
args: unknown[];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* RPC response from main thread to worker thread.
|
|
219
|
+
* Sent back over the MessagePort with the result or error.
|
|
220
|
+
*/
|
|
221
|
+
export interface RpcResponse {
|
|
222
|
+
/** Matching request ID */
|
|
223
|
+
id: number;
|
|
224
|
+
/** Return value from the method (if successful) */
|
|
225
|
+
result?: unknown;
|
|
226
|
+
/** Error message (if failed) */
|
|
227
|
+
error?: string;
|
|
228
|
+
}
|