convex 1.41.0 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/browser.bundle.js +1 -1
  3. package/dist/browser.bundle.js.map +1 -1
  4. package/dist/cjs/browser/simple_client-node.js +85 -27
  5. package/dist/cjs/browser/simple_client-node.js.map +3 -3
  6. package/dist/cjs/cli/env.js +12 -5
  7. package/dist/cjs/cli/env.js.map +2 -2
  8. package/dist/cjs/cli/envDefault.js +12 -7
  9. package/dist/cjs/cli/envDefault.js.map +2 -2
  10. package/dist/cjs/cli/insights.js +11 -1
  11. package/dist/cjs/cli/insights.js.map +2 -2
  12. package/dist/cjs/cli/lib/env.js +5 -1
  13. package/dist/cjs/cli/lib/env.js.map +2 -2
  14. package/dist/cjs/cli/lib/login.js +16 -12
  15. package/dist/cjs/cli/lib/login.js.map +2 -2
  16. package/dist/cjs/cli/lib/logs.js +4 -1
  17. package/dist/cjs/cli/lib/logs.js.map +2 -2
  18. package/dist/cjs/cli/lib/run.js +27 -2
  19. package/dist/cjs/cli/lib/run.js.map +2 -2
  20. package/dist/cjs/cli/lib/utils/utils.js +30 -0
  21. package/dist/cjs/cli/lib/utils/utils.js.map +2 -2
  22. package/dist/cjs/cli/program.js +2 -1
  23. package/dist/cjs/cli/program.js.map +2 -2
  24. package/dist/cjs/cli/project.js +27 -0
  25. package/dist/cjs/cli/project.js.map +7 -0
  26. package/dist/cjs/cli/projectCreate.js +90 -0
  27. package/dist/cjs/cli/projectCreate.js.map +7 -0
  28. package/dist/cjs/index.js +1 -1
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/server/database.js.map +1 -1
  31. package/dist/cjs/server/impl/meta_impl.js +6 -6
  32. package/dist/cjs/server/impl/meta_impl.js.map +2 -2
  33. package/dist/cjs/server/impl/registration_impl.js +9 -2
  34. package/dist/cjs/server/impl/registration_impl.js.map +2 -2
  35. package/dist/cjs/server/index.js.map +2 -2
  36. package/dist/cjs/server/meta.js.map +1 -1
  37. package/dist/cjs/server/query.js.map +1 -1
  38. package/dist/cjs/server/registration.js.map +1 -1
  39. package/dist/cjs/server/storage.js.map +1 -1
  40. package/dist/cjs/server/system_fields.js.map +1 -1
  41. package/dist/cjs-types/cli/env.d.ts.map +1 -1
  42. package/dist/cjs-types/cli/envDefault.d.ts.map +1 -1
  43. package/dist/cjs-types/cli/insights.d.ts +1 -0
  44. package/dist/cjs-types/cli/insights.d.ts.map +1 -1
  45. package/dist/cjs-types/cli/lib/env.d.ts +3 -1
  46. package/dist/cjs-types/cli/lib/env.d.ts.map +1 -1
  47. package/dist/cjs-types/cli/lib/env.test.d.ts +2 -0
  48. package/dist/cjs-types/cli/lib/env.test.d.ts.map +1 -0
  49. package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
  50. package/dist/cjs-types/cli/lib/logs.d.ts +1 -1
  51. package/dist/cjs-types/cli/lib/logs.d.ts.map +1 -1
  52. package/dist/cjs-types/cli/lib/run.d.ts +1 -1
  53. package/dist/cjs-types/cli/lib/run.d.ts.map +1 -1
  54. package/dist/cjs-types/cli/lib/utils/utils.d.ts +10 -0
  55. package/dist/cjs-types/cli/lib/utils/utils.d.ts.map +1 -1
  56. package/dist/cjs-types/cli/program.d.ts.map +1 -1
  57. package/dist/cjs-types/cli/project.d.ts +3 -0
  58. package/dist/cjs-types/cli/project.d.ts.map +1 -0
  59. package/dist/cjs-types/cli/projectCreate.d.ts +5 -0
  60. package/dist/cjs-types/cli/projectCreate.d.ts.map +1 -0
  61. package/dist/cjs-types/index.d.ts +1 -1
  62. package/dist/cjs-types/server/database.d.ts +21 -3
  63. package/dist/cjs-types/server/database.d.ts.map +1 -1
  64. package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -1
  65. package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
  66. package/dist/cjs-types/server/index.d.ts +1 -1
  67. package/dist/cjs-types/server/index.d.ts.map +1 -1
  68. package/dist/cjs-types/server/meta.d.ts +10 -0
  69. package/dist/cjs-types/server/meta.d.ts.map +1 -1
  70. package/dist/cjs-types/server/query.d.ts +1 -1
  71. package/dist/cjs-types/server/registration.d.ts +15 -3
  72. package/dist/cjs-types/server/registration.d.ts.map +1 -1
  73. package/dist/cjs-types/server/storage.d.ts +20 -3
  74. package/dist/cjs-types/server/storage.d.ts.map +1 -1
  75. package/dist/cli.bundle.cjs +1047 -619
  76. package/dist/cli.bundle.cjs.map +4 -4
  77. package/dist/esm/browser/simple_client-node.js +85 -27
  78. package/dist/esm/browser/simple_client-node.js.map +3 -3
  79. package/dist/esm/cli/env.js +12 -5
  80. package/dist/esm/cli/env.js.map +2 -2
  81. package/dist/esm/cli/envDefault.js +12 -7
  82. package/dist/esm/cli/envDefault.js.map +2 -2
  83. package/dist/esm/cli/insights.js +11 -1
  84. package/dist/esm/cli/insights.js.map +2 -2
  85. package/dist/esm/cli/lib/env.js +5 -1
  86. package/dist/esm/cli/lib/env.js.map +2 -2
  87. package/dist/esm/cli/lib/login.js +18 -13
  88. package/dist/esm/cli/lib/login.js.map +2 -2
  89. package/dist/esm/cli/lib/logs.js +5 -2
  90. package/dist/esm/cli/lib/logs.js.map +2 -2
  91. package/dist/esm/cli/lib/run.js +32 -3
  92. package/dist/esm/cli/lib/run.js.map +2 -2
  93. package/dist/esm/cli/lib/utils/utils.js +29 -0
  94. package/dist/esm/cli/lib/utils/utils.js.map +2 -2
  95. package/dist/esm/cli/program.js +2 -1
  96. package/dist/esm/cli/program.js.map +2 -2
  97. package/dist/esm/cli/project.js +5 -0
  98. package/dist/esm/cli/project.js.map +7 -0
  99. package/dist/esm/cli/projectCreate.js +68 -0
  100. package/dist/esm/cli/projectCreate.js.map +7 -0
  101. package/dist/esm/index.js +1 -1
  102. package/dist/esm/index.js.map +1 -1
  103. package/dist/esm/server/impl/meta_impl.js +6 -6
  104. package/dist/esm/server/impl/meta_impl.js.map +2 -2
  105. package/dist/esm/server/impl/registration_impl.js +9 -2
  106. package/dist/esm/server/impl/registration_impl.js.map +2 -2
  107. package/dist/esm/server/index.js.map +2 -2
  108. package/dist/esm-types/cli/env.d.ts.map +1 -1
  109. package/dist/esm-types/cli/envDefault.d.ts.map +1 -1
  110. package/dist/esm-types/cli/insights.d.ts +1 -0
  111. package/dist/esm-types/cli/insights.d.ts.map +1 -1
  112. package/dist/esm-types/cli/lib/env.d.ts +3 -1
  113. package/dist/esm-types/cli/lib/env.d.ts.map +1 -1
  114. package/dist/esm-types/cli/lib/env.test.d.ts +2 -0
  115. package/dist/esm-types/cli/lib/env.test.d.ts.map +1 -0
  116. package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
  117. package/dist/esm-types/cli/lib/logs.d.ts +1 -1
  118. package/dist/esm-types/cli/lib/logs.d.ts.map +1 -1
  119. package/dist/esm-types/cli/lib/run.d.ts +1 -1
  120. package/dist/esm-types/cli/lib/run.d.ts.map +1 -1
  121. package/dist/esm-types/cli/lib/utils/utils.d.ts +10 -0
  122. package/dist/esm-types/cli/lib/utils/utils.d.ts.map +1 -1
  123. package/dist/esm-types/cli/program.d.ts.map +1 -1
  124. package/dist/esm-types/cli/project.d.ts +3 -0
  125. package/dist/esm-types/cli/project.d.ts.map +1 -0
  126. package/dist/esm-types/cli/projectCreate.d.ts +5 -0
  127. package/dist/esm-types/cli/projectCreate.d.ts.map +1 -0
  128. package/dist/esm-types/index.d.ts +1 -1
  129. package/dist/esm-types/server/database.d.ts +21 -3
  130. package/dist/esm-types/server/database.d.ts.map +1 -1
  131. package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -1
  132. package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
  133. package/dist/esm-types/server/index.d.ts +1 -1
  134. package/dist/esm-types/server/index.d.ts.map +1 -1
  135. package/dist/esm-types/server/meta.d.ts +10 -0
  136. package/dist/esm-types/server/meta.d.ts.map +1 -1
  137. package/dist/esm-types/server/query.d.ts +1 -1
  138. package/dist/esm-types/server/registration.d.ts +15 -3
  139. package/dist/esm-types/server/registration.d.ts.map +1 -1
  140. package/dist/esm-types/server/storage.d.ts +20 -3
  141. package/dist/esm-types/server/storage.d.ts.map +1 -1
  142. package/dist/react.bundle.js +1 -1
  143. package/dist/react.bundle.js.map +1 -1
  144. package/package.json +4 -4
  145. package/src/cli/env.ts +16 -6
  146. package/src/cli/envDefault.ts +13 -7
  147. package/src/cli/insights.ts +12 -0
  148. package/src/cli/lib/env.test.ts +60 -0
  149. package/src/cli/lib/env.ts +9 -1
  150. package/src/cli/lib/login.ts +18 -18
  151. package/src/cli/lib/logs.ts +7 -2
  152. package/src/cli/lib/run.ts +37 -3
  153. package/src/cli/lib/utils/utils.ts +56 -0
  154. package/src/cli/program.ts +2 -0
  155. package/src/cli/project.ts +7 -0
  156. package/src/cli/projectCreate.ts +99 -0
  157. package/src/index.ts +1 -1
  158. package/src/server/database.ts +21 -3
  159. package/src/server/impl/meta_impl.ts +7 -6
  160. package/src/server/impl/registration_impl.ts +11 -3
  161. package/src/server/index.ts +1 -0
  162. package/src/server/meta.ts +10 -0
  163. package/src/server/query.ts +1 -1
  164. package/src/server/registration.test.ts +25 -1
  165. package/src/server/registration.ts +16 -1
  166. package/src/server/storage.ts +22 -3
  167. package/src/server/system_fields.ts +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/lib/login.ts"],
