@credibledata/cred-cli 0.0.103 → 0.0.105
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 +106 -1
- package/dist/agent-contract.spec.js +548 -0
- package/dist/agent-contract.spec.js.map +1 -0
- package/dist/browser.js +72 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.spec.js +125 -0
- package/dist/browser.spec.js.map +1 -0
- package/dist/client/api.js +4137 -1159
- package/dist/client/api.js.map +1 -1
- package/dist/client-codeassist/api.js +476 -0
- package/dist/client-codeassist/api.js.map +1 -0
- package/dist/client-codeassist/base.js +69 -0
- package/dist/client-codeassist/base.js.map +1 -0
- package/dist/client-codeassist/common.js +162 -0
- package/dist/client-codeassist/common.js.map +1 -0
- package/dist/client-codeassist/configuration.js +44 -0
- package/dist/client-codeassist/configuration.js.map +1 -0
- package/dist/client-codeassist/index.js +32 -0
- package/dist/client-codeassist/index.js.map +1 -0
- package/dist/clientconfiguration.js +17 -289
- package/dist/clientconfiguration.js.map +1 -1
- package/dist/clientconfiguration.spec.js +35 -96
- package/dist/clientconfiguration.spec.js.map +1 -1
- package/dist/commands/add.js +103 -3
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.spec.js +113 -0
- package/dist/commands/add.spec.js.map +1 -0
- package/dist/commands/connection/createconnections.js +104 -7
- package/dist/commands/connection/createconnections.js.map +1 -1
- package/dist/commands/connection/createconnections.spec.js +35 -1
- package/dist/commands/connection/createconnections.spec.js.map +1 -1
- package/dist/commands/connection/deleteconnection.js +4 -2
- package/dist/commands/connection/deleteconnection.js.map +1 -1
- package/dist/commands/connection/deleteconnection.spec.js +6 -1
- package/dist/commands/connection/deleteconnection.spec.js.map +1 -1
- package/dist/commands/connection/listconnections.js +2 -0
- package/dist/commands/connection/listconnections.js.map +1 -1
- package/dist/commands/connection/updateconnection.js +365 -0
- package/dist/commands/connection/updateconnection.js.map +1 -0
- package/dist/commands/connection/updateconnection.spec.js +625 -0
- package/dist/commands/connection/updateconnection.spec.js.map +1 -0
- package/dist/commands/database/createdatabase.js +52 -0
- package/dist/commands/database/createdatabase.js.map +1 -0
- package/dist/commands/database/database.spec.js +267 -0
- package/dist/commands/database/database.spec.js.map +1 -0
- package/dist/commands/database/deletedatabase.js +91 -0
- package/dist/commands/database/deletedatabase.js.map +1 -0
- package/dist/commands/database/getdatabase.js +97 -0
- package/dist/commands/database/getdatabase.js.map +1 -0
- package/dist/commands/database/listdatabases.js +36 -0
- package/dist/commands/database/listdatabases.js.map +1 -0
- package/dist/commands/database/shared.js +125 -0
- package/dist/commands/database/shared.js.map +1 -0
- package/dist/commands/database/shared.spec.js +109 -0
- package/dist/commands/database/shared.spec.js.map +1 -0
- package/dist/commands/database/updatedatabase.js +39 -0
- package/dist/commands/database/updatedatabase.js.map +1 -0
- package/dist/commands/environment/createenvironment.js +59 -28
- package/dist/commands/environment/createenvironment.js.map +1 -1
- package/dist/commands/environment/createenvironment.spec.js +29 -0
- package/dist/commands/environment/createenvironment.spec.js.map +1 -1
- package/dist/commands/environment/deleteenvironment.js +3 -2
- package/dist/commands/environment/deleteenvironment.js.map +1 -1
- package/dist/commands/environment/deleteenvironment.spec.js +5 -1
- package/dist/commands/environment/deleteenvironment.spec.js.map +1 -1
- package/dist/commands/environment/getenvironment.js +1 -0
- package/dist/commands/environment/getenvironment.js.map +1 -1
- package/dist/commands/environment/listenvironments.js +40 -8
- package/dist/commands/environment/listenvironments.js.map +1 -1
- package/dist/commands/environment/listenvironments.spec.js +41 -2
- package/dist/commands/environment/listenvironments.spec.js.map +1 -1
- package/dist/commands/environment/setenvironment.js +145 -6
- package/dist/commands/environment/setenvironment.js.map +1 -1
- package/dist/commands/environment/setenvironment.spec.js +256 -8
- package/dist/commands/environment/setenvironment.spec.js.map +1 -1
- package/dist/commands/environment/updateenvironment.js +12 -8
- package/dist/commands/environment/updateenvironment.js.map +1 -1
- package/dist/commands/environment/updateenvironment.spec.js +36 -2
- package/dist/commands/environment/updateenvironment.spec.js.map +1 -1
- package/dist/commands/get.js +64 -1
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/group/addmember.js +3 -1
- package/dist/commands/group/addmember.js.map +1 -1
- package/dist/commands/group/addmember.spec.js +7 -2
- package/dist/commands/group/addmember.spec.js.map +1 -1
- package/dist/commands/group/creategroup.js +2 -0
- package/dist/commands/group/creategroup.js.map +1 -1
- package/dist/commands/group/deletegroup.js +3 -1
- package/dist/commands/group/deletegroup.js.map +1 -1
- package/dist/commands/group/deletegroup.spec.js +7 -1
- package/dist/commands/group/deletegroup.spec.js.map +1 -1
- package/dist/commands/group/getgroup.js +2 -0
- package/dist/commands/group/getgroup.js.map +1 -1
- package/dist/commands/group/listgroups.js +2 -0
- package/dist/commands/group/listgroups.js.map +1 -1
- package/dist/commands/group/removemember.js +3 -1
- package/dist/commands/group/removemember.js.map +1 -1
- package/dist/commands/group/removemember.spec.js +7 -2
- package/dist/commands/group/removemember.spec.js.map +1 -1
- package/dist/commands/groupaccesstoken/deleteToken.js +2 -1
- package/dist/commands/groupaccesstoken/deleteToken.js.map +1 -1
- package/dist/commands/groupaccesstoken/groupContainer.js +2 -0
- package/dist/commands/groupaccesstoken/groupContainer.js.map +1 -1
- package/dist/commands/list.js +24 -4
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/materialization/cancelrun.js +3 -1
- package/dist/commands/materialization/cancelrun.js.map +1 -1
- package/dist/commands/materialization/getindex.js +2 -0
- package/dist/commands/materialization/getindex.js.map +1 -1
- package/dist/commands/materialization/getmaterialization.js +2 -0
- package/dist/commands/materialization/getmaterialization.js.map +1 -1
- package/dist/commands/materialization/getpreaggregate.js +2 -0
- package/dist/commands/materialization/getpreaggregate.js.map +1 -1
- package/dist/commands/materialization/getrun.js +2 -0
- package/dist/commands/materialization/getrun.js.map +1 -1
- package/dist/commands/materialization/listindexes.js +2 -0
- package/dist/commands/materialization/listindexes.js.map +1 -1
- package/dist/commands/materialization/listmaterializations.js +2 -0
- package/dist/commands/materialization/listmaterializations.js.map +1 -1
- package/dist/commands/materialization/listpreaggregates.js +2 -0
- package/dist/commands/materialization/listpreaggregates.js.map +1 -1
- package/dist/commands/materialization/listruns.js +3 -1
- package/dist/commands/materialization/listruns.js.map +1 -1
- package/dist/commands/materialization/rerun.js +3 -1
- package/dist/commands/materialization/rerun.js.map +1 -1
- package/dist/commands/misc/inquirerHost.js +87 -0
- package/dist/commands/misc/inquirerHost.js.map +1 -0
- package/dist/commands/misc/inquirerHost.spec.js +91 -0
- package/dist/commands/misc/inquirerHost.spec.js.map +1 -0
- package/dist/commands/misc/login.js +348 -58
- package/dist/commands/misc/login.js.map +1 -1
- package/dist/commands/misc/login.spec.js +525 -7
- package/dist/commands/misc/login.spec.js.map +1 -1
- package/dist/commands/misc/logout.js +26 -3
- package/dist/commands/misc/logout.js.map +1 -1
- package/dist/commands/misc/logout.spec.js +52 -12
- package/dist/commands/misc/logout.spec.js.map +1 -1
- package/dist/commands/misc/resolveLoginTarget.spec.js +90 -0
- package/dist/commands/misc/resolveLoginTarget.spec.js.map +1 -0
- package/dist/commands/misc/scope.spec.js +108 -0
- package/dist/commands/misc/scope.spec.js.map +1 -0
- package/dist/commands/misc/set-access-token.js +1 -1
- package/dist/commands/misc/set-access-token.js.map +1 -1
- package/dist/commands/misc/set-access-token.spec.js +13 -2
- package/dist/commands/misc/set-access-token.spec.js.map +1 -1
- package/dist/commands/misc/setup.js +819 -0
- package/dist/commands/misc/setup.js.map +1 -0
- package/dist/commands/misc/setup.spec.js +783 -0
- package/dist/commands/misc/setup.spec.js.map +1 -0
- package/dist/commands/misc/status.js +168 -0
- package/dist/commands/misc/status.js.map +1 -0
- package/dist/commands/misc/status.spec.js +301 -0
- package/dist/commands/misc/status.spec.js.map +1 -0
- package/dist/commands/misc/token.js +57 -0
- package/dist/commands/misc/token.js.map +1 -0
- package/dist/commands/misc/token.spec.js +92 -0
- package/dist/commands/misc/token.spec.js.map +1 -0
- package/dist/commands/package/deletepackage.js +4 -2
- package/dist/commands/package/deletepackage.js.map +1 -1
- package/dist/commands/package/deletepackage.spec.js +7 -1
- package/dist/commands/package/deletepackage.spec.js.map +1 -1
- package/dist/commands/package/getpackage.js +142 -0
- package/dist/commands/package/getpackage.js.map +1 -0
- package/dist/commands/package/getpackage.spec.js +246 -0
- package/dist/commands/package/getpackage.spec.js.map +1 -0
- package/dist/commands/package/listpackages.js +2 -0
- package/dist/commands/package/listpackages.js.map +1 -1
- package/dist/commands/package/publish.archive.spec.js +570 -0
- package/dist/commands/package/publish.archive.spec.js.map +1 -0
- package/dist/commands/package/publish.js +780 -49
- package/dist/commands/package/publish.js.map +1 -1
- package/dist/commands/package/publish.spec.js +451 -8
- package/dist/commands/package/publish.spec.js.map +1 -1
- package/dist/commands/package/updatepackage.js +22 -19
- package/dist/commands/package/updatepackage.js.map +1 -1
- package/dist/commands/package/updatepackage.spec.js +36 -1
- package/dist/commands/package/updatepackage.spec.js.map +1 -1
- package/dist/commands/permission/createpermission.js +3 -1
- package/dist/commands/permission/createpermission.js.map +1 -1
- package/dist/commands/permission/deletepermission.js +6 -3
- package/dist/commands/permission/deletepermission.js.map +1 -1
- package/dist/commands/permission/getpermission.js +2 -0
- package/dist/commands/permission/getpermission.js.map +1 -1
- package/dist/commands/permission/listpermissions.js +2 -0
- package/dist/commands/permission/listpermissions.js.map +1 -1
- package/dist/commands/rm.js +21 -0
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/set.js +40 -6
- package/dist/commands/set.js.map +1 -1
- package/dist/commands/set.spec.js +123 -0
- package/dist/commands/set.spec.js.map +1 -0
- package/dist/commands/table/addtable.js +155 -0
- package/dist/commands/table/addtable.js.map +1 -0
- package/dist/commands/table/deletetable.js +45 -0
- package/dist/commands/table/deletetable.js.map +1 -0
- package/dist/commands/table/gettable.js +32 -0
- package/dist/commands/table/gettable.js.map +1 -0
- package/dist/commands/table/listtables.js +36 -0
- package/dist/commands/table/listtables.js.map +1 -0
- package/dist/commands/table/table.spec.js +304 -0
- package/dist/commands/table/table.spec.js.map +1 -0
- package/dist/commands/table/tablefile.js +195 -0
- package/dist/commands/table/tablefile.js.map +1 -0
- package/dist/commands/table/tablefile.spec.js +158 -0
- package/dist/commands/table/tablefile.spec.js.map +1 -0
- package/dist/commands/update.js +21 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/version/archive-unarchive-version.js +4 -2
- package/dist/commands/version/archive-unarchive-version.js.map +1 -1
- package/dist/commands/version/archive-unarchive-version.spec.js +6 -1
- package/dist/commands/version/archive-unarchive-version.spec.js.map +1 -1
- package/dist/commands/version/listversions.js +2 -0
- package/dist/commands/version/listversions.js.map +1 -1
- package/dist/common/UserGroupId.js +9 -4
- package/dist/common/UserGroupId.js.map +1 -1
- package/dist/common/UserGroupId.spec.js +5 -0
- package/dist/common/UserGroupId.spec.js.map +1 -1
- package/dist/constants.js +37 -143
- package/dist/constants.js.map +1 -1
- package/dist/index.js +487 -90
- package/dist/index.js.map +1 -1
- package/dist/logger.js +42 -9
- package/dist/logger.js.map +1 -1
- package/dist/session.js +56 -0
- package/dist/session.js.map +1 -0
- package/dist/session.spec.js +103 -0
- package/dist/session.spec.js.map +1 -0
- package/dist/setup-core/briefing.js +176 -0
- package/dist/setup-core/briefing.js.map +1 -0
- package/dist/setup-core/credstore.js +415 -0
- package/dist/setup-core/credstore.js.map +1 -0
- package/dist/setup-core/credstore.spec.js +238 -0
- package/dist/setup-core/credstore.spec.js.map +1 -0
- package/dist/setup-core/environments.js +267 -0
- package/dist/setup-core/environments.js.map +1 -0
- package/dist/setup-core/flow.e2e.js +165 -0
- package/dist/setup-core/flow.e2e.js.map +1 -0
- package/dist/setup-core/flow.js +765 -0
- package/dist/setup-core/flow.js.map +1 -0
- package/dist/setup-core/flow.spec.js +1348 -0
- package/dist/setup-core/flow.spec.js.map +1 -0
- package/dist/setup-core/folderconfig.js +283 -0
- package/dist/setup-core/folderconfig.js.map +1 -0
- package/dist/setup-core/git.js +97 -0
- package/dist/setup-core/git.js.map +1 -0
- package/dist/setup-core/host.js +77 -0
- package/dist/setup-core/host.js.map +1 -0
- package/dist/setup-core/importconnections.js +470 -0
- package/dist/setup-core/importconnections.js.map +1 -0
- package/dist/setup-core/importconnections.spec.js +594 -0
- package/dist/setup-core/importconnections.spec.js.map +1 -0
- package/dist/setup-core/liveness.js +94 -0
- package/dist/setup-core/liveness.js.map +1 -0
- package/dist/setup-core/liveness.spec.js +59 -0
- package/dist/setup-core/liveness.spec.js.map +1 -0
- package/dist/setup-core/localpublisherconfig.js +26 -0
- package/dist/setup-core/localpublisherconfig.js.map +1 -0
- package/dist/setup-core/localpublisherconfig.spec.js +29 -0
- package/dist/setup-core/localpublisherconfig.spec.js.map +1 -0
- package/dist/setup-core/mcpconfig.js +198 -0
- package/dist/setup-core/mcpconfig.js.map +1 -0
- package/dist/setup-core/mcpconfig.spec.js +205 -0
- package/dist/setup-core/mcpconfig.spec.js.map +1 -0
- package/dist/setup-core/packagemanifest.js +55 -0
- package/dist/setup-core/packagemanifest.js.map +1 -0
- package/dist/setup-core/ports.js +182 -0
- package/dist/setup-core/ports.js.map +1 -0
- package/dist/setup-core/ports.spec.js +173 -0
- package/dist/setup-core/ports.spec.js.map +1 -0
- package/dist/setup-core/publisherconfig.js +268 -0
- package/dist/setup-core/publisherconfig.js.map +1 -0
- package/dist/setup-core/publisherconfig.oracle.js +166 -0
- package/dist/setup-core/publisherconfig.oracle.js.map +1 -0
- package/dist/setup-core/publisherconfig.spec.js +277 -0
- package/dist/setup-core/publisherconfig.spec.js.map +1 -0
- package/dist/setup-core/publisherversion.js +26 -0
- package/dist/setup-core/publisherversion.js.map +1 -0
- package/dist/setup-core/readiness.spec.js +161 -0
- package/dist/setup-core/readiness.spec.js.map +1 -0
- package/dist/setup-core/readylines.js +169 -0
- package/dist/setup-core/readylines.js.map +1 -0
- package/dist/setup-core/readylines.spec.js +70 -0
- package/dist/setup-core/readylines.spec.js.map +1 -0
- package/dist/setup-core/refresh.js +348 -0
- package/dist/setup-core/refresh.js.map +1 -0
- package/dist/setup-core/refresh.spec.js +501 -0
- package/dist/setup-core/refresh.spec.js.map +1 -0
- package/dist/setup-core/skills.js +279 -0
- package/dist/setup-core/skills.js.map +1 -0
- package/dist/setup-core/skills.spec.js +334 -0
- package/dist/setup-core/skills.spec.js.map +1 -0
- package/dist/setup-core/supervisor.js +879 -0
- package/dist/setup-core/supervisor.js.map +1 -0
- package/dist/setup-core/supervisor.spec.js +833 -0
- package/dist/setup-core/supervisor.spec.js.map +1 -0
- package/dist/setup-core/writefile.js +61 -0
- package/dist/setup-core/writefile.js.map +1 -0
- package/dist/setup-core/writefile.spec.js +68 -0
- package/dist/setup-core/writefile.spec.js.map +1 -0
- package/dist/utils.js +409 -3
- package/dist/utils.js.map +1 -1
- package/dist/utils.spec.js +373 -2
- package/dist/utils.spec.js.map +1 -1
- package/dist/versioncheck-refresh.js +18 -0
- package/dist/versioncheck-refresh.js.map +1 -0
- package/dist/versioncheck.js +324 -0
- package/dist/versioncheck.js.map +1 -0
- package/dist/versioncheck.spec.js +587 -0
- package/dist/versioncheck.spec.js.map +1 -0
- package/node_modules/@credibledata/cli-auth/dist/index.d.ts +86 -0
- package/node_modules/@credibledata/cli-auth/dist/index.js +102 -0
- package/node_modules/@credibledata/cli-auth/package.json +19 -0
- package/package.json +18 -6
- package/.github/workflows/build.yml +0 -23
- package/.mocharc.json +0 -10
- package/.prettierignore +0 -2
- package/.prettierrc +0 -4
- package/README-DEV.md +0 -40
- package/coverage/coverage-summary.json +0 -40
- package/coverage/tmp/coverage-2152-1789496974457-0.json +0 -1
- package/coverage/tmp/coverage-2153-1789496954404-0.json +0 -1
- package/docker/Dockerfile.ci +0 -18
- package/docker-compose.yml +0 -18
- package/eslint.config.mjs +0 -45
- package/generate-client.sh +0 -27
- package/mocha.setup.ts +0 -4
- package/openapitools.json +0 -10
- package/src/client/.openapi-generator/FILES +0 -9
- package/src/client/.openapi-generator/VERSION +0 -1
- package/src/client/.openapi-generator-ignore +0 -23
- package/src/client/api.ts +0 -15999
- package/src/client/base.ts +0 -86
- package/src/client/common.ts +0 -150
- package/src/client/configuration.ts +0 -110
- package/src/client/git_push.sh +0 -57
- package/src/client/index.ts +0 -18
- package/src/clientconfiguration.spec.ts +0 -615
- package/src/clientconfiguration.ts +0 -364
- package/src/commands/add.ts +0 -191
- package/src/commands/connection/createconnections.spec.ts +0 -413
- package/src/commands/connection/createconnections.ts +0 -109
- package/src/commands/connection/deleteconnection.spec.ts +0 -189
- package/src/commands/connection/deleteconnection.ts +0 -57
- package/src/commands/connection/listconnections.spec.ts +0 -132
- package/src/commands/connection/listconnections.ts +0 -58
- package/src/commands/environment/createenvironment.spec.ts +0 -249
- package/src/commands/environment/createenvironment.ts +0 -73
- package/src/commands/environment/deleteenvironment.spec.ts +0 -152
- package/src/commands/environment/deleteenvironment.ts +0 -48
- package/src/commands/environment/getenvironment.spec.ts +0 -110
- package/src/commands/environment/getenvironment.ts +0 -43
- package/src/commands/environment/listenvironments.spec.ts +0 -123
- package/src/commands/environment/listenvironments.ts +0 -67
- package/src/commands/environment/setenvironment.spec.ts +0 -63
- package/src/commands/environment/setenvironment.ts +0 -14
- package/src/commands/environment/updateenvironment.spec.ts +0 -386
- package/src/commands/environment/updateenvironment.ts +0 -168
- package/src/commands/get.ts +0 -153
- package/src/commands/group/addmember.spec.ts +0 -257
- package/src/commands/group/addmember.ts +0 -85
- package/src/commands/group/creategroup.spec.ts +0 -146
- package/src/commands/group/creategroup.ts +0 -54
- package/src/commands/group/deletegroup.spec.ts +0 -120
- package/src/commands/group/deletegroup.ts +0 -45
- package/src/commands/group/getgroup.spec.ts +0 -129
- package/src/commands/group/getgroup.ts +0 -47
- package/src/commands/group/listgroups.spec.ts +0 -137
- package/src/commands/group/listgroups.ts +0 -45
- package/src/commands/group/removemember.spec.ts +0 -224
- package/src/commands/group/removemember.ts +0 -75
- package/src/commands/groupaccesstoken/createToken.spec.ts +0 -211
- package/src/commands/groupaccesstoken/createToken.ts +0 -72
- package/src/commands/groupaccesstoken/deleteToken.spec.ts +0 -147
- package/src/commands/groupaccesstoken/deleteToken.ts +0 -29
- package/src/commands/groupaccesstoken/groupContainer.ts +0 -83
- package/src/commands/groupaccesstoken/listTokens.spec.ts +0 -147
- package/src/commands/groupaccesstoken/listTokens.ts +0 -29
- package/src/commands/legacy.ts +0 -5
- package/src/commands/list.ts +0 -326
- package/src/commands/materialization/cancelrun.ts +0 -70
- package/src/commands/materialization/getindex.ts +0 -55
- package/src/commands/materialization/getmaterialization.ts +0 -57
- package/src/commands/materialization/getpreaggregate.ts +0 -58
- package/src/commands/materialization/getrun.ts +0 -55
- package/src/commands/materialization/listindexes.ts +0 -69
- package/src/commands/materialization/listmaterializations.ts +0 -53
- package/src/commands/materialization/listpreaggregates.ts +0 -74
- package/src/commands/materialization/listruns.ts +0 -77
- package/src/commands/materialization/rerun.ts +0 -123
- package/src/commands/misc/login.spec.ts +0 -371
- package/src/commands/misc/login.ts +0 -343
- package/src/commands/misc/logout.spec.ts +0 -32
- package/src/commands/misc/logout.ts +0 -9
- package/src/commands/misc/loopbackOAuth.ts +0 -127
- package/src/commands/misc/set-access-token.spec.ts +0 -95
- package/src/commands/misc/set-access-token.ts +0 -32
- package/src/commands/package/deletepackage.spec.ts +0 -164
- package/src/commands/package/deletepackage.ts +0 -58
- package/src/commands/package/listpackages.spec.ts +0 -163
- package/src/commands/package/listpackages.ts +0 -74
- package/src/commands/package/publish.spec.ts +0 -642
- package/src/commands/package/publish.ts +0 -236
- package/src/commands/package/updatepackage.spec.ts +0 -319
- package/src/commands/package/updatepackage.ts +0 -95
- package/src/commands/permission/createpermission.spec.ts +0 -507
- package/src/commands/permission/createpermission.ts +0 -181
- package/src/commands/permission/deletepermission.ts +0 -117
- package/src/commands/permission/getpermission.ts +0 -115
- package/src/commands/permission/listpermissions.ts +0 -101
- package/src/commands/permission/scope.ts +0 -180
- package/src/commands/rm.ts +0 -146
- package/src/commands/set.ts +0 -25
- package/src/commands/update.ts +0 -107
- package/src/commands/version/archive-unarchive-version.spec.ts +0 -456
- package/src/commands/version/archive-unarchive-version.ts +0 -108
- package/src/commands/version/listversions.spec.ts +0 -138
- package/src/commands/version/listversions.ts +0 -45
- package/src/common/UserGroupId.spec.ts +0 -115
- package/src/common/UserGroupId.ts +0 -137
- package/src/constants.spec.ts +0 -111
- package/src/constants.ts +0 -228
- package/src/index.ts +0 -378
- package/src/logger.spec.ts +0 -158
- package/src/logger.ts +0 -90
- package/src/polyfills/file.polyfill.ts +0 -6
- package/src/utils.spec.ts +0 -135
- package/src/utils.ts +0 -115
- package/src/validator.spec.ts +0 -51
- package/src/validator.ts +0 -44
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.LOG_DRAIN_WAIT_MS = exports.TOKEN_CHECK_INTERVAL_MS = exports.SESSION_PID_FILE = exports.RELOAD_TOOL = void 0;
|
|
16
|
+
exports.npxLauncher = npxLauncher;
|
|
17
|
+
exports.publisherLogPath = publisherLogPath;
|
|
18
|
+
exports.isShownLine = isShownLine;
|
|
19
|
+
exports.startPublisher = startPublisher;
|
|
20
|
+
exports.startTokenLoop = startTokenLoop;
|
|
21
|
+
exports.toolCallFailure = toolCallFailure;
|
|
22
|
+
const child_process_1 = require("child_process");
|
|
23
|
+
const fs_1 = __importDefault(require("fs"));
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const host_1 = require("./host");
|
|
26
|
+
const publisherconfig_1 = require("./publisherconfig");
|
|
27
|
+
const writefile_1 = require("./writefile");
|
|
28
|
+
const readylines_1 = require("./readylines");
|
|
29
|
+
const refresh_1 = require("./refresh");
|
|
30
|
+
/**
|
|
31
|
+
* The MCP tool that reloads a package. Publisher renamed its tools to bare
|
|
32
|
+
* names in 0.2.x (`malloy_reloadPackage` → `reload_package`), and a renewal
|
|
33
|
+
* that calls a tool the server does not have fails silently: the token is
|
|
34
|
+
* rewritten on disk and the running server never learns of it. Pinned here,
|
|
35
|
+
* next to the publisher version it has to match.
|
|
36
|
+
*/
|
|
37
|
+
exports.RELOAD_TOOL = "reload_package";
|
|
38
|
+
/**
|
|
39
|
+
* Running and babysitting the local Publisher.
|
|
40
|
+
*
|
|
41
|
+
* This is what both `cred init`'s last step and `cred dev` hand off to — one
|
|
42
|
+
* supervisor, so re-entering a session tomorrow is the same code path as
|
|
43
|
+
* starting one today.
|
|
44
|
+
*
|
|
45
|
+
* Three jobs, and the second is the one that is easy to get wrong:
|
|
46
|
+
*
|
|
47
|
+
* 1. Spawn the server with the config and ports it was given.
|
|
48
|
+
* 2. Decide whether it actually came up. Both ports bind and both "listening
|
|
49
|
+
* at" lines print even when every configured environment failed to load, so
|
|
50
|
+
* "the process is alive" is not readiness. The `PUBLISHER_READY` counts are.
|
|
51
|
+
* 3. Keep the warehouse token alive. A `publisher` connection's token is a
|
|
52
|
+
* static JWT in a config file and the server has no refresh hook yet, so
|
|
53
|
+
* without this the session dies mid-use and surfaces as a confusing query
|
|
54
|
+
* error. Deleted wholesale once the upstream `tokenCommand` hook lands.
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* The file in the session directory that holds the running publisher's pid.
|
|
58
|
+
* Present only while a session runs, like the stamped config beside it; see
|
|
59
|
+
* `isOwnSessionRunning` in `flow.ts` for why both are checked.
|
|
60
|
+
*/
|
|
61
|
+
exports.SESSION_PID_FILE = "publisher.pid";
|
|
62
|
+
/** How long to wait for a readiness verdict before giving up on the spawn. */
|
|
63
|
+
const BOOT_TIMEOUT_MS = 120000;
|
|
64
|
+
/** How often to check whether the warehouse token needs renewing. */
|
|
65
|
+
exports.TOKEN_CHECK_INTERVAL_MS = 60000;
|
|
66
|
+
/**
|
|
67
|
+
* How long one renewal call to the server may take. Shorter than the tick, so a
|
|
68
|
+
* wedged server fails the call and the next tick retries it — without a bound,
|
|
69
|
+
* fetch waits out undici's five-minute default.
|
|
70
|
+
*/
|
|
71
|
+
const RELOAD_TIMEOUT_MS = 30000;
|
|
72
|
+
/**
|
|
73
|
+
* How long a SIGTERM has to work before we stop asking and use SIGKILL.
|
|
74
|
+
*
|
|
75
|
+
* A publisher wedged mid-compile does not service signals, and SIGTERM alone
|
|
76
|
+
* left `waitUntilStopped` blocked on a child that was never going to exit — a
|
|
77
|
+
* second Ctrl-C only sent another SIGTERM, so the way out was killing the CLI
|
|
78
|
+
* from another tab, which is exactly the path that skips the config cleanup and
|
|
79
|
+
* leaves a token on disk. Escalating is what makes the cleanup reachable.
|
|
80
|
+
*
|
|
81
|
+
* Five seconds because the graceful path is worth waiting for: it lets the
|
|
82
|
+
* server close its DuckDB handles rather than leaving `publisher_data/` for the
|
|
83
|
+
* next run to recover.
|
|
84
|
+
*/
|
|
85
|
+
const SIGKILL_AFTER_MS = 5000;
|
|
86
|
+
/**
|
|
87
|
+
* How long a failed boot waits for the child to close and the log file to be
|
|
88
|
+
* written out before it throws. The caller exits the process as soon as this
|
|
89
|
+
* throws, and the failure message sends people to the log. Bounded, so a
|
|
90
|
+
* child that ignores SIGTERM cannot hold the CLI open.
|
|
91
|
+
*/
|
|
92
|
+
exports.LOG_DRAIN_WAIT_MS = 2000;
|
|
93
|
+
/** Windows has neither process groups nor POSIX signals. */
|
|
94
|
+
const SUPPORTS_PROCESS_GROUPS = process.platform !== "win32";
|
|
95
|
+
/**
|
|
96
|
+
* Signal the child and everything it launched.
|
|
97
|
+
*
|
|
98
|
+
* `npx` launches the server as a further child, so signalling the `npx` pid can
|
|
99
|
+
* leave the server running and holding both ports. Negating the pid targets the
|
|
100
|
+
* process group instead, which the spawn put the whole tree into. Falls back to
|
|
101
|
+
* the plain kill where there are no process groups, or if the group is already
|
|
102
|
+
* gone (ESRCH) — a race we can only lose harmlessly.
|
|
103
|
+
*/
|
|
104
|
+
function killTree(child, signal) {
|
|
105
|
+
if (SUPPORTS_PROCESS_GROUPS && child.pid) {
|
|
106
|
+
try {
|
|
107
|
+
process.kill(-child.pid, signal);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
catch (_a) {
|
|
111
|
+
// Group already reaped, or never created. Fall through.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
child.kill(signal);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* How to run `npx` without a shell.
|
|
118
|
+
*
|
|
119
|
+
* On Windows `npx` is `npx.cmd`, which a shell-less `spawn` cannot launch
|
|
120
|
+
* (ENOENT), and Node refuses to spawn a `.cmd` without a shell at all since the
|
|
121
|
+
* CVE-2024-27980 fix. A shell would re-parse the arguments, including paths
|
|
122
|
+
* with spaces in them. So on Windows this runs npx's own script with the node
|
|
123
|
+
* binary that is running us, from where the Node installer puts it.
|
|
124
|
+
*/
|
|
125
|
+
function npxLauncher(platform = process.platform, execPath = process.execPath, exists = fs_1.default.existsSync) {
|
|
126
|
+
if (platform !== "win32")
|
|
127
|
+
return { command: "npx", args: [] };
|
|
128
|
+
const script = path_1.default.join(path_1.default.dirname(execPath), "node_modules", "npm", "bin", "npx-cli.js");
|
|
129
|
+
if (!exists(script)) {
|
|
130
|
+
throw new host_1.SetupError(`Could not find npx next to ${execPath} (looked for ${script}).`, "install Node.js with npm from nodejs.org, or run cred from a Node that has npm beside it.");
|
|
131
|
+
}
|
|
132
|
+
return { command: execPath, args: [script] };
|
|
133
|
+
}
|
|
134
|
+
/** The escalation timer per child, so a repeated stop does not stack them. */
|
|
135
|
+
const pendingKill = new WeakMap();
|
|
136
|
+
/**
|
|
137
|
+
* Ask the tree to stop, and make sure it does.
|
|
138
|
+
*
|
|
139
|
+
* SIGTERM first, so a healthy server shuts down cleanly; SIGKILL after
|
|
140
|
+
* {@link SIGKILL_AFTER_MS} if it is still there. The timer is `unref`'d and
|
|
141
|
+
* cleared on exit, so a server that goes straight away leaves nothing holding
|
|
142
|
+
* the event loop open — the escalation must not be the reason the CLI lingers
|
|
143
|
+
* for five seconds on every ordinary Ctrl-C.
|
|
144
|
+
*
|
|
145
|
+
* Idempotent: a second Ctrl-C re-sends SIGTERM but does not stack a second
|
|
146
|
+
* timer, because the first one is already counting and a second would just fire
|
|
147
|
+
* later against a pid that is gone.
|
|
148
|
+
*/
|
|
149
|
+
function stopTree(child, host) {
|
|
150
|
+
var _a;
|
|
151
|
+
killTree(child, "SIGTERM");
|
|
152
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
153
|
+
return;
|
|
154
|
+
if (pendingKill.has(child))
|
|
155
|
+
return;
|
|
156
|
+
const timer = setTimeout(() => {
|
|
157
|
+
pendingKill.delete(child);
|
|
158
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
159
|
+
return;
|
|
160
|
+
host.log("warn", `The publisher did not stop within ${SIGKILL_AFTER_MS / 1000}s, so it was killed. If this repeats, the session directory may hold a stale publisher_data/.`);
|
|
161
|
+
killTree(child, "SIGKILL");
|
|
162
|
+
}, SIGKILL_AFTER_MS);
|
|
163
|
+
(_a = timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
|
|
164
|
+
pendingKill.set(child, timer);
|
|
165
|
+
child.once("exit", () => {
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
pendingKill.delete(child);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Where a session's full server output goes: the directory's own `.credible/`,
|
|
172
|
+
* which setup keeps out of commits and `cred publish` never uploads. Truncated
|
|
173
|
+
* at each start, so it holds one session.
|
|
174
|
+
*/
|
|
175
|
+
function publisherLogPath(directory) {
|
|
176
|
+
return path_1.default.join(directory, ".credible", "publisher.log");
|
|
177
|
+
}
|
|
178
|
+
// The level winston's `simple` format puts first, after any colour codes.
|
|
179
|
+
// eslint-disable-next-line no-control-regex
|
|
180
|
+
const ANSI = /\x1b\[[0-9;]*m/g;
|
|
181
|
+
/**
|
|
182
|
+
* Whether a line of the server's output is shown in the terminal by default.
|
|
183
|
+
*
|
|
184
|
+
* The full boot log read as alarming and was mostly noise: the server rebuilds
|
|
185
|
+
* its throwaway local store each start (`--init`), logging "dropping and
|
|
186
|
+
* recreating all tables" and a line per dropped table, and it warns about a
|
|
187
|
+
* memory setting that only matters in a container. What a person at this
|
|
188
|
+
* terminal needs is what goes wrong, so:
|
|
189
|
+
*
|
|
190
|
+
* - The server's `error:` lines. A failed watch-mode recompile is one of these
|
|
191
|
+
* (`logger.error("Watch: failed to recompile …")` in the Publisher's
|
|
192
|
+
* `watch-mode.controller.ts`), and it is the reason this terminal exists.
|
|
193
|
+
* - The one `info:` line that says a watch-mode recompile worked
|
|
194
|
+
* (`Watch: recompiled package …`). Without it the last thing on screen after
|
|
195
|
+
* a fixed model is still the error, and nothing says the error is gone.
|
|
196
|
+
* - Anything else on stderr, which is where the server writes
|
|
197
|
+
* `PUBLISHER_INIT_FAILED`, a model's compile error with its caret, and a
|
|
198
|
+
* crash's message. Except npm's own notices, the `PUBLISHER_READY` line, and
|
|
199
|
+
* stack frames.
|
|
200
|
+
*
|
|
201
|
+
* Every other `warn:` and `info:` line is in the log file only.
|
|
202
|
+
*
|
|
203
|
+
* The same two rules apply to the server's JSON lines. It logs JSON instead of
|
|
204
|
+
* the text format when `OTEL_EXPORTER_OTLP_ENDPOINT` is set (`logger.ts` in the
|
|
205
|
+
* Publisher), and a user's environment reaches the child.
|
|
206
|
+
*/
|
|
207
|
+
function isShownLine(line, stream) {
|
|
208
|
+
const plain = line.replace(ANSI, "").trim();
|
|
209
|
+
if (!plain)
|
|
210
|
+
return false;
|
|
211
|
+
if (/^error\b/i.test(plain))
|
|
212
|
+
return true;
|
|
213
|
+
if (/^info\b.*\bWatch: recompiled package\b/i.test(plain))
|
|
214
|
+
return true;
|
|
215
|
+
const entry = jsonLogEntry(plain);
|
|
216
|
+
if ((entry === null || entry === void 0 ? void 0 : entry.level) === "error")
|
|
217
|
+
return true;
|
|
218
|
+
if ((entry === null || entry === void 0 ? void 0 : entry.level) === "info" &&
|
|
219
|
+
/\bWatch: recompiled package\b/.test(entry.message)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
if (stream !== "stderr")
|
|
223
|
+
return false;
|
|
224
|
+
// npm's notices are about the launcher; `PUBLISHER_READY` is a machine line
|
|
225
|
+
// that `cred` answers with its own "serving" line; and a stack's frames
|
|
226
|
+
// follow the message that says what went wrong, which is shown.
|
|
227
|
+
return !/^(npm (warn|notice)\b|PUBLISHER_READY\b|at )/i.test(plain);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The level and message of a line in winston's JSON format, or undefined for
|
|
231
|
+
* any other line. Its keys are sorted, so `level` is not first.
|
|
232
|
+
*/
|
|
233
|
+
function jsonLogEntry(plain) {
|
|
234
|
+
if (!plain.startsWith("{"))
|
|
235
|
+
return undefined;
|
|
236
|
+
try {
|
|
237
|
+
const parsed = JSON.parse(plain);
|
|
238
|
+
if (!parsed || typeof parsed !== "object")
|
|
239
|
+
return undefined;
|
|
240
|
+
const { level, message } = parsed;
|
|
241
|
+
if (typeof level !== "string")
|
|
242
|
+
return undefined;
|
|
243
|
+
return {
|
|
244
|
+
level: level.toLowerCase(),
|
|
245
|
+
message: typeof message === "string" ? message : "",
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
catch (_a) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** Open the session's log file, or undefined when it cannot be written. */
|
|
253
|
+
function openLogFile(logPath) {
|
|
254
|
+
try {
|
|
255
|
+
fs_1.default.mkdirSync(path_1.default.dirname(logPath), { recursive: true });
|
|
256
|
+
// `openSync` first, so a failure is thrown here rather than emitted later
|
|
257
|
+
// on the stream, where nothing would see it.
|
|
258
|
+
const fd = fs_1.default.openSync(logPath, "w");
|
|
259
|
+
const stream = fs_1.default.createWriteStream("", { fd });
|
|
260
|
+
// A later write error (a full disk) must not crash the session: the log
|
|
261
|
+
// is a copy, and the terminal still shows the errors.
|
|
262
|
+
stream.on("error", () => undefined);
|
|
263
|
+
return stream;
|
|
264
|
+
}
|
|
265
|
+
catch (_a) {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Write the config with a live access token in it, ready for the server to read.
|
|
271
|
+
*
|
|
272
|
+
* This file is a credential for as long as a session runs. Two things follow,
|
|
273
|
+
* and both are load-bearing rather than tidiness: it is written 0600, inside the
|
|
274
|
+
* 0700 session directory that `flow.ts` chose for exactly this reason, so no
|
|
275
|
+
* other account on the machine can read the token; and it is removed by
|
|
276
|
+
* {@link discardConfig} when the session ends, so a token does not outlive the
|
|
277
|
+
* process that needed it.
|
|
278
|
+
*/
|
|
279
|
+
function writeStampedConfig(options) {
|
|
280
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
281
|
+
const outcome = yield (0, refresh_1.ensureFreshTokens)(options.credStore);
|
|
282
|
+
if (outcome.status === "logged-out") {
|
|
283
|
+
return { status: "failed", reason: outcome.reason };
|
|
284
|
+
}
|
|
285
|
+
let warning;
|
|
286
|
+
if (outcome.status === "offline") {
|
|
287
|
+
// Carrying on is only true while the token on disk still works. Once it
|
|
288
|
+
// has expired, saying so while every query 401s is the wrong message, so
|
|
289
|
+
// it becomes a failure and the caller says to run `cred login`.
|
|
290
|
+
if (!options.credStore.isTokenValid().valid) {
|
|
291
|
+
return {
|
|
292
|
+
status: "failed",
|
|
293
|
+
reason: `${outcome.reason} The token on disk has expired.`,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
warning = `${outcome.reason} Continuing with the token on disk.`;
|
|
297
|
+
}
|
|
298
|
+
if (outcome.status === "not-renewable") {
|
|
299
|
+
warning = outcome.reason;
|
|
300
|
+
}
|
|
301
|
+
const token = options.credStore.getApiAccessToken();
|
|
302
|
+
if (!token) {
|
|
303
|
+
return {
|
|
304
|
+
status: "failed",
|
|
305
|
+
reason: "No access token available. Run `cred login`.",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
(0, writefile_1.writeFileAtomic)(options.configPath, `${JSON.stringify((0, publisherconfig_1.stampAccessToken)(options.config, token), null, 3)}\n`, { mode: 0o600 });
|
|
309
|
+
return { status: "ok", token, warning };
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Remove the config once nothing needs it.
|
|
314
|
+
*
|
|
315
|
+
* Best-effort on purpose: failing to delete it must not turn a clean shutdown
|
|
316
|
+
* into an error, and the 0700 directory means an undeleted file is still not
|
|
317
|
+
* readable by anyone else. A `kill -9` skips this, which is the residual case
|
|
318
|
+
* the directory mode covers.
|
|
319
|
+
*/
|
|
320
|
+
function discardConfig(configPath) {
|
|
321
|
+
for (const file of [
|
|
322
|
+
configPath,
|
|
323
|
+
path_1.default.join(path_1.default.dirname(configPath), exports.SESSION_PID_FILE),
|
|
324
|
+
]) {
|
|
325
|
+
try {
|
|
326
|
+
fs_1.default.unlinkSync(file);
|
|
327
|
+
}
|
|
328
|
+
catch (_a) {
|
|
329
|
+
// Already gone, or not ours to remove.
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Start the publisher and wait for a readiness verdict.
|
|
335
|
+
*
|
|
336
|
+
* Resolves only once the server has reported itself ready AND that report says
|
|
337
|
+
* it is serving something. Anything else — an init failure, a premature exit, a
|
|
338
|
+
* timeout, a ready-but-empty server — throws with what the server said.
|
|
339
|
+
*/
|
|
340
|
+
function startPublisher(options) {
|
|
341
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
342
|
+
var _a, _b, _c, _d, _e;
|
|
343
|
+
// Before the token is written, so a refusal leaves no credential behind.
|
|
344
|
+
const launcher = npxLauncher();
|
|
345
|
+
const stamped = yield writeStampedConfig(options);
|
|
346
|
+
if (stamped.status === "failed") {
|
|
347
|
+
throw new host_1.SetupError(stamped.reason);
|
|
348
|
+
}
|
|
349
|
+
if (stamped.warning)
|
|
350
|
+
options.host.log("warn", stamped.warning);
|
|
351
|
+
const logPath = publisherLogPath(options.directory);
|
|
352
|
+
const logFile = openLogFile(logPath);
|
|
353
|
+
// With no file to put it in, the output would be lost, so it all shows here.
|
|
354
|
+
const showAll = Boolean(options.showAllOutput) || !logFile;
|
|
355
|
+
const where = logFile
|
|
356
|
+
? path_1.default.relative(process.cwd(), logPath) || logPath
|
|
357
|
+
: undefined;
|
|
358
|
+
options.host.log("info", `Starting the local Publisher (${options.publisherVersion}). The first run downloads it, which takes about 30 seconds.${where && !options.showAllOutput
|
|
359
|
+
? ` Its errors show here; its full output is in ${where} (--debug shows it all here).`
|
|
360
|
+
: ""}`);
|
|
361
|
+
/** Where to read the rest, for a failure message. */
|
|
362
|
+
const outputIs = showAll
|
|
363
|
+
? "Its output is above."
|
|
364
|
+
: `Its output is in ${where}.`;
|
|
365
|
+
const child = (0, child_process_1.spawn)(launcher.command, [
|
|
366
|
+
...launcher.args,
|
|
367
|
+
"-y",
|
|
368
|
+
`@malloy-publisher/server@${options.publisherVersion}`,
|
|
369
|
+
"--server_root",
|
|
370
|
+
options.serverRoot,
|
|
371
|
+
// Rebuild the server's store from the config this run just wrote.
|
|
372
|
+
// Without it the server trusts its `publisher.db` from the last session
|
|
373
|
+
// over the config, so every session after the first in a directory
|
|
374
|
+
// served that first session's long-expired warehouse token, and ignored
|
|
375
|
+
// a changed environment or connection list.
|
|
376
|
+
"--init",
|
|
377
|
+
// Absolute, so it does not have to resolve against server_root.
|
|
378
|
+
"--config",
|
|
379
|
+
path_1.default.resolve(options.configPath),
|
|
380
|
+
"--host",
|
|
381
|
+
"127.0.0.1",
|
|
382
|
+
"--port",
|
|
383
|
+
String(options.uiPort),
|
|
384
|
+
"--mcp_port",
|
|
385
|
+
String(options.mcpPort),
|
|
386
|
+
"--watch-env",
|
|
387
|
+
options.watchEnvironment,
|
|
388
|
+
], {
|
|
389
|
+
cwd: options.serverRoot,
|
|
390
|
+
env: Object.assign(Object.assign(Object.assign({}, process.env), {
|
|
391
|
+
// Set only for this child. Never documented as something a user
|
|
392
|
+
// exports: in a hosted deployment this flag opens an SSRF surface,
|
|
393
|
+
// and it is default-deny for that reason.
|
|
394
|
+
PUBLISHER_ALLOW_PROXY_CONNECTIONS: "true",
|
|
395
|
+
// This terminal exists to show one thing: a failed recompile, which
|
|
396
|
+
// watch mode writes to stdout and nowhere else. The server's
|
|
397
|
+
// defaults bury that. It logs at `debug` unless told otherwise, and
|
|
398
|
+
// logs every HTTP response — so opening the UI emits a line per
|
|
399
|
+
// asset, and the compile error a user is looking for scrolls away
|
|
400
|
+
// behind `GET /assets/index-*.js 200`.
|
|
401
|
+
//
|
|
402
|
+
// Both are the server's own knobs (`getLogLevel`,
|
|
403
|
+
// `DISABLE_RESPONSE_LOGGING` in its `server.mjs`), which is why this
|
|
404
|
+
// is set here rather than filtered out of the stream: matching its
|
|
405
|
+
// log lines with our own patterns would be a second, guessed copy of
|
|
406
|
+
// a decision it already exposes. A user who wants the firehose can
|
|
407
|
+
// still set LOG_LEVEL themselves — `...process.env` comes first, so
|
|
408
|
+
// their value wins.
|
|
409
|
+
LOG_LEVEL: (_a = process.env.LOG_LEVEL) !== null && _a !== void 0 ? _a : "info", DISABLE_RESPONSE_LOGGING: (_b = process.env.DISABLE_RESPONSE_LOGGING) !== null && _b !== void 0 ? _b : "true" }), (process.env.npm_config_loglevel === undefined &&
|
|
410
|
+
process.env.NPM_CONFIG_LOGLEVEL === undefined
|
|
411
|
+
? { npm_config_loglevel: "error" }
|
|
412
|
+
: {})),
|
|
413
|
+
// `npx` is a launcher: the server runs as its child, not as `npx`
|
|
414
|
+
// itself. Signalling `npx` alone is not guaranteed to reach the
|
|
415
|
+
// server, and an orphaned server keeps both ports — which surfaces
|
|
416
|
+
// later as the next `cred dev` failing to allocate, blaming "whatever
|
|
417
|
+
// is holding ports", when the culprit is the previous run. Its own
|
|
418
|
+
// process group makes the whole tree signalable in one call. Not on
|
|
419
|
+
// Windows, which has no process groups and no POSIX signals.
|
|
420
|
+
detached: SUPPORTS_PROCESS_GROUPS,
|
|
421
|
+
});
|
|
422
|
+
// Beside the config, so "this directory's session is running" can ask
|
|
423
|
+
// whether this process is alive rather than trusting a file that a
|
|
424
|
+
// `kill -9` or a reboot leaves behind.
|
|
425
|
+
if (child.pid) {
|
|
426
|
+
(0, writefile_1.writeFileAtomic)(path_1.default.join(path_1.default.dirname(options.configPath), exports.SESSION_PID_FILE), `${child.pid}\n`);
|
|
427
|
+
}
|
|
428
|
+
// From here until the child exits, a Ctrl-C has to stop the child. It runs
|
|
429
|
+
// in its own process group, so the terminal's SIGINT reaches only us, and
|
|
430
|
+
// the host's default — exit — would leave it serving on both ports with the
|
|
431
|
+
// token file on disk. Subscribed now rather than after readiness because
|
|
432
|
+
// the boot wait can be two minutes, and that is when people press Ctrl-C.
|
|
433
|
+
let interrupted = false;
|
|
434
|
+
const unsubscribeInterrupt = (_e = (_d = (_c = options.host).onInterrupt) === null || _d === void 0 ? void 0 : _d.call(_c, () => {
|
|
435
|
+
interrupted = true;
|
|
436
|
+
stopTree(child, options.host);
|
|
437
|
+
})) !== null && _e !== void 0 ? _e : (() => undefined);
|
|
438
|
+
child.once("exit", () => unsubscribeInterrupt());
|
|
439
|
+
// Bound ports come from the listening lines; readiness comes from the
|
|
440
|
+
// PUBLISHER_READY line. We need both: the first for the URLs, the second to
|
|
441
|
+
// know whether the server is worth pointing anyone at.
|
|
442
|
+
let boundMcpPort = options.mcpPort;
|
|
443
|
+
let boundUiPort = options.uiPort;
|
|
444
|
+
// What the server says it bound, not what we asked for. They differ when a
|
|
445
|
+
// flag does not land — a mistyped `--host` falls back to a wildcard bind —
|
|
446
|
+
// and the whole point of reading the line is to dial what is actually there.
|
|
447
|
+
let boundMcpHost = "127.0.0.1";
|
|
448
|
+
let boundUiHost = "127.0.0.1";
|
|
449
|
+
// Subscribed now so the event cannot be missed. The log file is ended on
|
|
450
|
+
// the child's `close` (below), and has reached the disk once it closes.
|
|
451
|
+
const logClosed = new Promise((resolve) => {
|
|
452
|
+
if (logFile)
|
|
453
|
+
logFile.once("close", () => resolve());
|
|
454
|
+
else
|
|
455
|
+
child.once("close", () => resolve());
|
|
456
|
+
});
|
|
457
|
+
/**
|
|
458
|
+
* Wait for the log to reach the disk, but not forever: a grandchild that
|
|
459
|
+
* outlives the server can hold its stdio open, and then `close` never comes.
|
|
460
|
+
*/
|
|
461
|
+
const logDrained = () => __awaiter(this, void 0, void 0, function* () {
|
|
462
|
+
let drainTimer;
|
|
463
|
+
yield Promise.race([
|
|
464
|
+
logClosed,
|
|
465
|
+
new Promise((resolve) => {
|
|
466
|
+
drainTimer = setTimeout(resolve, exports.LOG_DRAIN_WAIT_MS);
|
|
467
|
+
}),
|
|
468
|
+
]);
|
|
469
|
+
clearTimeout(drainTimer);
|
|
470
|
+
});
|
|
471
|
+
const verdict = yield new Promise((resolve) => {
|
|
472
|
+
var _a, _b;
|
|
473
|
+
let settled = false;
|
|
474
|
+
const finish = (result) => {
|
|
475
|
+
if (settled)
|
|
476
|
+
return;
|
|
477
|
+
settled = true;
|
|
478
|
+
clearTimeout(timer);
|
|
479
|
+
resolve(result);
|
|
480
|
+
};
|
|
481
|
+
const timer = setTimeout(() => finish({
|
|
482
|
+
status: "failed",
|
|
483
|
+
reason: `the publisher did not report readiness within ${BOOT_TIMEOUT_MS / 1000}s. ${outputIs}`,
|
|
484
|
+
}), BOOT_TIMEOUT_MS);
|
|
485
|
+
/** Returns true once a line has settled the verdict. */
|
|
486
|
+
const readLine = (line) => {
|
|
487
|
+
const endpoint = (0, readylines_1.parseReadyLine)(line);
|
|
488
|
+
if ((endpoint === null || endpoint === void 0 ? void 0 : endpoint.which) === "mcp") {
|
|
489
|
+
boundMcpPort = endpoint.port;
|
|
490
|
+
boundMcpHost = endpoint.host;
|
|
491
|
+
}
|
|
492
|
+
if ((endpoint === null || endpoint === void 0 ? void 0 : endpoint.which) === "ui") {
|
|
493
|
+
boundUiPort = endpoint.port;
|
|
494
|
+
boundUiHost = endpoint.host;
|
|
495
|
+
}
|
|
496
|
+
const failure = (0, readylines_1.parseInitFailedLine)(line);
|
|
497
|
+
if (failure) {
|
|
498
|
+
finish({ status: "failed", reason: failure });
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
const readiness = (0, readylines_1.parseReadinessLine)(line);
|
|
502
|
+
if (readiness) {
|
|
503
|
+
const verdict = (0, readylines_1.readinessVerdict)(readiness);
|
|
504
|
+
finish(verdict.kind === "fatal"
|
|
505
|
+
? { status: "failed", reason: verdict.reason }
|
|
506
|
+
: verdict.kind === "degraded"
|
|
507
|
+
? { status: "degraded", reason: verdict.reason }
|
|
508
|
+
: { status: "ok" });
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
return false;
|
|
512
|
+
};
|
|
513
|
+
// One buffer per stream, not one shared by both. stdout and stderr are
|
|
514
|
+
// independent and unordered, so a shared splice point lets an stderr
|
|
515
|
+
// write land *inside* a stdout line that arrived in two chunks:
|
|
516
|
+
// `PUBLISHER_READY ... envir` + `warn: ...` + `onments=1 ...` splits into
|
|
517
|
+
// two lines, the first of which still carries the marker but has lost the
|
|
518
|
+
// counts. `parseReadinessLine` then returns undefined, the verdict is
|
|
519
|
+
// never reached, and a healthy server dies on the boot timeout — as an
|
|
520
|
+
// intermittent failure nobody can reproduce on demand. The publisher does
|
|
521
|
+
// write to stderr in this window: `PUBLISHER_INIT_FAILED` goes there, and
|
|
522
|
+
// LOG_LEVEL=info keeps warnings flowing.
|
|
523
|
+
const makeConsumer = (stream) => {
|
|
524
|
+
let buffer = "";
|
|
525
|
+
return (chunk) => {
|
|
526
|
+
var _a;
|
|
527
|
+
const text = chunk.toString();
|
|
528
|
+
logFile === null || logFile === void 0 ? void 0 : logFile.write(text);
|
|
529
|
+
// Watch mode swallows failed recompiles to stdout by design, so
|
|
530
|
+
// this terminal is the only place a human sees them. That is the
|
|
531
|
+
// whole reason the session runs in the foreground. Verbatim,
|
|
532
|
+
// because the text already has the server's own level and colours
|
|
533
|
+
// on it — see `Host.write`.
|
|
534
|
+
if (showAll)
|
|
535
|
+
options.host.write(text);
|
|
536
|
+
buffer += text;
|
|
537
|
+
const lines = buffer.split("\n");
|
|
538
|
+
// Keep a possibly-partial trailing line for the next chunk, so a
|
|
539
|
+
// readiness line split across chunks is not read as truncated.
|
|
540
|
+
buffer = (_a = lines.pop()) !== null && _a !== void 0 ? _a : "";
|
|
541
|
+
for (const line of lines) {
|
|
542
|
+
// Before `readLine`, which can return early: the line that
|
|
543
|
+
// settles the verdict may be the error a person needs to see.
|
|
544
|
+
if (!showAll && isShownLine(line, stream)) {
|
|
545
|
+
options.host.write(`${line}\n`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (const line of lines) {
|
|
549
|
+
if (readLine(line))
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", makeConsumer("stdout"));
|
|
555
|
+
(_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", makeConsumer("stderr"));
|
|
556
|
+
// On `close`, not `exit`: stdio can still deliver the last chunks after
|
|
557
|
+
// `exit`, and a crash on boot prints its stack as it dies.
|
|
558
|
+
child.once("close", () => logFile === null || logFile === void 0 ? void 0 : logFile.end());
|
|
559
|
+
child.on("error", (error) => finish({
|
|
560
|
+
status: "failed",
|
|
561
|
+
reason: `could not start the publisher: ${error.message}`,
|
|
562
|
+
}));
|
|
563
|
+
child.on("exit", (code) => finish({
|
|
564
|
+
status: "failed",
|
|
565
|
+
reason: `the publisher exited with code ${code} before reporting readiness. ${outputIs}`,
|
|
566
|
+
}));
|
|
567
|
+
});
|
|
568
|
+
if (verdict.status === "failed") {
|
|
569
|
+
stopTree(child, options.host);
|
|
570
|
+
discardConfig(options.configPath);
|
|
571
|
+
// The caller exits the process as soon as this throws, and the message
|
|
572
|
+
// sends people to the log, so let the log finish first.
|
|
573
|
+
yield logDrained();
|
|
574
|
+
if (interrupted) {
|
|
575
|
+
throw new host_1.SetupError("Stopped before the local Publisher was ready. It has been shut down.");
|
|
576
|
+
}
|
|
577
|
+
throw new host_1.SetupError(`The local Publisher did not come up: ${verdict.reason}`, "fix the reported problem and run `cred dev` again.");
|
|
578
|
+
}
|
|
579
|
+
// A model that does not compile is the state a session is most needed in, not
|
|
580
|
+
// a reason to refuse one. The server is up, its connections are live, watch
|
|
581
|
+
// mode is active and `compile_model` works over MCP — so the fix loop is
|
|
582
|
+
// available, and saving the file reloads it. What changes is that there is
|
|
583
|
+
// nothing to look at yet, so the browser stays shut.
|
|
584
|
+
const serving = verdict.status === "ok";
|
|
585
|
+
if (!serving) {
|
|
586
|
+
options.host.log("warn", `The publisher is running, but ${verdict.reason}. Fix the model and save — watch mode reloads it, and no restart is needed.`);
|
|
587
|
+
}
|
|
588
|
+
const uiUrl = `http://localhost:${boundUiPort}`;
|
|
589
|
+
// An IP literal rather than `localhost`, deliberately: an agent reads this
|
|
590
|
+
// out of `.mcp.json`, and `localhost` can resolve to `::1` on a host whose
|
|
591
|
+
// resolver prefers IPv6, where the server is not listening. `dialableHost`
|
|
592
|
+
// maps what the server actually bound — including a wildcard bind, which is
|
|
593
|
+
// not dialable — onto something that can be connected to. Bracketed because
|
|
594
|
+
// an IPv6 literal in a URL has to be.
|
|
595
|
+
const mcpUrl = `${dialableOrigin(boundMcpHost, boundMcpPort)}/mcp`;
|
|
596
|
+
const apiUrl = dialableOrigin(boundUiHost, boundUiPort);
|
|
597
|
+
// The URLs the server actually bound, not the ones we asked for: the
|
|
598
|
+
// renewal loop has to reach the same endpoints an agent does.
|
|
599
|
+
const stopTokenLoop = startTokenLoop(options, child, { mcpUrl, apiUrl }, stamped.token);
|
|
600
|
+
// Bound to the child's exit, not to `waitForExit` being called: the token
|
|
601
|
+
// must go when the server does, whether or not anyone is waiting on it.
|
|
602
|
+
// A caller that starts a session and drops it still leaves no credential
|
|
603
|
+
// behind.
|
|
604
|
+
//
|
|
605
|
+
// The same handler latches the exit code, because `waitForExit` subscribes
|
|
606
|
+
// only when the caller invokes it — and there is real time before that: the
|
|
607
|
+
// `openUrl` below awaits a full `exec()` of the OS browser command, which is
|
|
608
|
+
// the default path. A publisher that dies in that window fires its one
|
|
609
|
+
// `exit` event with nobody subscribed, so a promise created afterwards never
|
|
610
|
+
// settles. Nothing then holds the event loop (the child is reaped and the
|
|
611
|
+
// token-loop interval is `unref`'d), so the process ends with `exitCode`
|
|
612
|
+
// never set — reporting success, after printing that the publisher is
|
|
613
|
+
// serving. An agent shelling out and checking the status reads clean.
|
|
614
|
+
let exitedWith;
|
|
615
|
+
child.once("exit", (code) => {
|
|
616
|
+
exitedWith = code;
|
|
617
|
+
discardConfig(options.configPath);
|
|
618
|
+
});
|
|
619
|
+
if (options.openBrowser && serving) {
|
|
620
|
+
yield options.host.openUrl(uiUrl);
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
uiUrl,
|
|
624
|
+
mcpUrl,
|
|
625
|
+
waitForExit: () => __awaiter(this, void 0, void 0, function* () {
|
|
626
|
+
// Already gone when `exitedWith` is set. The interval is then cleared
|
|
627
|
+
// by `startTokenLoop`'s own exit handler, so there is nothing to stop.
|
|
628
|
+
const code = exitedWith !== undefined
|
|
629
|
+
? exitedWith
|
|
630
|
+
: yield new Promise((resolve) => {
|
|
631
|
+
child.once("exit", (exitCode) => {
|
|
632
|
+
stopTokenLoop();
|
|
633
|
+
resolve(exitCode);
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
// `exit` comes before the last output is in the log file: stdio can
|
|
637
|
+
// still deliver after it, and the file is ended only on `close`.
|
|
638
|
+
yield logDrained();
|
|
639
|
+
return code;
|
|
640
|
+
}),
|
|
641
|
+
interrupted: () => interrupted,
|
|
642
|
+
stop: () => {
|
|
643
|
+
stopTokenLoop();
|
|
644
|
+
stopTree(child, options.host);
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
/** `http://host:port` for a host the server reported binding. */
|
|
650
|
+
function dialableOrigin(boundHost, port) {
|
|
651
|
+
const host = (0, readylines_1.dialableHost)(boundHost);
|
|
652
|
+
return `http://${host.includes(":") ? `[${host}]` : host}:${port}`;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Keep the warehouse token fresh for as long as the session runs.
|
|
656
|
+
*
|
|
657
|
+
* The server reads `accessToken` out of its config only at boot, so renewing
|
|
658
|
+
* means rewriting the config (for the next boot) and updating each `publisher`
|
|
659
|
+
* connection on the running server, which swaps the live credential. A
|
|
660
|
+
* `reload_package` alone recompiles against the connections the server already
|
|
661
|
+
* holds, so it answered 200 and the old token stayed live. A failed update
|
|
662
|
+
* keeps the old connection serving, so a bad refresh degrades to a stale token
|
|
663
|
+
* rather than a dead server.
|
|
664
|
+
*
|
|
665
|
+
* The loop remembers the token it last handed the server (`applied`, starting
|
|
666
|
+
* with the one the boot wrote), and pushes whenever `~/.cred` holds a different
|
|
667
|
+
* one. The expiry on disk alone is not enough: another `cred dev`, a `cred`
|
|
668
|
+
* command or the VS Code extension can refresh `~/.cred` first, and then the
|
|
669
|
+
* token on disk has hours left while this server still holds the old one. The
|
|
670
|
+
* same rule retries a push that failed, because `applied` only moves once the
|
|
671
|
+
* server has taken the token.
|
|
672
|
+
*
|
|
673
|
+
* Replaced entirely by the upstream `tokenCommand` hook when it lands: that
|
|
674
|
+
* makes the server fetch its own token via `cred token`, and this whole loop,
|
|
675
|
+
* plus the config rewriting, goes away.
|
|
676
|
+
*/
|
|
677
|
+
function startTokenLoop(options, child, endpoints, bootToken) {
|
|
678
|
+
var _a;
|
|
679
|
+
// One renewal at a time. The expiry check below reads the token on disk,
|
|
680
|
+
// which does not change until a renewal finishes writing it — so a renewal
|
|
681
|
+
// slower than the tick interval would let the next tick pass the same check
|
|
682
|
+
// and start a second one. Two concurrent redemptions of one refresh token is
|
|
683
|
+
// the worst possible race here: with Auth0 rotation on, the loser gets
|
|
684
|
+
// `invalid_grant`, which is indistinguishable from a genuinely dead token
|
|
685
|
+
// and takes the whole credential store with it (see `refresh.ts`). There is
|
|
686
|
+
// no timeout that makes that safe, so the guard is a flag, not a deadline.
|
|
687
|
+
let renewing = false;
|
|
688
|
+
let applied = bootToken;
|
|
689
|
+
// A push that failed for this token. Retried every tick, but warned about
|
|
690
|
+
// once: a line a minute would bury the compile errors this terminal is for.
|
|
691
|
+
let failedToApply;
|
|
692
|
+
// The last warning printed, so an Auth0 outage says so once rather than on
|
|
693
|
+
// every tick until it ends.
|
|
694
|
+
let lastWarning;
|
|
695
|
+
const warnOnce = (message) => {
|
|
696
|
+
if (message === lastWarning)
|
|
697
|
+
return;
|
|
698
|
+
lastWarning = message;
|
|
699
|
+
options.host.log("warn", message);
|
|
700
|
+
};
|
|
701
|
+
const timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
702
|
+
if (renewing)
|
|
703
|
+
return;
|
|
704
|
+
renewing = true;
|
|
705
|
+
try {
|
|
706
|
+
const remaining = options.credStore.secondsUntilExpiry();
|
|
707
|
+
const renewDue = remaining !== undefined && remaining <= refresh_1.REFRESH_SKEW_SECONDS;
|
|
708
|
+
if (!renewDue && options.credStore.getApiAccessToken() === applied) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const stamped = yield writeStampedConfig(options);
|
|
712
|
+
if (stamped.status === "failed") {
|
|
713
|
+
warnOnce(`Could not renew the warehouse token: ${stamped.reason} Queries may start failing until you run \`cred login\`.`);
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (stamped.warning)
|
|
717
|
+
warnOnce(stamped.warning);
|
|
718
|
+
// Offline with the token still valid: nothing new to hand over, so
|
|
719
|
+
// no request to the server and no "Renewed" line.
|
|
720
|
+
if (stamped.token === applied)
|
|
721
|
+
return;
|
|
722
|
+
try {
|
|
723
|
+
yield applyToken(options, endpoints, stamped.token);
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (failedToApply !== stamped.token) {
|
|
727
|
+
failedToApply = stamped.token;
|
|
728
|
+
options.host.log("warn", `Renewed the token but could not hand it to the publisher: ${error instanceof Error ? error.message : String(error)}. Retrying every minute.`);
|
|
729
|
+
}
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const retried = failedToApply === stamped.token;
|
|
733
|
+
applied = stamped.token;
|
|
734
|
+
failedToApply = undefined;
|
|
735
|
+
lastWarning = undefined;
|
|
736
|
+
options.host.log("info", retried
|
|
737
|
+
? "The publisher is using the renewed warehouse token."
|
|
738
|
+
: "Renewed the warehouse token.");
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
// Nothing awaits this callback, so a throw here is an unhandled
|
|
742
|
+
// rejection, and the CLI's handler for those exits the process. That
|
|
743
|
+
// skipped the shutdown: the publisher kept running and its token file
|
|
744
|
+
// stayed on disk. A corrupt or unreadable `~/.cred` was enough. Skip
|
|
745
|
+
// the tick instead, like every other failure in this loop.
|
|
746
|
+
options.host.log("warn", `Could not check the warehouse token: ${error instanceof Error ? error.message : String(error)}. Trying again in a minute.`);
|
|
747
|
+
}
|
|
748
|
+
finally {
|
|
749
|
+
renewing = false;
|
|
750
|
+
}
|
|
751
|
+
}), exports.TOKEN_CHECK_INTERVAL_MS);
|
|
752
|
+
// `unref` below stops this holding the event loop open; the child does that.
|
|
753
|
+
(_a = timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
|
|
754
|
+
child.once("exit", () => clearInterval(timer));
|
|
755
|
+
return () => clearInterval(timer);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Put `token` into the running server's connections, then reload.
|
|
759
|
+
*
|
|
760
|
+
* The connection update (`PATCH /api/v0/environments/:env/connections/:name`)
|
|
761
|
+
* is what swaps the live credential. The reload after it recompiles each
|
|
762
|
+
* package, so none keeps a connection built from the old token.
|
|
763
|
+
*/
|
|
764
|
+
function applyToken(options, endpoints, token) {
|
|
765
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
766
|
+
const stamped = (0, publisherconfig_1.stampAccessToken)(options.config, token);
|
|
767
|
+
for (const environment of stamped.environments) {
|
|
768
|
+
for (const connection of environment.connections) {
|
|
769
|
+
if (connection.type !== "publisher" ||
|
|
770
|
+
!connection.publisherConnection) {
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
const response = yield fetch(`${endpoints.apiUrl}/api/v0/environments/${encodeURIComponent(environment.name)}/connections/${encodeURIComponent(connection.name)}`, {
|
|
774
|
+
signal: AbortSignal.timeout(RELOAD_TIMEOUT_MS),
|
|
775
|
+
method: "PATCH",
|
|
776
|
+
headers: { "Content-Type": "application/json" },
|
|
777
|
+
// The whole sub-object: the server merges a patch one level deep.
|
|
778
|
+
body: JSON.stringify({
|
|
779
|
+
publisherConnection: connection.publisherConnection,
|
|
780
|
+
}),
|
|
781
|
+
});
|
|
782
|
+
if (!response.ok) {
|
|
783
|
+
throw new Error(`updating connection ${connection.name} returned HTTP ${response.status}`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
yield reloadPackages(options, endpoints.mcpUrl);
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Ask the running server to recompile each package.
|
|
792
|
+
*
|
|
793
|
+
* Uses the MCP endpoint's `reload_package` ({@link RELOAD_TOOL}). It recompiles
|
|
794
|
+
* against the connections the server holds, so it does not pick up a token by
|
|
795
|
+
* itself; {@link applyToken} updates the connections first.
|
|
796
|
+
*/
|
|
797
|
+
function reloadPackages(options, mcpUrl) {
|
|
798
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
799
|
+
var _a;
|
|
800
|
+
const packageNames = options.config.environments.flatMap((environment) => environment.packages.map((pkg) => pkg.name));
|
|
801
|
+
for (const name of packageNames) {
|
|
802
|
+
// `mcpUrl`, not `options.mcpPort`: the requested port and host are not
|
|
803
|
+
// necessarily the ones the server bound (a flag that does not land falls
|
|
804
|
+
// back to a wildcard bind), and the caller already parsed the listening
|
|
805
|
+
// line to find out. Dialing the request instead meant a renewal on a
|
|
806
|
+
// relocated server failed its reload every hour and the session served a
|
|
807
|
+
// stale warehouse token until restart.
|
|
808
|
+
const response = yield fetch(mcpUrl, {
|
|
809
|
+
signal: AbortSignal.timeout(RELOAD_TIMEOUT_MS),
|
|
810
|
+
method: "POST",
|
|
811
|
+
headers: {
|
|
812
|
+
"Content-Type": "application/json",
|
|
813
|
+
Accept: "application/json, text/event-stream",
|
|
814
|
+
},
|
|
815
|
+
body: JSON.stringify({
|
|
816
|
+
jsonrpc: "2.0",
|
|
817
|
+
id: 1,
|
|
818
|
+
method: "tools/call",
|
|
819
|
+
params: {
|
|
820
|
+
name: exports.RELOAD_TOOL,
|
|
821
|
+
arguments: {
|
|
822
|
+
environmentName: options.watchEnvironment,
|
|
823
|
+
packageName: name,
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
}),
|
|
827
|
+
});
|
|
828
|
+
if (!response.ok) {
|
|
829
|
+
throw new Error(`reload returned HTTP ${response.status}`);
|
|
830
|
+
}
|
|
831
|
+
// A tool failure is not an HTTP failure: MCP answers 200 with a JSON-RPC
|
|
832
|
+
// `error`, or a `result` flagged `isError`, and the reload has not
|
|
833
|
+
// happened. Read as success, the loop stopped retrying.
|
|
834
|
+
const failure = toolCallFailure((_a = response.headers.get("content-type")) !== null && _a !== void 0 ? _a : "", yield response.text());
|
|
835
|
+
if (failure)
|
|
836
|
+
throw new Error(`reload of ${name} failed: ${failure}`);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Why a `tools/call` response says the call failed, or undefined if it did not.
|
|
842
|
+
*
|
|
843
|
+
* The MCP endpoint answers with plain JSON or with a server-sent-events stream
|
|
844
|
+
* (the request accepts both), so both are read. A body that is neither is
|
|
845
|
+
* reported as a failure too: a reload nobody can confirm is retried.
|
|
846
|
+
*/
|
|
847
|
+
function toolCallFailure(contentType, body) {
|
|
848
|
+
var _a, _b, _c, _d;
|
|
849
|
+
const messages = [];
|
|
850
|
+
try {
|
|
851
|
+
if (contentType.includes("text/event-stream")) {
|
|
852
|
+
for (const line of body.split("\n")) {
|
|
853
|
+
// A blank `data:` is a keep-alive or priming event, not a reply.
|
|
854
|
+
// Parsed, it read as unreadable and the reload retried every tick.
|
|
855
|
+
const payload = line.startsWith("data:")
|
|
856
|
+
? line.slice("data:".length).trim()
|
|
857
|
+
: "";
|
|
858
|
+
if (payload)
|
|
859
|
+
messages.push(JSON.parse(payload));
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
else if (body.trim()) {
|
|
863
|
+
messages.push(JSON.parse(body));
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
catch (_e) {
|
|
867
|
+
return "the server sent a response that could not be read";
|
|
868
|
+
}
|
|
869
|
+
for (const message of messages) {
|
|
870
|
+
const { error, result } = (message !== null && message !== void 0 ? message : {});
|
|
871
|
+
if (error)
|
|
872
|
+
return (_a = error.message) !== null && _a !== void 0 ? _a : "the server returned an error";
|
|
873
|
+
if (result === null || result === void 0 ? void 0 : result.isError) {
|
|
874
|
+
return ((_d = (_c = (_b = result.content) === null || _b === void 0 ? void 0 : _b.find((part) => part.text)) === null || _c === void 0 ? void 0 : _c.text) !== null && _d !== void 0 ? _d : "the tool reported an error");
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return undefined;
|
|
878
|
+
}
|
|
879
|
+
//# sourceMappingURL=supervisor.js.map
|