4
- "sourcesContent": ["import { errors, BaseClient, custom } from \"openid-client\";\nimport {\n bigBrainAPI,\n bigBrainFetch,\n logAndHandleFetchError,\n throwingFetch,\n isWebContainer,\n} from \"./utils/utils.js\";\nimport open from \"open\";\nimport { chalkStderr } from \"chalk\";\nimport { provisionHost } from \"./config.js\";\nimport { version } from \"../version.js\";\nimport { Context } from \"../../bundler/context.js\";\nimport {\n changeSpinner,\n logError,\n logFailure,\n logFinishedStep,\n logMessage,\n logOutput,\n logVerbose,\n showSpinner,\n} from \"../../bundler/log.js\";\nimport { Issuer } from \"openid-client\";\nimport { hostname } from \"os\";\nimport { execSync } from \"child_process\";\nimport { promptString, promptYesNo } from \"./utils/prompts.js\";\nimport {\n formatPathForPrinting,\n globalConfigPath,\n modifyGlobalConfig,\n} from \"./utils/globalConfig.js\";\nimport { updateBigBrainAuthAfterLogin } from \"./deploymentSelection.js\";\n\n// Per https://github.com/panva/node-openid-client/tree/main/docs#customizing\ncustom.setHttpOptionsDefaults({\n timeout: parseInt(process.env.OPENID_CLIENT_TIMEOUT || \"10000\"),\n});\n\ninterface AuthorizeArgs {\n authnToken: string;\n deviceName: string;\n anonymousId?: string | undefined;\n}\n\nexport async function checkAuthorization(\n ctx: Context,\n acceptOptIns: boolean,\n): Promise<boolean> {\n const header = ctx.bigBrainAuth()?.header ?? null;\n if (header === null) {\n return false;\n }\n try {\n const resp = await fetch(`${provisionHost}/api/authorize`, {\n method: \"HEAD\",\n headers: {\n Authorization: header,\n \"Convex-Client\": `npm-cli-${version}`,\n },\n });\n // Don't throw an error if this request returns a non-200 status.\n // Big Brain responds with a variety of error codes -- 401 if the token is correctly-formed but not valid, and either 400 or 500 if the token is ill-formed.\n // We only care if this check returns a 200 code (so we can skip logging in again) -- any other errors should be silently skipped and we'll run the whole login flow again.\n if (resp.status !== 200) {\n return false;\n }\n } catch (e: any) {\n // This `catch` block should only be hit if a network error was encountered\n logError(\n `Unexpected error when authorizing - are you connected to the internet?`,\n );\n return await logAndHandleFetchError(ctx, e);\n }\n\n // Check that we have optin as well\n const shouldContinue = await optins(ctx, acceptOptIns);\n if (!shouldContinue) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n return true;\n}\n\nasync function performDeviceAuthorization(\n ctx: Context,\n authClient: BaseClient,\n shouldOpen: boolean,\n vercel?: boolean,\n vercelOverride?: string,\n): Promise<string> {\n // Device authorization flow follows this guide: https://github.com/auth0/auth0-device-flow-cli-sample/blob/9f0f3b76a6cd56ea8d99e76769187ea5102d519d/cli.js\n // License: MIT License\n // Copyright (c) 2019 Auth0 Samples\n /*\n The MIT License (MIT)\n\n Copyright (c) 2019 Auth0 Samples\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n // Device Authorization Request - https://tools.ietf.org/html/rfc8628#section-3.1\n // Get authentication URL\n let handle;\n try {\n handle = await authClient.deviceAuthorization();\n } catch {\n // We couldn't get verification URL from the auth provider, proceed with manual auth\n return promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n }\n\n // Device Authorization Response - https://tools.ietf.org/html/rfc8628#section-3.2\n // Open authentication URL\n const { verification_uri_complete, user_code, expires_in } = handle;\n\n // Construct Vercel URL if --vercel flag is used\n const urlToOpen = vercel\n ? `https://vercel.com/sso/integrations/${vercelOverride || \"convex\"}?url=${verification_uri_complete}`\n : verification_uri_complete;\n\n logMessage(\n `Visit ${urlToOpen} to finish logging in.\\n` +\n `You should see the following code which expires in ${\n expires_in % 60 === 0\n ? `${expires_in / 60} minutes`\n : `${expires_in} seconds`\n }: ${user_code}`,\n );\n if (shouldOpen) {\n shouldOpen = await promptYesNo(ctx, {\n message: `Open the browser?`,\n default: true,\n });\n }\n\n if (shouldOpen) {\n showSpinner(`Opening ${urlToOpen} in your browser to log in...\\n`);\n try {\n const p = await open(urlToOpen);\n p.once(\"error\", () => {\n changeSpinner(`Manually open ${urlToOpen} in your browser to log in.`);\n });\n changeSpinner(\"Waiting for the confirmation...\");\n } catch {\n logError(chalkStderr.red(`Unable to open browser.`));\n changeSpinner(`Manually open ${urlToOpen} in your browser to log in.`);\n }\n } else {\n showSpinner(`Open ${urlToOpen} in your browser to log in.`);\n }\n\n // Device Access Token Request - https://tools.ietf.org/html/rfc8628#section-3.4\n // Device Access Token Response - https://tools.ietf.org/html/rfc8628#section-3.5\n try {\n const tokens = await handle.poll();\n if (typeof tokens.access_token === \"string\") {\n return tokens.access_token;\n } else {\n // Unexpected error\n // eslint-disable-next-line no-restricted-syntax\n throw Error(\"Access token is missing\");\n }\n } catch (err: any) {\n switch (err.error) {\n case \"access_denied\": // end-user declined the device confirmation prompt, consent or rules failed\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"Access denied.\",\n errForSentry: err,\n });\n case \"expired_token\": // end-user did not complete the interaction in time\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"Device flow expired.\",\n errForSentry: err,\n });\n default: {\n const message =\n err instanceof errors.OPError\n ? `Error = ${err.error}; error_description = ${err.error_description}`\n : `Login failed with error: ${err}`;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: err,\n });\n }\n }\n }\n}\n\nasync function performPasswordAuthentication(\n ctx: Context,\n clientId: string,\n username: string,\n password: string,\n): Promise<string> {\n if (!process.env.WORKOS_API_SECRET) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"WORKOS_API_SECRET environment variable is not set\",\n });\n }\n\n // Unfortunately, `openid-client` doesn't support the resource owner password credentials flow so we need to manually send the requests.\n const options: Parameters<typeof throwingFetch>[1] = {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n grant_type: \"password\",\n email: username,\n password: password,\n client_id: clientId,\n client_secret: process.env.WORKOS_API_SECRET,\n }),\n };\n\n try {\n const response = await throwingFetch(\n \"https://apiauth.convex.dev/user_management/authenticate\",\n options,\n );\n const data = await response.json();\n if (typeof data.access_token === \"string\") {\n return data.access_token;\n } else {\n // Unexpected error\n // eslint-disable-next-line no-restricted-syntax\n throw Error(\"Access token is missing\");\n }\n } catch (err: any) {\n logFailure(`Password flow failed: ${err}`);\n if (err.response) {\n logError(chalkStderr.red(`${JSON.stringify(err.response.data)}`));\n }\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: err,\n printedMessage: null,\n });\n }\n}\n\nexport async function performLogin(\n ctx: Context,\n {\n overrideAuthUrl,\n overrideAuthClient,\n overrideAuthUsername,\n overrideAuthPassword,\n overrideAccessToken,\n loginFlow,\n open,\n acceptOptIns,\n dumpAccessToken,\n deviceName: deviceNameOverride,\n anonymousId,\n vercel,\n vercelOverride,\n }: {\n overrideAuthUrl?: string | undefined;\n overrideAuthClient?: string | undefined;\n overrideAuthUsername?: string | undefined;\n overrideAuthPassword?: string | undefined;\n overrideAccessToken?: string | undefined;\n loginFlow?: \"auto\" | \"paste\" | \"poll\" | undefined;\n // default `true`\n open?: boolean | undefined;\n // default `false`\n acceptOptIns?: boolean | undefined;\n dumpAccessToken?: boolean | undefined;\n deviceName?: string | undefined;\n anonymousId?: string | undefined;\n vercel?: boolean | undefined;\n vercelOverride?: string | undefined;\n } = {},\n) {\n loginFlow = loginFlow || \"auto\";\n // Get access token from big-brain\n // Default the device name to the hostname, but allow the user to change this if the terminal is interactive.\n // On Macs, the `hostname()` may be a weirdly-truncated form of the computer name. Attempt to read the \"real\" name before falling back to hostname.\n let deviceName = deviceNameOverride ?? \"\";\n if (!deviceName && process.platform === \"darwin\") {\n try {\n deviceName = execSync(\"scutil --get ComputerName\").toString().trim();\n } catch {\n // Just fall back to the hostname default below.\n }\n }\n if (!deviceName) {\n deviceName = hostname();\n }\n if (!deviceNameOverride) {\n logMessage(\n chalkStderr.bold(\n `Welcome to developing with Convex, let's get you logged in.`,\n ),\n );\n deviceName = await promptString(ctx, {\n message: \"Device name:\",\n default: deviceName,\n });\n }\n\n const issuer = overrideAuthUrl ?? \"https://auth.convex.dev\";\n let authIssuer;\n let accessToken: string;\n\n if (loginFlow === \"paste\" || (loginFlow === \"auto\" && isWebContainer())) {\n accessToken = await promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n } else {\n try {\n authIssuer = await Issuer.discover(issuer);\n } catch {\n // Couldn't contact https://auth.convex.dev/.well-known/openid-configuration,\n // proceed with manual auth.\n accessToken = await promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n }\n }\n\n // typical path\n if (authIssuer) {\n const clientId = overrideAuthClient ?? \"HFtA247jp9iNs08NTLIB7JsNPMmRIyfi\";\n const authClient = new authIssuer.Client({\n client_id: clientId,\n token_endpoint_auth_method: \"none\",\n id_token_signed_response_alg: \"RS256\",\n });\n\n if (overrideAccessToken) {\n accessToken = overrideAccessToken;\n } else if (overrideAuthUsername && overrideAuthPassword) {\n accessToken = await performPasswordAuthentication(\n ctx,\n clientId,\n overrideAuthUsername,\n overrideAuthPassword,\n );\n } else {\n accessToken = await performDeviceAuthorization(\n ctx,\n authClient,\n open ?? true,\n vercel,\n vercelOverride,\n );\n }\n }\n\n if (dumpAccessToken) {\n logOutput(`${accessToken!}`);\n return await ctx.crash({\n exitCode: 0,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n\n const authorizeArgs: AuthorizeArgs = {\n authnToken: accessToken!,\n deviceName: deviceName,\n anonymousId: anonymousId,\n };\n const data = await bigBrainAPI({\n ctx,\n method: \"POST\",\n path: \"authorize\",\n data: authorizeArgs,\n });\n const globalConfig = { accessToken: data.accessToken };\n try {\n await modifyGlobalConfig(ctx, globalConfig);\n const path = globalConfigPath();\n logFinishedStep(`Saved credentials to ${formatPathForPrinting(path)}`);\n } catch (err: unknown) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n errForSentry: err,\n printedMessage: null,\n });\n }\n\n logVerbose(`performLogin: updating big brain auth after login`);\n await updateBigBrainAuthAfterLogin(ctx, data.accessToken);\n\n logVerbose(`performLogin: checking opt ins, acceptOptIns: ${acceptOptIns}`);\n // Do opt in to TOS and Privacy Policy stuff\n const shouldContinue = await optins(ctx, acceptOptIns ?? false);\n if (!shouldContinue) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n\n if (vercel) {\n await promptJoinVercelTeams(ctx);\n }\n}\n\ntype PotentialVercelTeam = {\n teamId: number;\n teamName: string;\n teamSlug: string;\n planId: string;\n planName: string;\n pricingNotice: string | null;\n};\n\n// After `--vercel` login, surface any Vercel-marketplace teams the user has\n// access to but isn't yet a member of, and prompt to join each.\nasync function promptJoinVercelTeams(ctx: Context): Promise<void> {\n const fetch = bigBrainFetch(ctx);\n let teams: PotentialVercelTeam[];\n try {\n const res = await fetch(\n new URL(\"vercel/potential_teams\", `${provisionHost}/`),\n );\n if (!res.ok) {\n logVerbose(\n `vercel/potential_teams returned ${res.status}; skipping team-join prompt`,\n );\n return;\n }\n teams = await res.json();\n } catch (err) {\n logVerbose(`Failed to fetch potential Vercel teams: ${String(err)}`);\n return;\n }\n if (teams.length === 0) return;\n\n for (const [index, team] of teams.entries()) {\n const displayName = team.teamName.replace(/ \\(Vercel\\)$/, \"\");\n const counter = teams.length > 1 ? `[${index + 1}/${teams.length}] ` : \"\";\n const lines = [\n chalkStderr.bold(`${counter}You've been invited to join ${displayName}`) +\n ` (${team.planName}) through the Vercel marketplace.`,\n ];\n if (team.pricingNotice) {\n lines.push(chalkStderr.yellow(team.pricingNotice));\n }\n lines.push(`Join \"${displayName}\"?`);\n const join = await promptYesNo(ctx, {\n message: `${lines.join(\"\\n\")}`,\n default: true,\n });\n if (!join) continue;\n try {\n await fetch(\n new URL(\n `vercel/potential_teams/${team.teamId}/join`,\n `${provisionHost}/`,\n ),\n { method: \"POST\" },\n );\n logFinishedStep(`Joined ${displayName}`);\n } catch (err) {\n logFailure(`Failed to join ${displayName}: ${String(err)}`);\n }\n }\n}\n\n/// There are fields like version, but we keep them opaque\ntype OptIn = Record<string, unknown>;\n\ntype OptInToAccept = {\n optIn: OptIn;\n message: string;\n};\n\ntype AcceptOptInsArgs = {\n optInsAccepted: OptIn[];\n};\n\n// Returns whether we can proceed or not.\nasync function optins(ctx: Context, acceptOptIns: boolean): Promise<boolean> {\n const bbAuth = ctx.bigBrainAuth();\n if (bbAuth === null) {\n // This should never happen, but if we're not even logged in, we can't proceed.\n return false;\n }\n switch (bbAuth.kind) {\n case \"accessToken\":\n break;\n case \"deploymentKey\":\n case \"projectKey\":\n case \"previewDeployKey\":\n // If we have a key configured as auth, we do not need to check opt ins.\n return true;\n default: {\n bbAuth satisfies never;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: `Unexpected auth kind ${(bbAuth as any).kind}`,\n printedMessage: \"Hit an unexpected error while logging in.\",\n });\n }\n }\n const data = await bigBrainAPI({\n ctx,\n method: \"POST\",\n path: \"check_opt_ins\",\n });\n if (data.optInsToAccept.length === 0) {\n return true;\n }\n for (const optInToAccept of data.optInsToAccept) {\n const confirmed =\n acceptOptIns ||\n (await promptYesNo(ctx, {\n message: optInToAccept.message,\n }));\n if (!confirmed) {\n logFailure(\"Please accept the Terms of Service to use Convex.\");\n return Promise.resolve(false);\n }\n }\n\n const optInsAccepted = data.optInsToAccept.map((o: OptInToAccept) => o.optIn);\n const args: AcceptOptInsArgs = { optInsAccepted };\n await bigBrainAPI({\n ctx,\n method: \"POST\",\n path: \"accept_opt_ins\",\n data: args,\n });\n return true;\n}\n\nexport async function ensureLoggedIn(\n ctx: Context,\n options?: {\n message?: string | undefined;\n overrideAuthUrl?: string | undefined;\n overrideAuthClient?: string | undefined;\n overrideAuthUsername?: string | undefined;\n overrideAuthPassword?: string | undefined;\n },\n) {\n const isLoggedIn = await checkAuthorization(ctx, false);\n if (!isLoggedIn) {\n if (options?.message) {\n logMessage(options.message);\n }\n await performLogin(ctx, {\n acceptOptIns: false,\n overrideAuthUrl: options?.overrideAuthUrl,\n overrideAuthClient: options?.overrideAuthClient,\n overrideAuthUsername: options?.overrideAuthUsername,\n overrideAuthPassword: options?.overrideAuthPassword,\n });\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { errors, BaseClient, custom } from \"openid-client\";\nimport {\n bigBrainAPI,\n bigBrainFetch,\n logAndHandleFetchError,\n throwingFetch,\n isWebContainer,\n typedPlatformClient,\n} from \"./utils/utils.js\";\nimport open from \"open\";\nimport { chalkStderr } from \"chalk\";\nimport { provisionHost } from \"./config.js\";\nimport { version } from \"../version.js\";\nimport { Context } from \"../../bundler/context.js\";\nimport {\n changeSpinner,\n logError,\n logFailure,\n logFinishedStep,\n logMessage,\n logOutput,\n logVerbose,\n showSpinner,\n} from \"../../bundler/log.js\";\nimport { Issuer } from \"openid-client\";\nimport { hostname } from \"os\";\nimport { execSync } from \"child_process\";\nimport { promptString, promptYesNo } from \"./utils/prompts.js\";\nimport {\n formatPathForPrinting,\n globalConfigPath,\n modifyGlobalConfig,\n} from \"./utils/globalConfig.js\";\nimport { updateBigBrainAuthAfterLogin } from \"./deploymentSelection.js\";\n\n// Per https://github.com/panva/node-openid-client/tree/main/docs#customizing\ncustom.setHttpOptionsDefaults({\n timeout: parseInt(process.env.OPENID_CLIENT_TIMEOUT || \"10000\"),\n});\n\nexport async function checkAuthorization(\n ctx: Context,\n acceptOptIns: boolean,\n): Promise<boolean> {\n const header = ctx.bigBrainAuth()?.header ?? null;\n if (header === null) {\n return false;\n }\n try {\n const resp = await fetch(`${provisionHost}/api/authorize`, {\n method: \"HEAD\",\n headers: {\n Authorization: header,\n \"Convex-Client\": `npm-cli-${version}`,\n },\n });\n // Don't throw an error if this request returns a non-200 status.\n // Big Brain responds with a variety of error codes -- 401 if the token is correctly-formed but not valid, and either 400 or 500 if the token is ill-formed.\n // We only care if this check returns a 200 code (so we can skip logging in again) -- any other errors should be silently skipped and we'll run the whole login flow again.\n if (resp.status !== 200) {\n return false;\n }\n } catch (e: any) {\n // This `catch` block should only be hit if a network error was encountered\n logError(\n `Unexpected error when authorizing - are you connected to the internet?`,\n );\n return await logAndHandleFetchError(ctx, e);\n }\n\n // Check that we have optin as well\n const shouldContinue = await optins(ctx, acceptOptIns);\n if (!shouldContinue) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n return true;\n}\n\nasync function performDeviceAuthorization(\n ctx: Context,\n authClient: BaseClient,\n shouldOpen: boolean,\n vercel?: boolean,\n vercelOverride?: string,\n): Promise<string> {\n // Device authorization flow follows this guide: https://github.com/auth0/auth0-device-flow-cli-sample/blob/9f0f3b76a6cd56ea8d99e76769187ea5102d519d/cli.js\n // License: MIT License\n // Copyright (c) 2019 Auth0 Samples\n /*\n The MIT License (MIT)\n\n Copyright (c) 2019 Auth0 Samples\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n // Device Authorization Request - https://tools.ietf.org/html/rfc8628#section-3.1\n // Get authentication URL\n let handle;\n try {\n handle = await authClient.deviceAuthorization();\n } catch {\n // We couldn't get verification URL from the auth provider, proceed with manual auth\n return promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n }\n\n // Device Authorization Response - https://tools.ietf.org/html/rfc8628#section-3.2\n // Open authentication URL\n const { verification_uri_complete, user_code, expires_in } = handle;\n\n // Construct Vercel URL if --vercel flag is used\n const urlToOpen = vercel\n ? `https://vercel.com/sso/integrations/${vercelOverride || \"convex\"}?url=${verification_uri_complete}`\n : verification_uri_complete;\n\n logMessage(\n `Visit ${urlToOpen} to finish logging in.\\n` +\n `You should see the following code which expires in ${\n expires_in % 60 === 0\n ? `${expires_in / 60} minutes`\n : `${expires_in} seconds`\n }: ${user_code}`,\n );\n if (shouldOpen) {\n shouldOpen = await promptYesNo(ctx, {\n message: `Open the browser?`,\n default: true,\n });\n }\n\n if (shouldOpen) {\n showSpinner(`Opening ${urlToOpen} in your browser to log in...\\n`);\n try {\n const p = await open(urlToOpen);\n p.once(\"error\", () => {\n changeSpinner(`Manually open ${urlToOpen} in your browser to log in.`);\n });\n changeSpinner(\"Waiting for the confirmation...\");\n } catch {\n logError(chalkStderr.red(`Unable to open browser.`));\n changeSpinner(`Manually open ${urlToOpen} in your browser to log in.`);\n }\n } else {\n showSpinner(`Open ${urlToOpen} in your browser to log in.`);\n }\n\n // Device Access Token Request - https://tools.ietf.org/html/rfc8628#section-3.4\n // Device Access Token Response - https://tools.ietf.org/html/rfc8628#section-3.5\n try {\n const tokens = await handle.poll();\n if (typeof tokens.access_token === \"string\") {\n return tokens.access_token;\n } else {\n // Unexpected error\n // eslint-disable-next-line no-restricted-syntax\n throw Error(\"Access token is missing\");\n }\n } catch (err: any) {\n switch (err.error) {\n case \"access_denied\": // end-user declined the device confirmation prompt, consent or rules failed\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"Access denied.\",\n errForSentry: err,\n });\n case \"expired_token\": // end-user did not complete the interaction in time\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"Device flow expired.\",\n errForSentry: err,\n });\n default: {\n const message =\n err instanceof errors.OPError\n ? `Error = ${err.error}; error_description = ${err.error_description}`\n : `Login failed with error: ${err}`;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: err,\n });\n }\n }\n }\n}\n\nasync function performPasswordAuthentication(\n ctx: Context,\n clientId: string,\n username: string,\n password: string,\n): Promise<string> {\n if (!process.env.WORKOS_API_SECRET) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: \"WORKOS_API_SECRET environment variable is not set\",\n });\n }\n\n // Unfortunately, `openid-client` doesn't support the resource owner password credentials flow so we need to manually send the requests.\n const options: Parameters<typeof throwingFetch>[1] = {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n grant_type: \"password\",\n email: username,\n password: password,\n client_id: clientId,\n client_secret: process.env.WORKOS_API_SECRET,\n }),\n };\n\n try {\n const response = await throwingFetch(\n \"https://apiauth.convex.dev/user_management/authenticate\",\n options,\n );\n const data = await response.json();\n if (typeof data.access_token === \"string\") {\n return data.access_token;\n } else {\n // Unexpected error\n // eslint-disable-next-line no-restricted-syntax\n throw Error(\"Access token is missing\");\n }\n } catch (err: any) {\n logFailure(`Password flow failed: ${err}`);\n if (err.response) {\n logError(chalkStderr.red(`${JSON.stringify(err.response.data)}`));\n }\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: err,\n printedMessage: null,\n });\n }\n}\n\nexport async function performLogin(\n ctx: Context,\n {\n overrideAuthUrl,\n overrideAuthClient,\n overrideAuthUsername,\n overrideAuthPassword,\n overrideAccessToken,\n loginFlow,\n open,\n acceptOptIns,\n dumpAccessToken,\n deviceName: deviceNameOverride,\n anonymousId,\n vercel,\n vercelOverride,\n }: {\n overrideAuthUrl?: string | undefined;\n overrideAuthClient?: string | undefined;\n overrideAuthUsername?: string | undefined;\n overrideAuthPassword?: string | undefined;\n overrideAccessToken?: string | undefined;\n loginFlow?: \"auto\" | \"paste\" | \"poll\" | undefined;\n // default `true`\n open?: boolean | undefined;\n // default `false`\n acceptOptIns?: boolean | undefined;\n dumpAccessToken?: boolean | undefined;\n deviceName?: string | undefined;\n anonymousId?: string | undefined;\n vercel?: boolean | undefined;\n vercelOverride?: string | undefined;\n } = {},\n) {\n loginFlow = loginFlow || \"auto\";\n // Get access token from big-brain\n // Default the device name to the hostname, but allow the user to change this if the terminal is interactive.\n // On Macs, the `hostname()` may be a weirdly-truncated form of the computer name. Attempt to read the \"real\" name before falling back to hostname.\n let deviceName = deviceNameOverride ?? \"\";\n if (!deviceName && process.platform === \"darwin\") {\n try {\n deviceName = execSync(\"scutil --get ComputerName\").toString().trim();\n } catch {\n // Just fall back to the hostname default below.\n }\n }\n if (!deviceName) {\n deviceName = hostname();\n }\n if (!deviceNameOverride) {\n logMessage(\n chalkStderr.bold(\n `Welcome to developing with Convex, let's get you logged in.`,\n ),\n );\n deviceName = await promptString(ctx, {\n message: \"Device name:\",\n default: deviceName,\n });\n }\n\n const issuer = overrideAuthUrl ?? \"https://auth.convex.dev\";\n let authIssuer;\n let accessToken: string;\n\n if (loginFlow === \"paste\" || (loginFlow === \"auto\" && isWebContainer())) {\n accessToken = await promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n } else {\n try {\n authIssuer = await Issuer.discover(issuer);\n } catch {\n // Couldn't contact https://auth.convex.dev/.well-known/openid-configuration,\n // proceed with manual auth.\n accessToken = await promptString(ctx, {\n message:\n \"Open https://dashboard.convex.dev/auth, log in and paste the token here:\",\n });\n }\n }\n\n // typical path\n if (authIssuer) {\n const clientId = overrideAuthClient ?? \"HFtA247jp9iNs08NTLIB7JsNPMmRIyfi\";\n const authClient = new authIssuer.Client({\n client_id: clientId,\n token_endpoint_auth_method: \"none\",\n id_token_signed_response_alg: \"RS256\",\n });\n\n if (overrideAccessToken) {\n accessToken = overrideAccessToken;\n } else if (overrideAuthUsername && overrideAuthPassword) {\n accessToken = await performPasswordAuthentication(\n ctx,\n clientId,\n overrideAuthUsername,\n overrideAuthPassword,\n );\n } else {\n accessToken = await performDeviceAuthorization(\n ctx,\n authClient,\n open ?? true,\n vercel,\n vercelOverride,\n );\n }\n }\n\n if (dumpAccessToken) {\n logOutput(`${accessToken!}`);\n return await ctx.crash({\n exitCode: 0,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n\n // Exchange the WorkOS access token for a Convex personal access token.\n ctx._updateBigBrainAuth({\n accessToken: accessToken!,\n kind: \"accessToken\",\n header: `Bearer ${accessToken!}`,\n });\n const response = await typedPlatformClient(ctx).POST(\n \"/create_personal_access_token\",\n {\n // `anonymousId` links a prior anonymous session to this account. It's\n // intentionally absent from the generated platform API types,\n // so cast to pass it through.\n body: { name: deviceName, anonymousId } as { name: string },\n },\n );\n const newAccessToken = response.data!.accessToken;\n const globalConfig = { accessToken: newAccessToken };\n try {\n await modifyGlobalConfig(ctx, globalConfig);\n const path = globalConfigPath();\n logFinishedStep(`Saved credentials to ${formatPathForPrinting(path)}`);\n } catch (err: unknown) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n errForSentry: err,\n printedMessage: null,\n });\n }\n\n logVerbose(`performLogin: updating big brain auth after login`);\n await updateBigBrainAuthAfterLogin(ctx, newAccessToken);\n\n logVerbose(`performLogin: checking opt ins, acceptOptIns: ${acceptOptIns}`);\n // Do opt in to TOS and Privacy Policy stuff\n const shouldContinue = await optins(ctx, acceptOptIns ?? false);\n if (!shouldContinue) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: null,\n });\n }\n\n if (vercel) {\n await promptJoinVercelTeams(ctx);\n }\n}\n\ntype PotentialVercelTeam = {\n teamId: number;\n teamName: string;\n teamSlug: string;\n planId: string;\n planName: string;\n pricingNotice: string | null;\n};\n\n// After `--vercel` login, surface any Vercel-marketplace teams the user has\n// access to but isn't yet a member of, and prompt to join each.\nasync function promptJoinVercelTeams(ctx: Context): Promise<void> {\n const fetch = bigBrainFetch(ctx);\n let teams: PotentialVercelTeam[];\n try {\n const res = await fetch(\n new URL(\"vercel/potential_teams\", `${provisionHost}/`),\n );\n if (!res.ok) {\n logVerbose(\n `vercel/potential_teams returned ${res.status}; skipping team-join prompt`,\n );\n return;\n }\n teams = await res.json();\n } catch (err) {\n logVerbose(`Failed to fetch potential Vercel teams: ${String(err)}`);\n return;\n }\n if (teams.length === 0) return;\n\n for (const [index, team] of teams.entries()) {\n const displayName = team.teamName.replace(/ \\(Vercel\\)$/, \"\");\n const counter = teams.length > 1 ? `[${index + 1}/${teams.length}] ` : \"\";\n const lines = [\n chalkStderr.bold(`${counter}You've been invited to join ${displayName}`) +\n ` (${team.planName}) through the Vercel marketplace.`,\n ];\n if (team.pricingNotice) {\n lines.push(chalkStderr.yellow(team.pricingNotice));\n }\n lines.push(`Join \"${displayName}\"?`);\n const join = await promptYesNo(ctx, {\n message: `${lines.join(\"\\n\")}`,\n default: true,\n });\n if (!join) continue;\n try {\n await fetch(\n new URL(\n `vercel/potential_teams/${team.teamId}/join`,\n `${provisionHost}/`,\n ),\n { method: \"POST\" },\n );\n logFinishedStep(`Joined ${displayName}`);\n } catch (err) {\n logFailure(`Failed to join ${displayName}: ${String(err)}`);\n }\n }\n}\n\n/// There are fields like version, but we keep them opaque\ntype OptIn = Record<string, unknown>;\n\ntype OptInToAccept = {\n optIn: OptIn;\n message: string;\n};\n\ntype AcceptOptInsArgs = {\n optInsAccepted: OptIn[];\n};\n\n// Returns whether we can proceed or not.\nasync function optins(ctx: Context, acceptOptIns: boolean): Promise<boolean> {\n const bbAuth = ctx.bigBrainAuth();\n if (bbAuth === null) {\n // This should never happen, but if we're not even logged in, we can't proceed.\n return false;\n }\n switch (bbAuth.kind) {\n case \"accessToken\":\n break;\n case \"deploymentKey\":\n case \"projectKey\":\n case \"previewDeployKey\":\n // If we have a key configured as auth, we do not need to check opt ins.\n return true;\n default: {\n bbAuth satisfies never;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: `Unexpected auth kind ${(bbAuth as any).kind}`,\n printedMessage: \"Hit an unexpected error while logging in.\",\n });\n }\n }\n const data = await bigBrainAPI({\n ctx,\n method: \"POST\",\n path: \"check_opt_ins\",\n });\n if (data.optInsToAccept.length === 0) {\n return true;\n }\n for (const optInToAccept of data.optInsToAccept) {\n const confirmed =\n acceptOptIns ||\n (await promptYesNo(ctx, {\n message: optInToAccept.message,\n }));\n if (!confirmed) {\n logFailure(\"Please accept the Terms of Service to use Convex.\");\n return Promise.resolve(false);\n }\n }\n\n const optInsAccepted = data.optInsToAccept.map((o: OptInToAccept) => o.optIn);\n const args: AcceptOptInsArgs = { optInsAccepted };\n await bigBrainAPI({\n ctx,\n method: \"POST\",\n path: \"accept_opt_ins\",\n data: args,\n });\n return true;\n}\n\nexport async function ensureLoggedIn(\n ctx: Context,\n options?: {\n message?: string | undefined;\n overrideAuthUrl?: string | undefined;\n overrideAuthClient?: string | undefined;\n overrideAuthUsername?: string | undefined;\n overrideAuthPassword?: string | undefined;\n },\n) {\n const isLoggedIn = await checkAuthorization(ctx, false);\n if (!isLoggedIn) {\n if (options?.message) {\n logMessage(options.message);\n }\n await performLogin(ctx, {\n acceptOptIns: false,\n overrideAuthUrl: options?.overrideAuthUrl,\n overrideAuthClient: options?.overrideAuthClient,\n overrideAuthUsername: options?.overrideAuthUsername,\n overrideAuthPassword: options?.overrideAuthPassword,\n });\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_openid_client", "open", "fetch"]
7
7
  }
@@ -112,7 +112,10 @@ async function watchLogs(ctx, url, adminKey, dest, options) {
112
112
  options?.jsonl
113
113
  );
114
114
  }
115
- } catch {
115
+ } catch (e) {
116
+ if (e instanceof import_utils.ThrowingFetchError && e.response.status === 403) {
117
+ return await e.handle(ctx);
118
+ }
116
119
  numFailures += 1;
117
120
  }
118
121
  if (numFailures > 0) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/lib/logs.ts"],
4
- "sourcesContent": ["import { Context } from \"../../bundler/context.js\";\nimport { logMessage, logOutput, logWarning } from \"../../bundler/log.js\";\nimport { nextBackoff } from \"./dev.js\";\n// eslint-disable-next-line no-restricted-imports -- chalk used for writing to stdout\nimport chalk, { chalkStderr } from \"chalk\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport { format } from \"node:util\";\nimport { deploymentFetch } from \"./utils/utils.js\";\nimport { FunctionExecution } from \"./apiTypes.js\";\n\nexport type LogMode = \"always\" | \"pause-on-deploy\" | \"disable\";\n\nexport class LogManager {\n private paused: boolean = false;\n\n constructor(private mode: LogMode) {}\n\n async waitForUnpaused() {\n while (this.paused) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n beginDeploy() {\n if (this.mode === \"pause-on-deploy\") {\n this.paused = true;\n }\n }\n\n endDeploy() {\n if (this.mode === \"pause-on-deploy\") {\n this.paused = false;\n }\n }\n}\n\nconst MAX_UDF_STREAM_FAILURE_COUNT = 5;\n\ntype LogDestination = \"stdout\" | \"stderr\";\n\nexport async function logsForDeployment(\n ctx: Context,\n credentials: {\n url: string;\n adminKey: string;\n },\n options: {\n success: boolean;\n history: number;\n jsonl: boolean;\n deploymentNotice: string;\n },\n) {\n logMessage(chalkStderr.yellow(`Watching logs${options.deploymentNotice}...`));\n await watchLogs(ctx, credentials.url, credentials.adminKey, \"stdout\", {\n history: options.history,\n success: options.success,\n jsonl: options.jsonl,\n });\n}\n\nexport async function watchLogs(\n ctx: Context,\n url: string,\n adminKey: string,\n dest: LogDestination,\n options?: {\n success: boolean;\n history?: number | boolean;\n jsonl?: boolean;\n logManager?: LogManager;\n },\n) {\n let numFailures = 0;\n let isFirst = true;\n let cursorMs = 0;\n\n // Select the appropriate chalk instance and write function based on destination\n const chalkInstance = dest === \"stdout\" ? chalk : chalkStderr;\n const write = (s: string) => logToDestination(dest, s);\n\n for (;;) {\n try {\n const { entries, newCursor } = await pollUdfLog(\n ctx,\n cursorMs,\n url,\n adminKey,\n );\n cursorMs = newCursor;\n numFailures = 0;\n\n // Delay printing logs until the log manager is unpaused.\n await options?.logManager?.waitForUnpaused();\n\n // The first execution, we just want to fetch the current head cursor so we don't send stale\n // logs to the client.\n if (isFirst) {\n isFirst = false;\n if (\n options?.history === true ||\n (typeof options?.history === \"number\" && options?.history > 0)\n ) {\n const entriesSlice =\n options?.history === true\n ? entries\n : entries.slice(entries.length - options?.history);\n processLogs(\n entriesSlice,\n write,\n options?.success,\n chalkInstance,\n options?.jsonl,\n );\n }\n } else {\n processLogs(\n entries,\n write,\n options?.success === true,\n chalkInstance,\n options?.jsonl,\n );\n }\n } catch {\n numFailures += 1;\n }\n // Handle backoff\n if (numFailures > 0) {\n const backoff = nextBackoff(numFailures);\n\n // If we exceed a threshold number of failures, warn the user and display backoff.\n if (numFailures > MAX_UDF_STREAM_FAILURE_COUNT) {\n logWarning(\n `Convex [WARN] Failed to fetch logs. Waiting ${backoff}ms before next retry.`,\n );\n }\n await new Promise((resolve) => {\n setTimeout(() => resolve(null), backoff);\n });\n }\n }\n}\n\ntype UdfType = \"Query\" | \"Mutation\" | \"Action\" | \"HttpAction\";\n\ntype StructuredLogLine = {\n messages: string[];\n level: \"LOG\" | \"DEBUG\" | \"INFO\" | \"WARN\" | \"ERROR\";\n timestamp: number;\n isTruncated: boolean;\n};\ntype LogLine = string | StructuredLogLine;\n\nasync function pollUdfLog(\n ctx: Context,\n cursor: number,\n url: string,\n adminKey: string,\n): Promise<{ entries: FunctionExecution[]; newCursor: number }> {\n const fetch = deploymentFetch(ctx, {\n deploymentUrl: url,\n adminKey,\n });\n const response = await fetch(`/api/stream_function_logs?cursor=${cursor}`, {\n method: \"GET\",\n });\n return await response.json();\n}\n\nconst prefixForSource = (udfType: UdfType): string => {\n return udfType.charAt(0);\n};\n\nfunction processLogs(\n rawLogs: FunctionExecution[],\n write: (message: string) => void,\n shouldShowSuccessLogs: boolean,\n chalkInstance: typeof chalk,\n jsonl?: boolean,\n) {\n if (jsonl) {\n for (let i = 0; i < rawLogs.length; i++) {\n const log = rawLogs[i];\n write(JSON.stringify(log));\n }\n return;\n }\n\n for (let i = 0; i < rawLogs.length; i++) {\n const log = rawLogs[i];\n if (log.logLines) {\n const id = log.identifier;\n const udfType = log.udfType;\n const timestampMs = log.timestamp * 1000;\n const executionTimeMs =\n \"executionTime\" in log ? log.executionTime * 1000 : NaN;\n\n for (let j = 0; j < log.logLines.length; j++) {\n const formatted = formatLogLineMessage(\n \"info\",\n timestampMs,\n udfType,\n id,\n log.logLines[j],\n chalkInstance,\n );\n write(formatted);\n }\n\n if (\"error\" in log && log.error) {\n const formatted = formatLogLineMessage(\n \"error\",\n timestampMs,\n udfType,\n id,\n log.error!,\n chalkInstance,\n );\n write(formatted);\n } else if (log.kind === \"Completion\" && shouldShowSuccessLogs) {\n const formatted = chalkInstance.green(\n formatFunctionExecutionMessage(\n timestampMs,\n udfType,\n id,\n executionTimeMs,\n ),\n );\n write(formatted);\n }\n }\n }\n}\n\nexport function formatFunctionExecutionMessage(\n timestampMs: number,\n udfType: UdfType,\n udfPath: string,\n executionTimeMs: number,\n): string {\n return `${prefixLog(timestampMs, udfType, udfPath)} Function executed in ${Math.ceil(executionTimeMs)} ms`;\n}\n\nexport function formatLogLineMessage(\n type: \"info\" | \"error\",\n timestampMs: number,\n udfType: UdfType,\n udfPath: string,\n message: LogLine,\n chalkInstance: typeof chalk = chalk,\n): string {\n const prefix = prefixForSource(udfType);\n if (typeof message === \"string\") {\n if (type === \"info\") {\n const match = message.match(/^\\[.*?\\] /);\n if (match === null) {\n return chalkInstance.red(\n `[CONVEX ${prefix}(${udfPath})] Could not parse console.log`,\n );\n }\n const level = message.slice(1, match[0].length - 2);\n const args = message.slice(match[0].length);\n return `${chalkInstance.cyan(`${prefixLog(timestampMs, udfType, udfPath)} [${level}]`)} ${format(args)}`;\n } else {\n return chalkInstance.red(\n `${prefixLog(timestampMs, udfType, udfPath)} ${message}`,\n );\n }\n } else {\n const level = message.level;\n const formattedMessage = `${message.messages.join(\" \")}${message.isTruncated ? \" (truncated due to length)\" : \"\"}`;\n return `${chalkInstance.cyan(\n `${prefixLog(message.timestamp, udfType, udfPath)} [${level}]`,\n )} ${formattedMessage}`;\n }\n}\n\nfunction logToDestination(dest: LogDestination, s: string) {\n switch (dest) {\n case \"stdout\":\n logOutput(s);\n break;\n case \"stderr\":\n logMessage(s);\n break;\n }\n}\n\nfunction prefixLog(timestampMs: number, udfType: UdfType, udfPath: string) {\n const prefix = prefixForSource(udfType);\n const localizedTimestamp = new Date(timestampMs).toLocaleString();\n\n return `${localizedTimestamp} [CONVEX ${prefix}(${udfPath})]`;\n}\n\nexport function formatLogsAsText(\n rawLogs: FunctionExecution[],\n shouldShowSuccessLogs: boolean = false,\n): string {\n const lines: string[] = [];\n const write = (message: string) =>\n lines.push(stripVTControlCharacters(message));\n processLogs(rawLogs, write, shouldShowSuccessLogs, chalk);\n return lines.join(\"\\n\");\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Context } from \"../../bundler/context.js\";\nimport { logMessage, logOutput, logWarning } from \"../../bundler/log.js\";\nimport { nextBackoff } from \"./dev.js\";\n// eslint-disable-next-line no-restricted-imports -- chalk used for writing to stdout\nimport chalk, { chalkStderr } from \"chalk\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport { format } from \"node:util\";\nimport { deploymentFetch, ThrowingFetchError } from \"./utils/utils.js\";\nimport { FunctionExecution } from \"./apiTypes.js\";\n\nexport type LogMode = \"always\" | \"pause-on-deploy\" | \"disable\";\n\nexport class LogManager {\n private paused: boolean = false;\n\n constructor(private mode: LogMode) {}\n\n async waitForUnpaused() {\n while (this.paused) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n beginDeploy() {\n if (this.mode === \"pause-on-deploy\") {\n this.paused = true;\n }\n }\n\n endDeploy() {\n if (this.mode === \"pause-on-deploy\") {\n this.paused = false;\n }\n }\n}\n\nconst MAX_UDF_STREAM_FAILURE_COUNT = 5;\n\ntype LogDestination = \"stdout\" | \"stderr\";\n\nexport async function logsForDeployment(\n ctx: Context,\n credentials: {\n url: string;\n adminKey: string;\n },\n options: {\n success: boolean;\n history: number;\n jsonl: boolean;\n deploymentNotice: string;\n },\n) {\n logMessage(chalkStderr.yellow(`Watching logs${options.deploymentNotice}...`));\n await watchLogs(ctx, credentials.url, credentials.adminKey, \"stdout\", {\n history: options.history,\n success: options.success,\n jsonl: options.jsonl,\n });\n}\n\nexport async function watchLogs(\n ctx: Context,\n url: string,\n adminKey: string,\n dest: LogDestination,\n options?: {\n success: boolean;\n history?: number | boolean;\n jsonl?: boolean;\n logManager?: LogManager;\n },\n) {\n let numFailures = 0;\n let isFirst = true;\n let cursorMs = 0;\n\n // Select the appropriate chalk instance and write function based on destination\n const chalkInstance = dest === \"stdout\" ? chalk : chalkStderr;\n const write = (s: string) => logToDestination(dest, s);\n\n for (;;) {\n try {\n const { entries, newCursor } = await pollUdfLog(\n ctx,\n cursorMs,\n url,\n adminKey,\n );\n cursorMs = newCursor;\n numFailures = 0;\n\n // Delay printing logs until the log manager is unpaused.\n await options?.logManager?.waitForUnpaused();\n\n // The first execution, we just want to fetch the current head cursor so we don't send stale\n // logs to the client.\n if (isFirst) {\n isFirst = false;\n if (\n options?.history === true ||\n (typeof options?.history === \"number\" && options?.history > 0)\n ) {\n const entriesSlice =\n options?.history === true\n ? entries\n : entries.slice(entries.length - options?.history);\n processLogs(\n entriesSlice,\n write,\n options?.success,\n chalkInstance,\n options?.jsonl,\n );\n }\n } else {\n processLogs(\n entries,\n write,\n options?.success === true,\n chalkInstance,\n options?.jsonl,\n );\n }\n } catch (e) {\n // A 403 means the admin key isn't authorized for this deployment.\n // Retrying won't help, so surface the error and fail immediately.\n if (e instanceof ThrowingFetchError && e.response.status === 403) {\n return await e.handle(ctx);\n }\n numFailures += 1;\n }\n // Handle backoff\n if (numFailures > 0) {\n const backoff = nextBackoff(numFailures);\n\n // If we exceed a threshold number of failures, warn the user and display backoff.\n if (numFailures > MAX_UDF_STREAM_FAILURE_COUNT) {\n logWarning(\n `Convex [WARN] Failed to fetch logs. Waiting ${backoff}ms before next retry.`,\n );\n }\n await new Promise((resolve) => {\n setTimeout(() => resolve(null), backoff);\n });\n }\n }\n}\n\ntype UdfType = \"Query\" | \"Mutation\" | \"Action\" | \"HttpAction\";\n\ntype StructuredLogLine = {\n messages: string[];\n level: \"LOG\" | \"DEBUG\" | \"INFO\" | \"WARN\" | \"ERROR\";\n timestamp: number;\n isTruncated: boolean;\n};\ntype LogLine = string | StructuredLogLine;\n\nasync function pollUdfLog(\n ctx: Context,\n cursor: number,\n url: string,\n adminKey: string,\n): Promise<{ entries: FunctionExecution[]; newCursor: number }> {\n const fetch = deploymentFetch(ctx, {\n deploymentUrl: url,\n adminKey,\n });\n const response = await fetch(`/api/stream_function_logs?cursor=${cursor}`, {\n method: \"GET\",\n });\n return await response.json();\n}\n\nconst prefixForSource = (udfType: UdfType): string => {\n return udfType.charAt(0);\n};\n\nfunction processLogs(\n rawLogs: FunctionExecution[],\n write: (message: string) => void,\n shouldShowSuccessLogs: boolean,\n chalkInstance: typeof chalk,\n jsonl?: boolean,\n) {\n if (jsonl) {\n for (let i = 0; i < rawLogs.length; i++) {\n const log = rawLogs[i];\n write(JSON.stringify(log));\n }\n return;\n }\n\n for (let i = 0; i < rawLogs.length; i++) {\n const log = rawLogs[i];\n if (log.logLines) {\n const id = log.identifier;\n const udfType = log.udfType;\n const timestampMs = log.timestamp * 1000;\n const executionTimeMs =\n \"executionTime\" in log ? log.executionTime * 1000 : NaN;\n\n for (let j = 0; j < log.logLines.length; j++) {\n const formatted = formatLogLineMessage(\n \"info\",\n timestampMs,\n udfType,\n id,\n log.logLines[j],\n chalkInstance,\n );\n write(formatted);\n }\n\n if (\"error\" in log && log.error) {\n const formatted = formatLogLineMessage(\n \"error\",\n timestampMs,\n udfType,\n id,\n log.error!,\n chalkInstance,\n );\n write(formatted);\n } else if (log.kind === \"Completion\" && shouldShowSuccessLogs) {\n const formatted = chalkInstance.green(\n formatFunctionExecutionMessage(\n timestampMs,\n udfType,\n id,\n executionTimeMs,\n ),\n );\n write(formatted);\n }\n }\n }\n}\n\nexport function formatFunctionExecutionMessage(\n timestampMs: number,\n udfType: UdfType,\n udfPath: string,\n executionTimeMs: number,\n): string {\n return `${prefixLog(timestampMs, udfType, udfPath)} Function executed in ${Math.ceil(executionTimeMs)} ms`;\n}\n\nexport function formatLogLineMessage(\n type: \"info\" | \"error\",\n timestampMs: number,\n udfType: UdfType,\n udfPath: string,\n message: LogLine,\n chalkInstance: typeof chalk = chalk,\n): string {\n const prefix = prefixForSource(udfType);\n if (typeof message === \"string\") {\n if (type === \"info\") {\n const match = message.match(/^\\[.*?\\] /);\n if (match === null) {\n return chalkInstance.red(\n `[CONVEX ${prefix}(${udfPath})] Could not parse console.log`,\n );\n }\n const level = message.slice(1, match[0].length - 2);\n const args = message.slice(match[0].length);\n return `${chalkInstance.cyan(`${prefixLog(timestampMs, udfType, udfPath)} [${level}]`)} ${format(args)}`;\n } else {\n return chalkInstance.red(\n `${prefixLog(timestampMs, udfType, udfPath)} ${message}`,\n );\n }\n } else {\n const level = message.level;\n const formattedMessage = `${message.messages.join(\" \")}${message.isTruncated ? \" (truncated due to length)\" : \"\"}`;\n return `${chalkInstance.cyan(\n `${prefixLog(message.timestamp, udfType, udfPath)} [${level}]`,\n )} ${formattedMessage}`;\n }\n}\n\nfunction logToDestination(dest: LogDestination, s: string) {\n switch (dest) {\n case \"stdout\":\n logOutput(s);\n break;\n case \"stderr\":\n logMessage(s);\n break;\n }\n}\n\nfunction prefixLog(timestampMs: number, udfType: UdfType, udfPath: string) {\n const prefix = prefixForSource(udfType);\n const localizedTimestamp = new Date(timestampMs).toLocaleString();\n\n return `${localizedTimestamp} [CONVEX ${prefix}(${udfPath})]`;\n}\n\nexport function formatLogsAsText(\n rawLogs: FunctionExecution[],\n shouldShowSuccessLogs: boolean = false,\n): string {\n const lines: string[] = [];\n const write = (message: string) =>\n lines.push(stripVTControlCharacters(message));\n processLogs(rawLogs, write, shouldShowSuccessLogs, chalk);\n return lines.join(\"\\n\");\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_node_util", "chalk"]
7
7
  }
@@ -76,6 +76,14 @@ async function runFunctionAndLog(ctx, args) {
76
76
  );
77
77
  } catch (err) {
78
78
  const errorMessage = err.toString().trim();
79
+ const permissionError = (0, import_utils.permissionDeniedErrorMessage)(errorMessage);
80
+ if (permissionError !== null) {
81
+ return await ctx.crash({
82
+ exitCode: 1,
83
+ errorType: "fatal",
84
+ printedMessage: import_chalk.chalkStderr.red(permissionError)
85
+ });
86
+ }
79
87
  if (errorMessage.includes("Could not find function")) {
80
88
  const functions = await runSystemQuery(ctx, {
81
89
  deploymentUrl: args.deploymentUrl,
@@ -300,12 +308,29 @@ async function subscribeAndLog(ctx, args) {
300
308
  }
301
309
  });
302
310
  }
303
- async function subscribe(_ctx, args) {
311
+ async function subscribe(ctx, args) {
304
312
  const client = new import_browser.BaseConvexClient(
305
313
  args.deploymentUrl,
306
314
  (updatedQueries) => {
307
315
  for (const queryToken of updatedQueries) {
308
- args.callbacks?.onChange?.(client.localQueryResultByToken(queryToken));
316
+ let result;
317
+ try {
318
+ result = client.localQueryResultByToken(queryToken);
319
+ } catch (err) {
320
+ const permissionError = (0, import_utils.permissionDeniedErrorMessage)(
321
+ err.toString()
322
+ );
323
+ if (permissionError !== null) {
324
+ void ctx.crash({
325
+ exitCode: 1,
326
+ errorType: "fatal",
327
+ printedMessage: import_chalk.chalkStderr.red(permissionError)
328
+ });
329
+ return;
330
+ }
331
+ throw err;
332
+ }
333
+ args.callbacks?.onChange?.(result);
309
334
  }
310
335
  },
311
336
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/lib/run.ts"],
4
- "sourcesContent": ["import { chalkStderr } from \"chalk\";\nimport util from \"util\";\nimport ws from \"ws\";\nimport { ConvexHttpClient } from \"../../browser/http_client.js\";\nimport { BaseConvexClient } from \"../../browser/index.js\";\nimport {\n PaginationResult,\n UserIdentityAttributes,\n makeFunctionReference,\n} from \"../../server/index.js\";\nimport { Value, convexToJson, jsonToConvex } from \"../../values/value.js\";\nimport { Context, OneoffCtx } from \"../../bundler/context.js\";\nimport { logFinishedStep, logMessage, logOutput } from \"../../bundler/log.js\";\nimport { waitForever, waitUntilCalled } from \"./utils/utils.js\";\nimport JSON5 from \"json5\";\nimport path from \"path\";\nimport { readProjectConfig } from \"./config.js\";\nimport { watchAndPush } from \"./dev.js\";\nimport { Logger, DefaultLogger } from \"../../browser/logging.js\";\n\nexport async function runFunctionAndLog(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n componentPath?: string | undefined;\n callbacks?:\n | {\n onSuccess?: () => void | undefined;\n }\n | undefined;\n },\n) {\n const client = new ConvexHttpClient(args.deploymentUrl, {\n logger: instantiateStderrLogger(),\n });\n const identity = args.identityString\n ? await getFakeIdentity(ctx, args.identityString)\n : undefined;\n client.setAdminAuth(args.adminKey, identity);\n\n const functionArgs = await parseArgs(ctx, args.argsString);\n const { projectConfig } = await readProjectConfig(ctx);\n const parsedFunctionName = await parseFunctionName(\n ctx,\n args.functionName,\n projectConfig.functions,\n );\n let result: Value;\n try {\n result = await client.function(\n makeFunctionReference(parsedFunctionName),\n args.componentPath,\n functionArgs,\n );\n } catch (err) {\n const errorMessage = (err as Error).toString().trim();\n\n if (errorMessage.includes(\"Could not find function\")) {\n const functions = (await runSystemQuery(ctx, {\n deploymentUrl: args.deploymentUrl,\n adminKey: args.adminKey,\n functionName: \"_system/cli/modules:apiSpec\",\n componentPath: args.componentPath,\n args: {},\n })) as (\n | {\n functionType: \"Query\" | \"Mutation\" | \"Action\";\n identifier: string;\n }\n | {\n functionType: \"HttpAction\";\n }\n )[];\n\n const functionNames = functions\n .filter(\n (\n fn,\n ): fn is {\n functionType: \"Query\" | \"Mutation\" | \"Action\";\n identifier: string;\n } => fn.functionType !== \"HttpAction\",\n )\n .map(({ identifier }) => {\n const separatorPos = identifier.indexOf(\":\");\n\n const path =\n separatorPos === -1\n ? \"\"\n : identifier.substring(0, separatorPos).replace(/\\.js$/, \"\");\n const name =\n separatorPos === -1\n ? identifier\n : identifier.substring(separatorPos + 1);\n\n return `\u2022 ${chalkStderr.gray(`${path}:`)}${name}`;\n });\n\n const availableFunctionsMessage =\n functionNames.length > 0\n ? `Available functions:\\n${functionNames.join(\"\\n\")}`\n : \"No functions found.\";\n\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Failed to run function \"${args.functionName}\":\\n${chalkStderr.red(errorMessage)}\\n\\n${availableFunctionsMessage}`,\n });\n }\n\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem or env vars\",\n printedMessage: `Failed to run function \"${args.functionName}\":\\n${chalkStderr.red(errorMessage)}`,\n });\n }\n\n args.callbacks?.onSuccess?.();\n\n // `null` is the default return type\n if (result !== null) {\n logOutput(formatValue(result));\n }\n}\n\nasync function getFakeIdentity(ctx: Context, identityString: string) {\n let identity: UserIdentityAttributes;\n try {\n identity = JSON5.parse(identityString);\n } catch (err) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Failed to parse identity as JSON: \"${identityString}\"\\n${chalkStderr.red((err as Error).toString().trim())}`,\n });\n }\n const subject = identity.subject ?? \"\" + simpleHash(JSON.stringify(identity));\n const issuer = identity.issuer ?? \"https://convex.test\";\n const tokenIdentifier =\n identity.tokenIdentifier ?? `${issuer.toString()}|${subject.toString()}`;\n return {\n ...identity,\n subject,\n issuer,\n tokenIdentifier,\n };\n}\n\nexport async function parseArgs(ctx: Context, argsString: string) {\n try {\n const argsJson = JSON5.parse(argsString);\n return jsonToConvex(argsJson) as Record<string, Value>;\n } catch (err) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem or env vars\",\n printedMessage: `Failed to parse arguments as JSON: \"${argsString}\"\\n${chalkStderr.red((err as Error).toString().trim())}`,\n });\n }\n}\n\nexport async function parseFunctionName(\n ctx: Context,\n functionName: string,\n // Usually `convex/` -- should contain trailing slash\n functionDirName: string,\n) {\n // api.foo.bar -> foo:bar\n // foo/bar -> foo/bar:default\n // foo/bar:baz -> foo/bar:baz\n // convex/foo/bar -> foo/bar:default\n\n // This is the `api.foo.bar` format\n if (functionName.startsWith(\"api.\") || functionName.startsWith(\"internal.\")) {\n const parts = functionName.split(\".\");\n if (parts.length < 3) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Function name has too few parts: \"${functionName}\"`,\n });\n }\n const exportName = parts.pop();\n const parsedName = `${parts.slice(1).join(\"/\")}:${exportName}`;\n return parsedName;\n }\n\n // This is the `foo/bar:baz` format\n\n // This is something like `convex/foo/bar`, which could either be addressing `foo/bar:default` or `convex/foo/bar:default`\n // if there's a directory with the same name as the functions directory nested directly underneath.\n // We'll prefer the `convex/foo/bar:default` version, and check if the file exists, and otherwise treat this as a relative path from the project root.\n const filePath = functionName.split(\":\")[0];\n const possibleExtensions = [\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".mts\",\n \".mjs\",\n \".cts\",\n \".cjs\",\n ];\n let hasExtension = false;\n let normalizedFilePath: string = filePath;\n for (const extension of possibleExtensions) {\n if (filePath.endsWith(extension)) {\n normalizedFilePath = filePath.slice(0, -extension.length);\n hasExtension = true;\n break;\n }\n }\n\n const exportName = functionName.split(\":\")[1] ?? \"default\";\n const normalizedName = `${normalizedFilePath}:${exportName}`;\n\n // This isn't a relative path from the project root\n if (!filePath.startsWith(functionDirName)) {\n return normalizedName;\n }\n\n const filePathWithoutPrefix = normalizedFilePath.slice(\n functionDirName.length,\n );\n const functionNameWithoutPrefix = `${filePathWithoutPrefix}:${exportName}`;\n\n if (hasExtension) {\n if (ctx.fs.exists(path.join(functionDirName, filePath))) {\n return normalizedName;\n } else {\n return functionNameWithoutPrefix;\n }\n } else {\n const exists = possibleExtensions.some((extension) =>\n ctx.fs.exists(path.join(functionDirName, filePath + extension)),\n );\n if (exists) {\n return normalizedName;\n } else {\n return functionNameWithoutPrefix;\n }\n }\n}\n\nfunction simpleHash(string: string) {\n let hash = 0;\n for (let i = 0; i < string.length; i++) {\n const char = string.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return hash;\n}\n\nexport async function runSystemPaginatedQuery(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n componentPath: string | undefined;\n args: Record<string, Value>;\n limit?: number;\n },\n) {\n const results = [];\n let cursor = null;\n let isDone = false;\n while (!isDone && (args.limit === undefined || results.length < args.limit)) {\n const paginationResult = (await runSystemQuery(ctx, {\n ...args,\n args: {\n ...args.args,\n paginationOpts: {\n cursor,\n numItems:\n args.limit === undefined ? 10000 : args.limit - results.length,\n },\n },\n })) as unknown as PaginationResult<Record<string, Value>>;\n isDone = paginationResult.isDone;\n cursor = paginationResult.continueCursor;\n results.push(...paginationResult.page);\n }\n return results;\n}\n\nexport async function runSystemQuery(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n componentPath: string | undefined;\n args: Record<string, Value>;\n },\n): Promise<Value> {\n let onResult: (result: Value) => void;\n const resultPromise = new Promise<Value>((resolve) => {\n onResult = resolve;\n });\n const [donePromise, onDone] = waitUntilCalled();\n await subscribe(ctx, {\n ...args,\n parsedFunctionName: args.functionName,\n parsedFunctionArgs: args.args,\n until: donePromise,\n callbacks: {\n onChange: (result) => {\n onDone();\n onResult(result);\n },\n },\n });\n return resultPromise;\n}\n\nexport function formatValue(value: Value) {\n const json = convexToJson(value);\n if (process.stdout.isTTY) {\n // TODO (Tom) add JSON syntax highlighting like https://stackoverflow.com/a/51319962/398212\n // until then, just spit out something that isn't quite JSON because it's easy\n return util.inspect(value, { colors: true, depth: null });\n } else {\n return JSON.stringify(json, null, 2);\n }\n}\n\nexport async function subscribeAndLog(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n componentPath: string | undefined;\n },\n) {\n const { projectConfig } = await readProjectConfig(ctx);\n\n const parsedFunctionName = await parseFunctionName(\n ctx,\n args.functionName,\n projectConfig.functions,\n );\n const identity = args.identityString\n ? await getFakeIdentity(ctx, args.identityString)\n : undefined;\n const functionArgs = await parseArgs(ctx, args.argsString);\n return subscribe(ctx, {\n deploymentUrl: args.deploymentUrl,\n adminKey: args.adminKey,\n identity,\n parsedFunctionName,\n parsedFunctionArgs: functionArgs,\n componentPath: args.componentPath,\n until: waitForever(),\n callbacks: {\n onStart() {\n logFinishedStep(\n `Watching query ${args.functionName} on ${args.deploymentUrl}...`,\n );\n },\n onChange(result) {\n logOutput(formatValue(result));\n },\n onStop() {\n logMessage(`Closing connection to ${args.deploymentUrl}...`);\n },\n },\n });\n}\n\nexport async function subscribe(\n _ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n identity?: UserIdentityAttributes | undefined;\n parsedFunctionName: string;\n parsedFunctionArgs: Record<string, Value>;\n componentPath: string | undefined;\n until: Promise<unknown>;\n callbacks?:\n | {\n onStart?: () => void;\n onChange?: (result: Value) => void;\n onStop?: () => void;\n }\n | undefined;\n },\n) {\n const client = new BaseConvexClient(\n args.deploymentUrl,\n (updatedQueries) => {\n for (const queryToken of updatedQueries) {\n args.callbacks?.onChange?.(client.localQueryResultByToken(queryToken)!);\n }\n },\n {\n // pretend that a Node.js 'ws' library WebSocket is a browser WebSocket\n webSocketConstructor: ws as unknown as typeof WebSocket,\n unsavedChangesWarning: false,\n },\n );\n client.setAdminAuth(args.adminKey, args.identity);\n const { unsubscribe } = client.subscribe(\n args.parsedFunctionName,\n args.parsedFunctionArgs,\n {\n componentPath: args.componentPath,\n },\n );\n\n args.callbacks?.onStart?.();\n\n let done = false;\n const [donePromise, onDone] = waitUntilCalled();\n const stopWatching = () => {\n if (done) {\n return;\n }\n done = true;\n unsubscribe();\n void client.close();\n process.off(\"SIGINT\", sigintListener);\n onDone();\n args.callbacks?.onStop?.();\n };\n function sigintListener() {\n stopWatching();\n }\n process.on(\"SIGINT\", sigintListener);\n void args.until.finally(stopWatching);\n while (!done) {\n // loops once per day (any large value < 2**31 would work)\n const oneDay = 24 * 60 * 60 * 1000;\n await Promise.race([\n donePromise,\n new Promise((resolve) => setTimeout(resolve, oneDay)),\n ]);\n }\n}\n\nexport async function runInDeployment(\n ctx: OneoffCtx,\n args: {\n deploymentUrl: string;\n adminKey: string;\n deploymentName: string | null;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n push: boolean;\n watch: boolean;\n typecheck: \"enable\" | \"try\" | \"disable\";\n typecheckComponents: boolean;\n codegen: boolean;\n componentPath: string | undefined;\n liveComponentSources: boolean;\n },\n) {\n if (args.push) await pushToDeployment(ctx, args);\n\n if (args.watch) {\n return await subscribeAndLog(ctx, args);\n }\n return await runFunctionAndLog(ctx, args);\n}\n\nexport async function pushToDeployment(\n ctx: OneoffCtx,\n args: {\n deploymentUrl: string;\n adminKey: string;\n deploymentName: string | null;\n typecheck: \"enable\" | \"try\" | \"disable\";\n typecheckComponents: boolean;\n codegen: boolean;\n liveComponentSources: boolean;\n },\n) {\n await watchAndPush(\n ctx,\n {\n url: args.deploymentUrl,\n adminKey: args.adminKey,\n deploymentName: args.deploymentName,\n verbose: false,\n dryRun: false,\n typecheck: args.typecheck,\n typecheckComponents: args.typecheckComponents,\n debug: false,\n debugNodeApis: false,\n codegen: args.codegen,\n liveComponentSources: args.liveComponentSources,\n pushAllModules: false,\n largeIndexDeletionCheck: \"no verification\", // `convex run` can\u2019t push to prod\n message: null,\n },\n {\n once: true,\n traceEvents: false,\n untilSuccess: true,\n },\n );\n}\n\nfunction instantiateStderrLogger(): Logger {\n const logger = new DefaultLogger({ verbose: false });\n logger.addLogLineListener((_level, ...args) => {\n // eslint-disable-next-line no-console\n console.error(...args);\n });\n return logger;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { chalkStderr } from \"chalk\";\nimport util from \"util\";\nimport ws from \"ws\";\nimport { ConvexHttpClient } from \"../../browser/http_client.js\";\nimport { BaseConvexClient } from \"../../browser/index.js\";\nimport {\n PaginationResult,\n UserIdentityAttributes,\n makeFunctionReference,\n} from \"../../server/index.js\";\nimport { Value, convexToJson, jsonToConvex } from \"../../values/value.js\";\nimport { Context, OneoffCtx } from \"../../bundler/context.js\";\nimport { logFinishedStep, logMessage, logOutput } from \"../../bundler/log.js\";\nimport {\n permissionDeniedErrorMessage,\n waitForever,\n waitUntilCalled,\n} from \"./utils/utils.js\";\nimport JSON5 from \"json5\";\nimport path from \"path\";\nimport { readProjectConfig } from \"./config.js\";\nimport { watchAndPush } from \"./dev.js\";\nimport { Logger, DefaultLogger } from \"../../browser/logging.js\";\n\nexport async function runFunctionAndLog(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n componentPath?: string | undefined;\n callbacks?:\n | {\n onSuccess?: () => void | undefined;\n }\n | undefined;\n },\n) {\n const client = new ConvexHttpClient(args.deploymentUrl, {\n logger: instantiateStderrLogger(),\n });\n const identity = args.identityString\n ? await getFakeIdentity(ctx, args.identityString)\n : undefined;\n client.setAdminAuth(args.adminKey, identity);\n\n const functionArgs = await parseArgs(ctx, args.argsString);\n const { projectConfig } = await readProjectConfig(ctx);\n const parsedFunctionName = await parseFunctionName(\n ctx,\n args.functionName,\n projectConfig.functions,\n );\n let result: Value;\n try {\n result = await client.function(\n makeFunctionReference(parsedFunctionName),\n args.componentPath,\n functionArgs,\n );\n } catch (err) {\n const errorMessage = (err as Error).toString().trim();\n\n const permissionError = permissionDeniedErrorMessage(errorMessage);\n if (permissionError !== null) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: chalkStderr.red(permissionError),\n });\n }\n\n if (errorMessage.includes(\"Could not find function\")) {\n const functions = (await runSystemQuery(ctx, {\n deploymentUrl: args.deploymentUrl,\n adminKey: args.adminKey,\n functionName: \"_system/cli/modules:apiSpec\",\n componentPath: args.componentPath,\n args: {},\n })) as (\n | {\n functionType: \"Query\" | \"Mutation\" | \"Action\";\n identifier: string;\n }\n | {\n functionType: \"HttpAction\";\n }\n )[];\n\n const functionNames = functions\n .filter(\n (\n fn,\n ): fn is {\n functionType: \"Query\" | \"Mutation\" | \"Action\";\n identifier: string;\n } => fn.functionType !== \"HttpAction\",\n )\n .map(({ identifier }) => {\n const separatorPos = identifier.indexOf(\":\");\n\n const path =\n separatorPos === -1\n ? \"\"\n : identifier.substring(0, separatorPos).replace(/\\.js$/, \"\");\n const name =\n separatorPos === -1\n ? identifier\n : identifier.substring(separatorPos + 1);\n\n return `\u2022 ${chalkStderr.gray(`${path}:`)}${name}`;\n });\n\n const availableFunctionsMessage =\n functionNames.length > 0\n ? `Available functions:\\n${functionNames.join(\"\\n\")}`\n : \"No functions found.\";\n\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Failed to run function \"${args.functionName}\":\\n${chalkStderr.red(errorMessage)}\\n\\n${availableFunctionsMessage}`,\n });\n }\n\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem or env vars\",\n printedMessage: `Failed to run function \"${args.functionName}\":\\n${chalkStderr.red(errorMessage)}`,\n });\n }\n\n args.callbacks?.onSuccess?.();\n\n // `null` is the default return type\n if (result !== null) {\n logOutput(formatValue(result));\n }\n}\n\nasync function getFakeIdentity(ctx: Context, identityString: string) {\n let identity: UserIdentityAttributes;\n try {\n identity = JSON5.parse(identityString);\n } catch (err) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Failed to parse identity as JSON: \"${identityString}\"\\n${chalkStderr.red((err as Error).toString().trim())}`,\n });\n }\n const subject = identity.subject ?? \"\" + simpleHash(JSON.stringify(identity));\n const issuer = identity.issuer ?? \"https://convex.test\";\n const tokenIdentifier =\n identity.tokenIdentifier ?? `${issuer.toString()}|${subject.toString()}`;\n return {\n ...identity,\n subject,\n issuer,\n tokenIdentifier,\n };\n}\n\nexport async function parseArgs(ctx: Context, argsString: string) {\n try {\n const argsJson = JSON5.parse(argsString);\n return jsonToConvex(argsJson) as Record<string, Value>;\n } catch (err) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem or env vars\",\n printedMessage: `Failed to parse arguments as JSON: \"${argsString}\"\\n${chalkStderr.red((err as Error).toString().trim())}`,\n });\n }\n}\n\nexport async function parseFunctionName(\n ctx: Context,\n functionName: string,\n // Usually `convex/` -- should contain trailing slash\n functionDirName: string,\n) {\n // api.foo.bar -> foo:bar\n // foo/bar -> foo/bar:default\n // foo/bar:baz -> foo/bar:baz\n // convex/foo/bar -> foo/bar:default\n\n // This is the `api.foo.bar` format\n if (functionName.startsWith(\"api.\") || functionName.startsWith(\"internal.\")) {\n const parts = functionName.split(\".\");\n if (parts.length < 3) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Function name has too few parts: \"${functionName}\"`,\n });\n }\n const exportName = parts.pop();\n const parsedName = `${parts.slice(1).join(\"/\")}:${exportName}`;\n return parsedName;\n }\n\n // This is the `foo/bar:baz` format\n\n // This is something like `convex/foo/bar`, which could either be addressing `foo/bar:default` or `convex/foo/bar:default`\n // if there's a directory with the same name as the functions directory nested directly underneath.\n // We'll prefer the `convex/foo/bar:default` version, and check if the file exists, and otherwise treat this as a relative path from the project root.\n const filePath = functionName.split(\":\")[0];\n const possibleExtensions = [\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".mts\",\n \".mjs\",\n \".cts\",\n \".cjs\",\n ];\n let hasExtension = false;\n let normalizedFilePath: string = filePath;\n for (const extension of possibleExtensions) {\n if (filePath.endsWith(extension)) {\n normalizedFilePath = filePath.slice(0, -extension.length);\n hasExtension = true;\n break;\n }\n }\n\n const exportName = functionName.split(\":\")[1] ?? \"default\";\n const normalizedName = `${normalizedFilePath}:${exportName}`;\n\n // This isn't a relative path from the project root\n if (!filePath.startsWith(functionDirName)) {\n return normalizedName;\n }\n\n const filePathWithoutPrefix = normalizedFilePath.slice(\n functionDirName.length,\n );\n const functionNameWithoutPrefix = `${filePathWithoutPrefix}:${exportName}`;\n\n if (hasExtension) {\n if (ctx.fs.exists(path.join(functionDirName, filePath))) {\n return normalizedName;\n } else {\n return functionNameWithoutPrefix;\n }\n } else {\n const exists = possibleExtensions.some((extension) =>\n ctx.fs.exists(path.join(functionDirName, filePath + extension)),\n );\n if (exists) {\n return normalizedName;\n } else {\n return functionNameWithoutPrefix;\n }\n }\n}\n\nfunction simpleHash(string: string) {\n let hash = 0;\n for (let i = 0; i < string.length; i++) {\n const char = string.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return hash;\n}\n\nexport async function runSystemPaginatedQuery(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n componentPath: string | undefined;\n args: Record<string, Value>;\n limit?: number;\n },\n) {\n const results = [];\n let cursor = null;\n let isDone = false;\n while (!isDone && (args.limit === undefined || results.length < args.limit)) {\n const paginationResult = (await runSystemQuery(ctx, {\n ...args,\n args: {\n ...args.args,\n paginationOpts: {\n cursor,\n numItems:\n args.limit === undefined ? 10000 : args.limit - results.length,\n },\n },\n })) as unknown as PaginationResult<Record<string, Value>>;\n isDone = paginationResult.isDone;\n cursor = paginationResult.continueCursor;\n results.push(...paginationResult.page);\n }\n return results;\n}\n\nexport async function runSystemQuery(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n componentPath: string | undefined;\n args: Record<string, Value>;\n },\n): Promise<Value> {\n let onResult: (result: Value) => void;\n const resultPromise = new Promise<Value>((resolve) => {\n onResult = resolve;\n });\n const [donePromise, onDone] = waitUntilCalled();\n await subscribe(ctx, {\n ...args,\n parsedFunctionName: args.functionName,\n parsedFunctionArgs: args.args,\n until: donePromise,\n callbacks: {\n onChange: (result) => {\n onDone();\n onResult(result);\n },\n },\n });\n return resultPromise;\n}\n\nexport function formatValue(value: Value) {\n const json = convexToJson(value);\n if (process.stdout.isTTY) {\n // TODO (Tom) add JSON syntax highlighting like https://stackoverflow.com/a/51319962/398212\n // until then, just spit out something that isn't quite JSON because it's easy\n return util.inspect(value, { colors: true, depth: null });\n } else {\n return JSON.stringify(json, null, 2);\n }\n}\n\nexport async function subscribeAndLog(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n componentPath: string | undefined;\n },\n) {\n const { projectConfig } = await readProjectConfig(ctx);\n\n const parsedFunctionName = await parseFunctionName(\n ctx,\n args.functionName,\n projectConfig.functions,\n );\n const identity = args.identityString\n ? await getFakeIdentity(ctx, args.identityString)\n : undefined;\n const functionArgs = await parseArgs(ctx, args.argsString);\n return subscribe(ctx, {\n deploymentUrl: args.deploymentUrl,\n adminKey: args.adminKey,\n identity,\n parsedFunctionName,\n parsedFunctionArgs: functionArgs,\n componentPath: args.componentPath,\n until: waitForever(),\n callbacks: {\n onStart() {\n logFinishedStep(\n `Watching query ${args.functionName} on ${args.deploymentUrl}...`,\n );\n },\n onChange(result) {\n logOutput(formatValue(result));\n },\n onStop() {\n logMessage(`Closing connection to ${args.deploymentUrl}...`);\n },\n },\n });\n}\n\nexport async function subscribe(\n ctx: Context,\n args: {\n deploymentUrl: string;\n adminKey: string;\n identity?: UserIdentityAttributes | undefined;\n parsedFunctionName: string;\n parsedFunctionArgs: Record<string, Value>;\n componentPath: string | undefined;\n until: Promise<unknown>;\n callbacks?:\n | {\n onStart?: () => void;\n onChange?: (result: Value) => void;\n onStop?: () => void;\n }\n | undefined;\n },\n) {\n const client = new BaseConvexClient(\n args.deploymentUrl,\n (updatedQueries) => {\n for (const queryToken of updatedQueries) {\n let result: Value;\n try {\n result = client.localQueryResultByToken(queryToken)!;\n } catch (err) {\n // A failed query (e.g. a permission error) throws here. Surface\n // permission errors cleanly instead of an uncaught stack trace, and\n // let any other error propagate as before.\n const permissionError = permissionDeniedErrorMessage(\n (err as Error).toString(),\n );\n if (permissionError !== null) {\n void ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: chalkStderr.red(permissionError),\n });\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n throw err;\n }\n args.callbacks?.onChange?.(result);\n }\n },\n {\n // pretend that a Node.js 'ws' library WebSocket is a browser WebSocket\n webSocketConstructor: ws as unknown as typeof WebSocket,\n unsavedChangesWarning: false,\n },\n );\n client.setAdminAuth(args.adminKey, args.identity);\n const { unsubscribe } = client.subscribe(\n args.parsedFunctionName,\n args.parsedFunctionArgs,\n {\n componentPath: args.componentPath,\n },\n );\n\n args.callbacks?.onStart?.();\n\n let done = false;\n const [donePromise, onDone] = waitUntilCalled();\n const stopWatching = () => {\n if (done) {\n return;\n }\n done = true;\n unsubscribe();\n void client.close();\n process.off(\"SIGINT\", sigintListener);\n onDone();\n args.callbacks?.onStop?.();\n };\n function sigintListener() {\n stopWatching();\n }\n process.on(\"SIGINT\", sigintListener);\n void args.until.finally(stopWatching);\n while (!done) {\n // loops once per day (any large value < 2**31 would work)\n const oneDay = 24 * 60 * 60 * 1000;\n await Promise.race([\n donePromise,\n new Promise((resolve) => setTimeout(resolve, oneDay)),\n ]);\n }\n}\n\nexport async function runInDeployment(\n ctx: OneoffCtx,\n args: {\n deploymentUrl: string;\n adminKey: string;\n deploymentName: string | null;\n functionName: string;\n argsString: string;\n identityString?: string | undefined;\n push: boolean;\n watch: boolean;\n typecheck: \"enable\" | \"try\" | \"disable\";\n typecheckComponents: boolean;\n codegen: boolean;\n componentPath: string | undefined;\n liveComponentSources: boolean;\n },\n) {\n if (args.push) await pushToDeployment(ctx, args);\n\n if (args.watch) {\n return await subscribeAndLog(ctx, args);\n }\n return await runFunctionAndLog(ctx, args);\n}\n\nexport async function pushToDeployment(\n ctx: OneoffCtx,\n args: {\n deploymentUrl: string;\n adminKey: string;\n deploymentName: string | null;\n typecheck: \"enable\" | \"try\" | \"disable\";\n typecheckComponents: boolean;\n codegen: boolean;\n liveComponentSources: boolean;\n },\n) {\n await watchAndPush(\n ctx,\n {\n url: args.deploymentUrl,\n adminKey: args.adminKey,\n deploymentName: args.deploymentName,\n verbose: false,\n dryRun: false,\n typecheck: args.typecheck,\n typecheckComponents: args.typecheckComponents,\n debug: false,\n debugNodeApis: false,\n codegen: args.codegen,\n liveComponentSources: args.liveComponentSources,\n pushAllModules: false,\n largeIndexDeletionCheck: \"no verification\", // `convex run` can\u2019t push to prod\n message: null,\n },\n {\n once: true,\n traceEvents: false,\n untilSuccess: true,\n },\n );\n}\n\nfunction instantiateStderrLogger(): Logger {\n const logger = new DefaultLogger({ verbose: false });\n logger.addLogLineListener((_level, ...args) => {\n // eslint-disable-next-line no-console\n console.error(...args);\n });\n return logger;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AAC5B,kBAAiB;AACjB,gBAAe;AACf,yBAAiC;AACjC,qBAAiC;AACjC,oBAIO;AACP,mBAAkD;AAElD,iBAAuD;AACvD,mBAIO;AACP,mBAAkB;AAClB,kBAAiB;AACjB,oBAAkC;AAClC,iBAA6B;AAC7B,qBAAsC;AAEtC,eAAsB,kBACpB,KACA,MAaA;AACA,QAAM,SAAS,IAAI,oCAAiB,KAAK,eAAe;AAAA,IACtD,QAAQ,wBAAwB;AAAA,EAClC,CAAC;AACD,QAAM,WAAW,KAAK,iBAClB,MAAM,gBAAgB,KAAK,KAAK,cAAc,IAC9C;AACJ,SAAO,aAAa,KAAK,UAAU,QAAQ;AAE3C,QAAM,eAAe,MAAM,UAAU,KAAK,KAAK,UAAU;AACzD,QAAM,EAAE,cAAc,IAAI,UAAM,iCAAkB,GAAG;AACrD,QAAM,qBAAqB,MAAM;AAAA,IAC/B;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,EAChB;AACA,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,OAAO;AAAA,UACpB,qCAAsB,kBAAkB;AAAA,MACxC,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,eAAgB,IAAc,SAAS,EAAE,KAAK;AAEpD,UAAM,sBAAkB,2CAA6B,YAAY;AACjE,QAAI,oBAAoB,MAAM;AAC5B,aAAO,MAAM,IAAI,MAAM;AAAA,QACrB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,gBAAgB,yBAAY,IAAI,eAAe;AAAA,MACjD,CAAC;AAAA,IACH;AAEA,QAAI,aAAa,SAAS,yBAAyB,GAAG;AACpD,YAAM,YAAa,MAAM,eAAe,KAAK;AAAA,QAC3C,eAAe,KAAK;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,cAAc;AAAA,QACd,eAAe,KAAK;AAAA,QACpB,MAAM,CAAC;AAAA,MACT,CAAC;AAUD,YAAM,gBAAgB,UACnB;AAAA,QACC,CACE,OAIG,GAAG,iBAAiB;AAAA,MAC3B,EACC,IAAI,CAAC,EAAE,WAAW,MAAM;AACvB,cAAM,eAAe,WAAW,QAAQ,GAAG;AAE3C,cAAMA,QACJ,iBAAiB,KACb,KACA,WAAW,UAAU,GAAG,YAAY,EAAE,QAAQ,SAAS,EAAE;AAC/D,cAAM,OACJ,iBAAiB,KACb,aACA,WAAW,UAAU,eAAe,CAAC;AAE3C,eAAO,UAAK,yBAAY,KAAK,GAAGA,KAAI,GAAG,CAAC,GAAG,IAAI;AAAA,MACjD,CAAC;AAEH,YAAM,4BACJ,cAAc,SAAS,IACnB;AAAA,EAAyB,cAAc,KAAK,IAAI,CAAC,KACjD;AAEN,aAAO,MAAM,IAAI,MAAM;AAAA,QACrB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,gBAAgB,2BAA2B,KAAK,YAAY;AAAA,EAAO,yBAAY,IAAI,YAAY,CAAC;AAAA;AAAA,EAAO,yBAAyB;AAAA,MAClI,CAAC;AAAA,IACH;AAEA,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB,2BAA2B,KAAK,YAAY;AAAA,EAAO,yBAAY,IAAI,YAAY,CAAC;AAAA,IAClG,CAAC;AAAA,EACH;AAEA,OAAK,WAAW,YAAY;AAG5B,MAAI,WAAW,MAAM;AACnB,8BAAU,YAAY,MAAM,CAAC;AAAA,EAC/B;AACF;AAEA,eAAe,gBAAgB,KAAc,gBAAwB;AACnE,MAAI;AACJ,MAAI;AACF,eAAW,aAAAC,QAAM,MAAM,cAAc;AAAA,EACvC,SAAS,KAAK;AACZ,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB,sCAAsC,cAAc;AAAA,EAAM,yBAAY,IAAK,IAAc,SAAS,EAAE,KAAK,CAAC,CAAC;AAAA,IAC7H,CAAC;AAAA,EACH;AACA,QAAM,UAAU,SAAS,WAAW,KAAK,WAAW,KAAK,UAAU,QAAQ,CAAC;AAC5E,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,kBACJ,SAAS,mBAAmB,GAAG,OAAO,SAAS,CAAC,IAAI,QAAQ,SAAS,CAAC;AACxE,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,UAAU,KAAc,YAAoB;AAChE,MAAI;AACF,UAAM,WAAW,aAAAA,QAAM,MAAM,UAAU;AACvC,eAAO,2BAAa,QAAQ;AAAA,EAC9B,SAAS,KAAK;AACZ,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB,uCAAuC,UAAU;AAAA,EAAM,yBAAY,IAAK,IAAc,SAAS,EAAE,KAAK,CAAC,CAAC;AAAA,IAC1H,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,kBACpB,KACA,cAEA,iBACA;AAOA,MAAI,aAAa,WAAW,MAAM,KAAK,aAAa,WAAW,WAAW,GAAG;AAC3E,UAAM,QAAQ,aAAa,MAAM,GAAG;AACpC,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO,MAAM,IAAI,MAAM;AAAA,QACrB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,gBAAgB,qCAAqC,YAAY;AAAA,MACnE,CAAC;AAAA,IACH;AACA,UAAMC,cAAa,MAAM,IAAI;AAC7B,UAAM,aAAa,GAAG,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,IAAIA,WAAU;AAC5D,WAAO;AAAA,EACT;AAOA,QAAM,WAAW,aAAa,MAAM,GAAG,EAAE,CAAC;AAC1C,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,eAAe;AACnB,MAAI,qBAA6B;AACjC,aAAW,aAAa,oBAAoB;AAC1C,QAAI,SAAS,SAAS,SAAS,GAAG;AAChC,2BAAqB,SAAS,MAAM,GAAG,CAAC,UAAU,MAAM;AACxD,qBAAe;AACf;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,aAAa,MAAM,GAAG,EAAE,CAAC,KAAK;AACjD,QAAM,iBAAiB,GAAG,kBAAkB,IAAI,UAAU;AAG1D,MAAI,CAAC,SAAS,WAAW,eAAe,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,wBAAwB,mBAAmB;AAAA,IAC/C,gBAAgB;AAAA,EAClB;AACA,QAAM,4BAA4B,GAAG,qBAAqB,IAAI,UAAU;AAExE,MAAI,cAAc;AAChB,QAAI,IAAI,GAAG,OAAO,YAAAF,QAAK,KAAK,iBAAiB,QAAQ,CAAC,GAAG;AACvD,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF,OAAO;AACL,UAAM,SAAS,mBAAmB;AAAA,MAAK,CAAC,cACtC,IAAI,GAAG,OAAO,YAAAA,QAAK,KAAK,iBAAiB,WAAW,SAAS,CAAC;AAAA,IAChE;AACA,QAAI,QAAQ;AACV,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,WAAW,QAAgB;AAClC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,OAAO,OAAO,WAAW,CAAC;AAChC,YAAQ,QAAQ,KAAK,OAAO;AAC5B,WAAO,OAAO;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAsB,wBACpB,KACA,MAQA;AACA,QAAM,UAAU,CAAC;AACjB,MAAI,SAAS;AACb,MAAI,SAAS;AACb,SAAO,CAAC,WAAW,KAAK,UAAU,UAAa,QAAQ,SAAS,KAAK,QAAQ;AAC3E,UAAM,mBAAoB,MAAM,eAAe,KAAK;AAAA,MAClD,GAAG;AAAA,MACH,MAAM;AAAA,QACJ,GAAG,KAAK;AAAA,QACR,gBAAgB;AAAA,UACd;AAAA,UACA,UACE,KAAK,UAAU,SAAY,MAAQ,KAAK,QAAQ,QAAQ;AAAA,QAC5D;AAAA,MACF;AAAA,IACF,CAAC;AACD,aAAS,iBAAiB;AAC1B,aAAS,iBAAiB;AAC1B,YAAQ,KAAK,GAAG,iBAAiB,IAAI;AAAA,EACvC;AACA,SAAO;AACT;AAEA,eAAsB,eACpB,KACA,MAOgB;AAChB,MAAI;AACJ,QAAM,gBAAgB,IAAI,QAAe,CAAC,YAAY;AACpD,eAAW;AAAA,EACb,CAAC;AACD,QAAM,CAAC,aAAa,MAAM,QAAI,8BAAgB;AAC9C,QAAM,UAAU,KAAK;AAAA,IACnB,GAAG;AAAA,IACH,oBAAoB,KAAK;AAAA,IACzB,oBAAoB,KAAK;AAAA,IACzB,OAAO;AAAA,IACP,WAAW;AAAA,MACT,UAAU,CAAC,WAAW;AACpB,eAAO;AACP,iBAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEO,SAAS,YAAY,OAAc;AACxC,QAAM,WAAO,2BAAa,KAAK;AAC/B,MAAI,QAAQ,OAAO,OAAO;AAGxB,WAAO,YAAAG,QAAK,QAAQ,OAAO,EAAE,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,EAC1D,OAAO;AACL,WAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACrC;AACF;AAEA,eAAsB,gBACpB,KACA,MAQA;AACA,QAAM,EAAE,cAAc,IAAI,UAAM,iCAAkB,GAAG;AAErD,QAAM,qBAAqB,MAAM;AAAA,IAC/B;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,EAChB;AACA,QAAM,WAAW,KAAK,iBAClB,MAAM,gBAAgB,KAAK,KAAK,cAAc,IAC9C;AACJ,QAAM,eAAe,MAAM,UAAU,KAAK,KAAK,UAAU;AACzD,SAAO,UAAU,KAAK;AAAA,IACpB,eAAe,KAAK;AAAA,IACpB,UAAU,KAAK;AAAA,IACf;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB,eAAe,KAAK;AAAA,IACpB,WAAO,0BAAY;AAAA,IACnB,WAAW;AAAA,MACT,UAAU;AACR;AAAA,UACE,kBAAkB,KAAK,YAAY,OAAO,KAAK,aAAa;AAAA,QAC9D;AAAA,MACF;AAAA,MACA,SAAS,QAAQ;AACf,kCAAU,YAAY,MAAM,CAAC;AAAA,MAC/B;AAAA,MACA,SAAS;AACP,mCAAW,yBAAyB,KAAK,aAAa,KAAK;AAAA,MAC7D;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,UACpB,KACA,MAgBA;AACA,QAAM,SAAS,IAAI;AAAA,IACjB,KAAK;AAAA,IACL,CAAC,mBAAmB;AAClB,iBAAW,cAAc,gBAAgB;AACvC,YAAI;AACJ,YAAI;AACF,mBAAS,OAAO,wBAAwB,UAAU;AAAA,QACpD,SAAS,KAAK;AAIZ,gBAAM,sBAAkB;AAAA,YACrB,IAAc,SAAS;AAAA,UAC1B;AACA,cAAI,oBAAoB,MAAM;AAC5B,iBAAK,IAAI,MAAM;AAAA,cACb,UAAU;AAAA,cACV,WAAW;AAAA,cACX,gBAAgB,yBAAY,IAAI,eAAe;AAAA,YACjD,CAAC;AACD;AAAA,UACF;AAEA,gBAAM;AAAA,QACR;AACA,aAAK,WAAW,WAAW,MAAM;AAAA,MACnC;AAAA,IACF;AAAA,IACA;AAAA;AAAA,MAEE,sBAAsB,UAAAC;AAAA,MACtB,uBAAuB;AAAA,IACzB;AAAA,EACF;AACA,SAAO,aAAa,KAAK,UAAU,KAAK,QAAQ;AAChD,QAAM,EAAE,YAAY,IAAI,OAAO;AAAA,IAC7B,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,MACE,eAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,OAAK,WAAW,UAAU;AAE1B,MAAI,OAAO;AACX,QAAM,CAAC,aAAa,MAAM,QAAI,8BAAgB;AAC9C,QAAM,eAAe,MAAM;AACzB,QAAI,MAAM;AACR;AAAA,IACF;AACA,WAAO;AACP,gBAAY;AACZ,SAAK,OAAO,MAAM;AAClB,YAAQ,IAAI,UAAU,cAAc;AACpC,WAAO;AACP,SAAK,WAAW,SAAS;AAAA,EAC3B;AACA,WAAS,iBAAiB;AACxB,iBAAa;AAAA,EACf;AACA,UAAQ,GAAG,UAAU,cAAc;AACnC,OAAK,KAAK,MAAM,QAAQ,YAAY;AACpC,SAAO,CAAC,MAAM;AAEZ,UAAM,SAAS,KAAK,KAAK,KAAK;AAC9B,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,MACA,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,MAAM,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,gBACpB,KACA,MAeA;AACA,MAAI,KAAK,KAAM,OAAM,iBAAiB,KAAK,IAAI;AAE/C,MAAI,KAAK,OAAO;AACd,WAAO,MAAM,gBAAgB,KAAK,IAAI;AAAA,EACxC;AACA,SAAO,MAAM,kBAAkB,KAAK,IAAI;AAC1C;AAEA,eAAsB,iBACpB,KACA,MASA;AACA,YAAM;AAAA,IACJ;AAAA,IACA;AAAA,MACE,KAAK,KAAK;AAAA,MACV,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,WAAW,KAAK;AAAA,MAChB,qBAAqB,KAAK;AAAA,MAC1B,OAAO;AAAA,MACP,eAAe;AAAA,MACf,SAAS,KAAK;AAAA,MACd,sBAAsB,KAAK;AAAA,MAC3B,gBAAgB;AAAA,MAChB,yBAAyB;AAAA;AAAA,MACzB,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,cAAc;AAAA,IAChB;AAAA,EACF;AACF;AAEA,SAAS,0BAAkC;AACzC,QAAM,SAAS,IAAI,6BAAc,EAAE,SAAS,MAAM,CAAC;AACnD,SAAO,mBAAmB,CAAC,WAAW,SAAS;AAE7C,YAAQ,MAAM,GAAG,IAAI;AAAA,EACvB,CAAC;AACD,SAAO;AACT;",
6
6
  "names": ["path", "JSON5", "exportName", "util", "ws"]
7
7
  }
@@ -62,6 +62,7 @@ __export(utils_exports, {
62
62
  logNoDefaultRegionMessage: () => logNoDefaultRegionMessage,
63
63
  parseInteger: () => parseInteger,
64
64
  parsePositiveInteger: () => parsePositiveInteger,
65
+ permissionDeniedErrorMessage: () => permissionDeniedErrorMessage,
65
66
  poll: () => poll,
66
67
  processDeployKeyValue: () => processDeployKeyValue,
67
68
  productionProvisionHost: () => productionProvisionHost,
@@ -131,6 +132,27 @@ function readDeployKeyFromEnv(getEnv) {
131
132
  const fromToken = getEnv(CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME);
132
133
  return fromDeployKey || fromToken || void 0;
133
134
  }
135
+ const PERMISSION_DENIED_MESSAGE_PREFIX = "You do not have permission to perform this operation";
136
+ function deployKeyPermissionAdvice() {
137
+ const envVarName = process.env[CONVEX_DEPLOY_KEY_ENV_VAR_NAME] ? CONVEX_DEPLOY_KEY_ENV_VAR_NAME : process.env[CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME] ? CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME : null;
138
+ if (envVarName === null) {
139
+ return null;
140
+ }
141
+ return `This is determined by the permissions granted to ${envVarName}.`;
142
+ }
143
+ function permissionDeniedErrorMessage(errorMessage) {
144
+ const index = errorMessage.indexOf(PERMISSION_DENIED_MESSAGE_PREFIX);
145
+ if (index === -1) {
146
+ return null;
147
+ }
148
+ let msg = errorMessage.slice(index).split("\n")[0].trim();
149
+ const advice = deployKeyPermissionAdvice();
150
+ if (advice) {
151
+ msg = `${msg}
152
+ ${advice}`;
153
+ }
154
+ return msg;
155
+ }
134
156
  function parsePositiveInteger(value) {
135
157
  const parsedValue = parseInteger(value);
136
158
  if (parsedValue <= 0) {
@@ -185,6 +207,14 @@ class ThrowingFetchError extends Error {
185
207
  error_type = "fatal";
186
208
  msg = `${msg}
187
209
  Authenticate with \`npx convex dev\``;
210
+ } else if (this.response.status === 403) {
211
+ error_type = "fatal";
212
+ msg = this.serverErrorData?.message ?? msg;
213
+ const advice = deployKeyPermissionAdvice();
214
+ if (advice) {
215
+ msg = `${msg}
216
+ ${advice}`;
217
+ }
188
218
  } else if (this.response.status === 404) {
189
219
  error_type = "fatal";
190
220
  msg = `${msg}: ${this.response.url}`;