convex 1.43.0-alpha.1 → 1.44.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 (123) hide show
  1. package/CHANGELOG.md +133 -81
  2. package/dist/browser.bundle.js +1 -1
  3. package/dist/browser.bundle.js.map +1 -1
  4. package/dist/cjs/cli/codegen_templates/component_server.js +4 -3
  5. package/dist/cjs/cli/codegen_templates/component_server.js.map +2 -2
  6. package/dist/cjs/cli/codegen_templates/server.js +24 -12
  7. package/dist/cjs/cli/codegen_templates/server.js.map +2 -2
  8. package/dist/cjs/cli/lib/localDeployment/run.js +1 -1
  9. package/dist/cjs/cli/lib/localDeployment/run.js.map +2 -2
  10. package/dist/cjs/cli/lib/login.js +12 -8
  11. package/dist/cjs/cli/lib/login.js.map +2 -2
  12. package/dist/cjs/cli/lib/utils/sentry.js +2 -0
  13. package/dist/cjs/cli/lib/utils/sentry.js.map +2 -2
  14. package/dist/cjs/cli/login.js +52 -7
  15. package/dist/cjs/cli/login.js.map +2 -2
  16. package/dist/cjs/index.js +1 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/react/ConvexAuthState.js +30 -32
  19. package/dist/cjs/react/ConvexAuthState.js.map +2 -2
  20. package/dist/cjs/server/impl/actions_impl.js +12 -0
  21. package/dist/cjs/server/impl/actions_impl.js.map +2 -2
  22. package/dist/cjs/server/index.js +3 -0
  23. package/dist/cjs/server/index.js.map +2 -2
  24. package/dist/cjs/server/log.js +1 -2
  25. package/dist/cjs/server/log.js.map +2 -2
  26. package/dist/cjs/server/logVars.js +1 -4
  27. package/dist/cjs/server/logVars.js.map +2 -2
  28. package/dist/cjs/server/schema.js +69 -1
  29. package/dist/cjs/server/schema.js.map +2 -2
  30. package/dist/cjs-types/cli/codegen_templates/component_server.d.ts.map +1 -1
  31. package/dist/cjs-types/cli/codegen_templates/server.d.ts +1 -0
  32. package/dist/cjs-types/cli/codegen_templates/server.d.ts.map +1 -1
  33. package/dist/cjs-types/cli/lib/login.d.ts +5 -0
  34. package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
  35. package/dist/cjs-types/cli/lib/utils/sentry.d.ts +1 -0
  36. package/dist/cjs-types/cli/lib/utils/sentry.d.ts.map +1 -1
  37. package/dist/cjs-types/cli/login.d.ts.map +1 -1
  38. package/dist/cjs-types/cli/login.test.d.ts +2 -0
  39. package/dist/cjs-types/cli/login.test.d.ts.map +1 -0
  40. package/dist/cjs-types/index.d.ts +1 -1
  41. package/dist/cjs-types/index.d.ts.map +1 -1
  42. package/dist/cjs-types/react/ConvexAuthState.d.ts.map +1 -1
  43. package/dist/cjs-types/server/impl/actions_impl.d.ts.map +1 -1
  44. package/dist/cjs-types/server/impl/actions_impl.test.d.ts +2 -0
  45. package/dist/cjs-types/server/impl/actions_impl.test.d.ts.map +1 -0
  46. package/dist/cjs-types/server/index.d.ts +2 -2
  47. package/dist/cjs-types/server/index.d.ts.map +1 -1
  48. package/dist/cjs-types/server/log.d.ts.map +1 -1
  49. package/dist/cjs-types/server/logVars.d.ts +0 -6
  50. package/dist/cjs-types/server/logVars.d.ts.map +1 -1
  51. package/dist/cjs-types/server/schema.d.ts +83 -5
  52. package/dist/cjs-types/server/schema.d.ts.map +1 -1
  53. package/dist/cli.bundle.cjs +1280 -572
  54. package/dist/cli.bundle.cjs.map +4 -4
  55. package/dist/esm/cli/codegen_templates/component_server.js +8 -4
  56. package/dist/esm/cli/codegen_templates/component_server.js.map +2 -2
  57. package/dist/esm/cli/codegen_templates/server.js +22 -11
  58. package/dist/esm/cli/codegen_templates/server.js.map +2 -2
  59. package/dist/esm/cli/lib/localDeployment/run.js +2 -2
  60. package/dist/esm/cli/lib/localDeployment/run.js.map +2 -2
  61. package/dist/esm/cli/lib/login.js +11 -8
  62. package/dist/esm/cli/lib/login.js.map +2 -2
  63. package/dist/esm/cli/lib/utils/sentry.js +1 -0
  64. package/dist/esm/cli/lib/utils/sentry.js.map +2 -2
  65. package/dist/esm/cli/login.js +54 -10
  66. package/dist/esm/cli/login.js.map +2 -2
  67. package/dist/esm/index.js +1 -1
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/esm/react/ConvexAuthState.js +31 -32
  70. package/dist/esm/react/ConvexAuthState.js.map +2 -2
  71. package/dist/esm/server/impl/actions_impl.js +11 -0
  72. package/dist/esm/server/impl/actions_impl.js.map +2 -2
  73. package/dist/esm/server/index.js +2 -1
  74. package/dist/esm/server/index.js.map +2 -2
  75. package/dist/esm/server/log.js +2 -3
  76. package/dist/esm/server/log.js.map +2 -2
  77. package/dist/esm/server/logVars.js +1 -3
  78. package/dist/esm/server/logVars.js.map +2 -2
  79. package/dist/esm/server/schema.js +67 -0
  80. package/dist/esm/server/schema.js.map +2 -2
  81. package/dist/esm-types/cli/codegen_templates/component_server.d.ts.map +1 -1
  82. package/dist/esm-types/cli/codegen_templates/server.d.ts +1 -0
  83. package/dist/esm-types/cli/codegen_templates/server.d.ts.map +1 -1
  84. package/dist/esm-types/cli/lib/login.d.ts +5 -0
  85. package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
  86. package/dist/esm-types/cli/lib/utils/sentry.d.ts +1 -0
  87. package/dist/esm-types/cli/lib/utils/sentry.d.ts.map +1 -1
  88. package/dist/esm-types/cli/login.d.ts.map +1 -1
  89. package/dist/esm-types/cli/login.test.d.ts +2 -0
  90. package/dist/esm-types/cli/login.test.d.ts.map +1 -0
  91. package/dist/esm-types/index.d.ts +1 -1
  92. package/dist/esm-types/index.d.ts.map +1 -1
  93. package/dist/esm-types/react/ConvexAuthState.d.ts.map +1 -1
  94. package/dist/esm-types/server/impl/actions_impl.d.ts.map +1 -1
  95. package/dist/esm-types/server/impl/actions_impl.test.d.ts +2 -0
  96. package/dist/esm-types/server/impl/actions_impl.test.d.ts.map +1 -0
  97. package/dist/esm-types/server/index.d.ts +2 -2
  98. package/dist/esm-types/server/index.d.ts.map +1 -1
  99. package/dist/esm-types/server/log.d.ts.map +1 -1
  100. package/dist/esm-types/server/logVars.d.ts +0 -6
  101. package/dist/esm-types/server/logVars.d.ts.map +1 -1
  102. package/dist/esm-types/server/schema.d.ts +83 -5
  103. package/dist/esm-types/server/schema.d.ts.map +1 -1
  104. package/dist/react.bundle.js +31 -33
  105. package/dist/react.bundle.js.map +2 -2
  106. package/package.json +3 -4
  107. package/src/cli/codegen_templates/component_server.ts +12 -6
  108. package/src/cli/codegen_templates/server.ts +36 -19
  109. package/src/cli/lib/localDeployment/run.ts +2 -2
  110. package/src/cli/lib/login.ts +20 -9
  111. package/src/cli/lib/utils/sentry.ts +3 -0
  112. package/src/cli/login.test.ts +261 -0
  113. package/src/cli/login.ts +88 -13
  114. package/src/index.ts +1 -1
  115. package/src/react/ConvexAuthState.tsx +15 -7
  116. package/src/server/audit_logging.test.ts +1 -1
  117. package/src/server/impl/actions_impl.test.ts +59 -0
  118. package/src/server/impl/actions_impl.ts +23 -0
  119. package/src/server/index.ts +7 -1
  120. package/src/server/log.ts +1 -4
  121. package/src/server/logVars.ts +0 -7
  122. package/src/server/schema.test.ts +98 -0
  123. package/src/server/schema.ts +178 -1
@@ -24,8 +24,9 @@ module.exports = __toCommonJS(component_server_exports);
24
24
  var import_common = require("./common.js");
25
25
  var import_server = require("./server.js");
26
26
  function componentServerTS(isRoot, envVars) {
27
- const hasEnv = !!envVars && envVars.length > 0;
28
- const envInterface = hasEnv ? (0, import_server.generateEnvInterface)(envVars) : "";
27
+ const emittedEnvVars = envVars === void 0 ? void 0 : (0, import_server.withPlatformEnvVars)(envVars);
28
+ const hasEnv = emittedEnvVars !== void 0;
29
+ const envInterface = hasEnv ? (0, import_server.generateEnvInterface)(emittedEnvVars) : "";
29
30
  const result = `
30
31
  ${(0, import_common.header)(
31
32
  "Generated utilities for implementing server-side Convex query and mutation functions."
@@ -128,7 +129,7 @@ function componentServerTS(isRoot, envVars) {
128
129
  * @returns The wrapped function. Import this function from \`convex/http.js\` and route it to hook it up.
129
130
  */
130
131
  export const httpAction: HttpActionBuilder = httpActionGeneric;
131
- ${hasEnv ? "export const env: Env = process.env as unknown as Env;" : envVars === void 0 ? "export const env: Record<string, string | undefined> = process.env as unknown as Record<string, string | undefined>;" : ""}
132
+ ${hasEnv ? "export const env: Env = (globalThis as unknown as { process: { env: Env } }).process.env;" : "export const env: Record<string, string | undefined> = (globalThis as unknown as { process: { env: Record<string, string | undefined> } }).process.env;"}
132
133
 
133
134
  /**
134
135
  * A set of services for use within Convex query functions.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/codegen_templates/component_server.ts"],
4
- "sourcesContent": ["import { header } from \"./common.js\";\nimport { EnvVarMeta, generateEnvInterface } from \"./server.js\";\n\nexport function componentServerTS(\n isRoot: boolean,\n // - undefined: not yet known (initial codegen). Emits an untyped `env` stub.\n // - non-empty array: emit typed `Env` interface and typed `env` export.\n // - empty array: no env vars declared. Omit `env` from generated code.\n envVars: EnvVarMeta[] | undefined,\n): string {\n const hasEnv = !!envVars && envVars.length > 0;\n const envInterface = hasEnv ? generateEnvInterface(envVars!) : \"\";\n\n const result = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import type {\n ActionBuilder,\n ${isRoot ? \"AnyComponents,\" : \"\"}\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n } from \"convex/server\";\n import {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n ${isRoot ? \"componentsGeneric,\" : \"\"}\n } from \"convex/server\";\n import type { DataModel } from \"./dataModel.js\";\n ${envInterface}\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const query: QueryBuilder<DataModel, \"public\"> = queryGeneric;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalQuery: QueryBuilder<DataModel, \"internal\"> = internalQueryGeneric;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const mutation: MutationBuilder<DataModel, \"public\"> = mutationGeneric;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalMutation: MutationBuilder<DataModel, \"internal\"> = internalMutationGeneric;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const action: ActionBuilder<DataModel, \"public\"> = actionGeneric;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalAction: ActionBuilder<DataModel, \"internal\"> = internalActionGeneric;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export const httpAction: HttpActionBuilder = httpActionGeneric;\n ${hasEnv ? \"export const env: Env = process.env as unknown as Env;\" : envVars === undefined ? \"export const env: Record<string, string | undefined> = process.env as unknown as Record<string, string | undefined>;\" : \"\"}\n\n /**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * If you're using code generation, use the \\`QueryCtx\\` type in \\`convex/_generated/server.d.ts\\` instead.\n */\n export type QueryCtx = GenericQueryCtx<DataModel>;\n\n /**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n *\n * If you're using code generation, use the \\`MutationCtx\\` type in \\`convex/_generated/server.d.ts\\` instead.\n */\n export type MutationCtx = GenericMutationCtx<DataModel>;\n\n /**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\n export type ActionCtx = GenericActionCtx<DataModel>;\n\n /**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\n export type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n /**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\n export type DatabaseWriter = GenericDatabaseWriter<DataModel>;\n ${\n isRoot\n ? `\n /**\n * Load the API for calling functions from this Convex deployment's components.\n */\n export const components: AnyComponents = componentsGeneric();`\n : \"\"\n }\n `;\n return result;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AACvB,oBAAiD;AAE1C,SAAS,kBACd,QAIA,SACQ;AACR,QAAM,SAAS,CAAC,CAAC,WAAW,QAAQ,SAAS;AAC7C,QAAM,eAAe,aAAS,oCAAqB,OAAQ,IAAI;AAE/D,QAAM,SAAS;AAAA,QACb;AAAA,IACA;AAAA,EACF,CAAC;AAAA;AAAA;AAAA,MAGG,SAAS,mBAAmB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkB9B,SAAS,uBAAuB,EAAE;AAAA;AAAA;AAAA,IAGpC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2EZ,SAAS,2DAA2D,YAAY,SAAY,yHAAyH,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkDvN,SACI;AAAA;AAAA;AAAA;AAAA,mEAKA,EACN;AAAA;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["import { header } from \"./common.js\";\nimport {\n EnvVarMeta,\n generateEnvInterface,\n withPlatformEnvVars,\n} from \"./server.js\";\n\nexport function componentServerTS(\n isRoot: boolean,\n // - undefined: not yet known (initial codegen). Emits an untyped `env` stub.\n // - array (empty or not): emit a typed `Env` interface and typed `env`\n // export. The interface always includes the platform-provided env vars.\n envVars: EnvVarMeta[] | undefined,\n): string {\n const emittedEnvVars =\n envVars === undefined ? undefined : withPlatformEnvVars(envVars);\n const hasEnv = emittedEnvVars !== undefined;\n const envInterface = hasEnv ? generateEnvInterface(emittedEnvVars!) : \"\";\n\n const result = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import type {\n ActionBuilder,\n ${isRoot ? \"AnyComponents,\" : \"\"}\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n } from \"convex/server\";\n import {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n ${isRoot ? \"componentsGeneric,\" : \"\"}\n } from \"convex/server\";\n import type { DataModel } from \"./dataModel.js\";\n ${envInterface}\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const query: QueryBuilder<DataModel, \"public\"> = queryGeneric;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalQuery: QueryBuilder<DataModel, \"internal\"> = internalQueryGeneric;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const mutation: MutationBuilder<DataModel, \"public\"> = mutationGeneric;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalMutation: MutationBuilder<DataModel, \"internal\"> = internalMutationGeneric;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const action: ActionBuilder<DataModel, \"public\"> = actionGeneric;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalAction: ActionBuilder<DataModel, \"internal\"> = internalActionGeneric;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export const httpAction: HttpActionBuilder = httpActionGeneric;\n ${hasEnv ? \"export const env: Env = (globalThis as unknown as { process: { env: Env } }).process.env;\" : \"export const env: Record<string, string | undefined> = (globalThis as unknown as { process: { env: Record<string, string | undefined> } }).process.env;\"}\n\n /**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * If you're using code generation, use the \\`QueryCtx\\` type in \\`convex/_generated/server.d.ts\\` instead.\n */\n export type QueryCtx = GenericQueryCtx<DataModel>;\n\n /**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n *\n * If you're using code generation, use the \\`MutationCtx\\` type in \\`convex/_generated/server.d.ts\\` instead.\n */\n export type MutationCtx = GenericMutationCtx<DataModel>;\n\n /**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\n export type ActionCtx = GenericActionCtx<DataModel>;\n\n /**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\n export type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n /**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\n export type DatabaseWriter = GenericDatabaseWriter<DataModel>;\n ${\n isRoot\n ? `\n /**\n * Load the API for calling functions from this Convex deployment's components.\n */\n export const components: AnyComponents = componentsGeneric();`\n : \"\"\n }\n `;\n return result;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AACvB,oBAIO;AAEA,SAAS,kBACd,QAIA,SACQ;AACR,QAAM,iBACJ,YAAY,SAAY,aAAY,mCAAoB,OAAO;AACjE,QAAM,SAAS,mBAAmB;AAClC,QAAM,eAAe,aAAS,oCAAqB,cAAe,IAAI;AAEtE,QAAM,SAAS;AAAA,QACb;AAAA,IACA;AAAA,EACF,CAAC;AAAA;AAAA;AAAA,MAGG,SAAS,mBAAmB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkB9B,SAAS,uBAAuB,EAAE;AAAA;AAAA;AAAA,IAGpC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2EZ,SAAS,8FAA8F,yJAAyJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkDhQ,SACI;AAAA;AAAA;AAAA;AAAA,mEAKA,EACN;AAAA;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -19,38 +19,50 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var server_exports = {};
20
20
  __export(server_exports, {
21
21
  generateEnvInterface: () => generateEnvInterface,
22
- serverCodegen: () => serverCodegen
22
+ serverCodegen: () => serverCodegen,
23
+ withPlatformEnvVars: () => withPlatformEnvVars
23
24
  });
24
25
  module.exports = __toCommonJS(server_exports);
25
26
  var import_common = require("./common.js");
26
27
  var import_validator_helpers = require("./validator_helpers.js");
28
+ const PLATFORM_ENV_VARS = [
29
+ ["CONVEX_CLOUD_URL", { type: "value", value: '{"type":"string"}' }],
30
+ ["CONVEX_SITE_URL", { type: "value", value: '{"type":"string"}' }]
31
+ ];
32
+ function withPlatformEnvVars(envVars) {
33
+ return [...PLATFORM_ENV_VARS, ...envVars];
34
+ }
27
35
  const ENV_DOCSTRING = `/**
28
- * Typesafe environment variables declared in \`convex.config.ts\`.
36
+ * Typesafe environment variables.
37
+ *
38
+ * This includes platform-provided env vars and any variables declared in
39
+ * \`convex.config.ts\`.
29
40
  */`;
30
41
  function serverCodegen({
31
42
  useTypeScript,
32
43
  envVars
33
44
  }) {
34
- const hasEnv = !!envVars && envVars.length > 0;
35
- const envInterface = hasEnv ? generateEnvInterface(envVars) : "";
45
+ const emittedEnvVars = envVars === void 0 ? void 0 : withPlatformEnvVars(envVars);
46
+ const hasEnv = emittedEnvVars !== void 0;
47
+ const envInterface = hasEnv ? generateEnvInterface(emittedEnvVars) : "";
36
48
  const envDeclDTS = hasEnv ? `
37
49
  ${ENV_DOCSTRING}
38
50
  export declare const env: Env;
39
- ` : envVars === void 0 ? `
51
+ ` : `
40
52
  export declare const env: Record<string, string | undefined>;
41
- ` : "";
53
+ `;
42
54
  const envDeclTS = hasEnv ? `
43
55
  ${ENV_DOCSTRING}
44
- export const env: Env = process.env as unknown as Env;
45
- ` : envVars === void 0 ? `
46
- export const env: Record<string, string | undefined> = process.env as unknown as Record<string, string | undefined>;
47
- ` : "";
56
+ export const env: Env = (globalThis as unknown as { process: { env: Env } }).process.env;
57
+ ` : `
58
+ export const env: Record<string, string | undefined> = (globalThis as unknown as { process: { env: Record<string, string | undefined> } }).process.env;
59
+ `;
48
60
  const envDeclJS = hasEnv ? `
49
61
  ${ENV_DOCSTRING}
50
62
  export const env = process.env;
51
- ` : envVars === void 0 ? `
63
+ ` : `
52
64
  export const env = process.env;
53
- ` : "";
65
+ `;
54
66
  if (!useTypeScript) {
55
67
  const serverDTS = `
56
68
  ${(0, import_common.header)(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/codegen_templates/server.ts"],
4
- "sourcesContent": ["import { header } from \"./common.js\";\nimport { parseValidator, validatorToType } from \"./validator_helpers.js\";\n\nexport type EnvVarMeta = [\n string,\n { type: \"value\"; value: string; optional?: boolean | undefined },\n];\n\nconst ENV_DOCSTRING = `/**\n * Typesafe environment variables declared in \\`convex.config.ts\\`.\n */`;\n\nexport function serverCodegen({\n useTypeScript,\n envVars,\n}: {\n useTypeScript: boolean;\n // - undefined: env var declarations not yet known (initial codegen before\n // server analysis). Emits an untyped `env` stub so imports don't break.\n // - non-empty array: emit a typed `Env` interface and typed `env` export.\n // - empty array: no env vars declared. Omit `env` from generated code.\n envVars: EnvVarMeta[] | undefined;\n}) {\n const hasEnv = !!envVars && envVars.length > 0;\n const envInterface = hasEnv ? generateEnvInterface(envVars!) : \"\";\n const envDeclDTS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport declare const env: Env;\n`\n : envVars === undefined\n ? `\nexport declare const env: Record<string, string | undefined>;\n`\n : \"\";\n const envDeclTS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport const env: Env = process.env as unknown as Env;\n`\n : envVars === undefined\n ? `\nexport const env: Record<string, string | undefined> = process.env as unknown as Record<string, string | undefined>;\n`\n : \"\";\n const envDeclJS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport const env = process.env;\n`\n : envVars === undefined\n ? `\nexport const env = process.env;\n`\n : \"\";\n\n if (!useTypeScript) {\n // Generate separate .js and .d.ts files\n const serverDTS = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import {\n ActionBuilder,\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n } from \"convex/server\";\n import type { DataModel } from \"./dataModel.js\";\n ${envInterface}\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const query: QueryBuilder<DataModel, \"public\">;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalQuery: QueryBuilder<DataModel, \"internal\">;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const mutation: MutationBuilder<DataModel, \"public\">;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalMutation: MutationBuilder<DataModel, \"internal\">;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const action: ActionBuilder<DataModel, \"public\">;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalAction: ActionBuilder<DataModel, \"internal\">;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export declare const httpAction: HttpActionBuilder;\n${envDeclDTS}\n /**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * This differs from the {@link MutationCtx} because all of the services are\n * read-only.\n */\n export type QueryCtx = GenericQueryCtx<DataModel>;\n\n /**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n */\n export type MutationCtx = GenericMutationCtx<DataModel>;\n\n /**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\n export type ActionCtx = GenericActionCtx<DataModel>;\n\n /**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\n export type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n /**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\n export type DatabaseWriter = GenericDatabaseWriter<DataModel>;`;\n\n const serverJS = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n } from \"convex/server\";\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const query = queryGeneric;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalQuery = internalQueryGeneric;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const mutation = mutationGeneric;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalMutation = internalMutationGeneric;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const action = actionGeneric;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalAction = internalActionGeneric;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export const httpAction = httpActionGeneric;\n${envDeclJS}\n `;\n\n return {\n DTS: serverDTS,\n JS: serverJS,\n };\n } else {\n // Generate combined .ts file\n const serverTS = `${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\nimport {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n} from \"convex/server\";\nimport type {\n ActionBuilder,\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n} from \"convex/server\";\nimport type { DataModel } from \"./dataModel.js\";\n${envInterface}\n\n/**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const query: QueryBuilder<DataModel, \"public\"> = queryGeneric;\n\n/**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalQuery: QueryBuilder<DataModel, \"internal\"> = internalQueryGeneric;\n\n/**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const mutation: MutationBuilder<DataModel, \"public\"> = mutationGeneric;\n\n/**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalMutation: MutationBuilder<DataModel, \"internal\"> = internalMutationGeneric;\n\n/**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const action: ActionBuilder<DataModel, \"public\"> = actionGeneric;\n\n/**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalAction: ActionBuilder<DataModel, \"internal\"> = internalActionGeneric;\n\n/**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\nexport const httpAction: HttpActionBuilder = httpActionGeneric;\n${envDeclTS}\n/**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * This differs from the {@link MutationCtx} because all of the services are\n * read-only.\n */\nexport type QueryCtx = GenericQueryCtx<DataModel>;\n\n/**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n */\nexport type MutationCtx = GenericMutationCtx<DataModel>;\n\n/**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\nexport type ActionCtx = GenericActionCtx<DataModel>;\n\n/**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\nexport type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n/**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\nexport type DatabaseWriter = GenericDatabaseWriter<DataModel>;`;\n\n return {\n TS: serverTS,\n };\n }\n}\n\nexport function generateEnvInterface(envVars: EnvVarMeta[]): string {\n const lines: string[] = [];\n for (const [name, decl] of envVars) {\n const parsed = parseValidator(decl.value);\n let tsType = parsed ? validatorToType(parsed, false) : \"unknown\";\n if (decl.optional) {\n tsType += \" | undefined\";\n }\n lines.push(` readonly ${name}: ${tsType};`);\n }\n return `\n${ENV_DOCSTRING}\ntype Env = {\n${lines.join(\"\\n\")}\n};`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { header } from \"./common.js\";\nimport { parseValidator, validatorToType } from \"./validator_helpers.js\";\n\nexport type EnvVarMeta = [\n string,\n { type: \"value\"; value: string; optional?: boolean | undefined },\n];\n\n// Environment variables the platform always injects into every deployment,\n// independent of the user's `convex.config.ts` declarations. Both are always\n// present, so they're typed as required `string`.\nconst PLATFORM_ENV_VARS: EnvVarMeta[] = [\n [\"CONVEX_CLOUD_URL\", { type: \"value\", value: '{\"type\":\"string\"}' }],\n [\"CONVEX_SITE_URL\", { type: \"value\", value: '{\"type\":\"string\"}' }],\n];\n\n// Prepend the always-present platform env vars. Users can't declare env vars\n// with these names \u2014 the backend rejects overriding built-in system env vars \u2014\n// so there's no collision to worry about.\nexport function withPlatformEnvVars(envVars: EnvVarMeta[]): EnvVarMeta[] {\n return [...PLATFORM_ENV_VARS, ...envVars];\n}\n\nconst ENV_DOCSTRING = `/**\n * Typesafe environment variables.\n *\n * This includes platform-provided env vars and any variables declared in\n * \\`convex.config.ts\\`.\n */`;\n\nexport function serverCodegen({\n useTypeScript,\n envVars,\n}: {\n useTypeScript: boolean;\n // - undefined: env var declarations not yet known (initial codegen before\n // server analysis). Emits an untyped `env` stub so imports don't break.\n // - array (empty or not): emit a typed `Env` interface and typed `env`\n // export. The interface always includes the platform-provided env vars, so\n // an empty array still yields a typed `env` with just those.\n envVars: EnvVarMeta[] | undefined;\n}) {\n const emittedEnvVars =\n envVars === undefined ? undefined : withPlatformEnvVars(envVars);\n const hasEnv = emittedEnvVars !== undefined;\n const envInterface = hasEnv ? generateEnvInterface(emittedEnvVars!) : \"\";\n const envDeclDTS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport declare const env: Env;\n`\n : `\nexport declare const env: Record<string, string | undefined>;\n`;\n // Route through `globalThis` rather than the bare `process` global so the\n // generated file typechecks even in projects without `@types/node`.\n const envDeclTS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport const env: Env = (globalThis as unknown as { process: { env: Env } }).process.env;\n`\n : `\nexport const env: Record<string, string | undefined> = (globalThis as unknown as { process: { env: Record<string, string | undefined> } }).process.env;\n`;\n const envDeclJS = hasEnv\n ? `\n${ENV_DOCSTRING}\nexport const env = process.env;\n`\n : `\nexport const env = process.env;\n`;\n\n if (!useTypeScript) {\n // Generate separate .js and .d.ts files\n const serverDTS = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import {\n ActionBuilder,\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n } from \"convex/server\";\n import type { DataModel } from \"./dataModel.js\";\n ${envInterface}\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const query: QueryBuilder<DataModel, \"public\">;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalQuery: QueryBuilder<DataModel, \"internal\">;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const mutation: MutationBuilder<DataModel, \"public\">;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalMutation: MutationBuilder<DataModel, \"internal\">;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const action: ActionBuilder<DataModel, \"public\">;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export declare const internalAction: ActionBuilder<DataModel, \"internal\">;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export declare const httpAction: HttpActionBuilder;\n${envDeclDTS}\n /**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * This differs from the {@link MutationCtx} because all of the services are\n * read-only.\n */\n export type QueryCtx = GenericQueryCtx<DataModel>;\n\n /**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n */\n export type MutationCtx = GenericMutationCtx<DataModel>;\n\n /**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\n export type ActionCtx = GenericActionCtx<DataModel>;\n\n /**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\n export type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n /**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\n export type DatabaseWriter = GenericDatabaseWriter<DataModel>;`;\n\n const serverJS = `\n ${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\n import {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n } from \"convex/server\";\n\n /**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const query = queryGeneric;\n\n /**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalQuery = internalQueryGeneric;\n\n /**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const mutation = mutationGeneric;\n\n /**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalMutation = internalMutationGeneric;\n\n /**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const action = actionGeneric;\n\n /**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\n export const internalAction = internalActionGeneric;\n\n /**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\n export const httpAction = httpActionGeneric;\n${envDeclJS}\n `;\n\n return {\n DTS: serverDTS,\n JS: serverJS,\n };\n } else {\n // Generate combined .ts file\n const serverTS = `${header(\n \"Generated utilities for implementing server-side Convex query and mutation functions.\",\n )}\nimport {\n actionGeneric,\n httpActionGeneric,\n queryGeneric,\n mutationGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n} from \"convex/server\";\nimport type {\n ActionBuilder,\n HttpActionBuilder,\n MutationBuilder,\n QueryBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericQueryCtx,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n} from \"convex/server\";\nimport type { DataModel } from \"./dataModel.js\";\n${envInterface}\n\n/**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const query: QueryBuilder<DataModel, \"public\"> = queryGeneric;\n\n/**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalQuery: QueryBuilder<DataModel, \"internal\"> = internalQueryGeneric;\n\n/**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const mutation: MutationBuilder<DataModel, \"public\"> = mutationGeneric;\n\n/**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalMutation: MutationBuilder<DataModel, \"internal\"> = internalMutationGeneric;\n\n/**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const action: ActionBuilder<DataModel, \"public\"> = actionGeneric;\n\n/**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an \\`export\\` to name it and make it accessible.\n */\nexport const internalAction: ActionBuilder<DataModel, \"internal\"> = internalActionGeneric;\n\n/**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in \\`convex/http.js\\`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API \\`Request\\` object as its second.\n * @returns The wrapped function. Import this function from \\`convex/http.js\\` and route it to hook it up.\n */\nexport const httpAction: HttpActionBuilder = httpActionGeneric;\n${envDeclTS}\n/**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * This differs from the {@link MutationCtx} because all of the services are\n * read-only.\n */\nexport type QueryCtx = GenericQueryCtx<DataModel>;\n\n/**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n */\nexport type MutationCtx = GenericMutationCtx<DataModel>;\n\n/**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\nexport type ActionCtx = GenericActionCtx<DataModel>;\n\n/**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\nexport type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n/**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\nexport type DatabaseWriter = GenericDatabaseWriter<DataModel>;`;\n\n return {\n TS: serverTS,\n };\n }\n}\n\nexport function generateEnvInterface(envVars: EnvVarMeta[]): string {\n const lines: string[] = [];\n for (const [name, decl] of envVars) {\n const parsed = parseValidator(decl.value);\n let tsType = parsed ? validatorToType(parsed, false) : \"unknown\";\n if (decl.optional) {\n tsType += \" | undefined\";\n }\n lines.push(` readonly ${name}: ${tsType};`);\n }\n return `\n${ENV_DOCSTRING}\ntype Env = {\n${lines.join(\"\\n\")}\n};`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -144,7 +144,7 @@ async function runLocalBackend(ctx, args) {
144
144
  stdio: "ignore",
145
145
  env: {
146
146
  ...process.env,
147
- SENTRY_DSN: import_sentry.SENTRY_DSN
147
+ SENTRY_DSN: import_sentry.LOCAL_BACKEND_SENTRY_DSN
148
148
  }
149
149
  }).on("exit", (code) => {
150
150
  const why = code === null ? "from signal" : `with code ${code}`;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/lib/localDeployment/run.ts"],
4
- "sourcesContent": ["import { Context } from \"../../../bundler/context.js\";\nimport { logVerbose, logMessage } from \"../../../bundler/log.js\";\nimport {\n LocalDeploymentKind,\n deploymentStateDir,\n loadDeploymentConfig,\n loadUuidForAnonymousUser,\n} from \"./filePaths.js\";\nimport { ensureBackendBinaryDownloaded } from \"./download.js\";\nimport path from \"path\";\nimport child_process from \"child_process\";\nimport detect from \"detect-port\";\nimport { SENTRY_DSN } from \"../utils/sentry.js\";\nimport { createHash } from \"crypto\";\nimport { LocalDeploymentError } from \"./errors.js\";\nimport { LOCAL_BACKEND_INSTANCE_SECRET } from \"./utils.js\";\nimport { DeploymentType, DetailedDeploymentCredentials } from \"../api.js\";\n\nconst DEFAULT_STARTUP_TIMEOUT_SECS = 30;\n\nasync function parseStartupTimeoutSecs(ctx: Context): Promise<number> {\n const raw = process.env.CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS;\n if (raw === undefined) {\n return DEFAULT_STARTUP_TIMEOUT_SECS;\n }\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Invalid CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS=${JSON.stringify(raw)}: expected a positive number.`,\n });\n }\n return parsed;\n}\n\nexport async function runLocalBackend(\n ctx: Context,\n args: {\n ports: {\n cloud: number;\n site: number;\n };\n deploymentKind: LocalDeploymentKind;\n deploymentName: string;\n binaryPath: string;\n instanceSecret: string;\n isLatestVersion: boolean;\n },\n): Promise<{\n cleanupHandle: string;\n}> {\n const { ports } = args;\n const deploymentDir = deploymentStateDir(\n ctx,\n args.deploymentKind,\n args.deploymentName,\n );\n ctx.fs.mkdir(deploymentDir, { recursive: true });\n const deploymentNameSha = createHash(\"sha256\")\n .update(args.deploymentName)\n .digest(\"hex\");\n const commandArgs = [\n \"--port\",\n ports.cloud.toString(),\n \"--site-proxy-port\",\n ports.site.toString(),\n \"--sentry-identifier\",\n deploymentNameSha,\n \"--instance-name\",\n args.deploymentName,\n \"--instance-secret\",\n args.instanceSecret,\n \"--local-storage\",\n path.join(deploymentDir, \"convex_local_storage\"),\n \"--beacon-tag\",\n selfHostedEventTag(args.deploymentKind),\n path.join(deploymentDir, \"convex_local_backend.sqlite3\"),\n ];\n if (args.isLatestVersion) {\n // CLI args that were added in later versions of backend go here instead of above\n // since the CLI may run older versions of backend (e.g. when upgrading).\n if (args.deploymentKind === \"anonymous\") {\n const uuid = loadUuidForAnonymousUser(ctx);\n if (uuid !== null) {\n commandArgs.push(\n \"--beacon-fields\",\n JSON.stringify({\n override_uuid: uuid,\n }),\n );\n }\n }\n }\n\n // Check that binary works by running with --help\n try {\n const result = child_process.spawnSync(args.binaryPath, [\n ...commandArgs,\n \"--help\",\n ]);\n if (result.status === 3221225781) {\n const message =\n \"Local backend exited because shared libraries are missing. These may include libraries installed via 'Microsoft Visual C++ Redistributable for Visual Studio.'\";\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(\n \"Local backend exited with code 3221225781\",\n ),\n });\n } else if (result.status !== 0) {\n const message = `Failed to run backend binary, exit code ${result.status}, error: ${result.stderr === null ? \"null\" : result.stderr.toString()}`;\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n }\n } catch (e) {\n const message = `Failed to run backend binary: ${(e as any).toString()}`;\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n }\n const commandStr = `${args.binaryPath} ${commandArgs.join(\" \")}`;\n logVerbose(`Starting local backend: \\`${commandStr}\\``);\n const p = child_process\n .spawn(args.binaryPath, commandArgs, {\n stdio: \"ignore\",\n env: {\n ...process.env,\n SENTRY_DSN: SENTRY_DSN,\n },\n })\n .on(\"exit\", (code) => {\n const why = code === null ? \"from signal\" : `with code ${code}`;\n logVerbose(`Local backend exited ${why}, full command \\`${commandStr}\\``);\n });\n const cleanupHandle = ctx.registerCleanup(async () => {\n logVerbose(`Stopping local backend on port ${ports.cloud}`);\n p.kill(\"SIGTERM\");\n });\n\n await ensureBackendRunning(ctx, {\n cloudPort: ports.cloud,\n deploymentName: args.deploymentName,\n maxTimeSecs: await parseStartupTimeoutSecs(ctx),\n });\n\n return {\n cleanupHandle,\n };\n}\n\n/** Crash if correct local backend is not currently listening on the expected port. */\nexport async function assertLocalBackendRunning(\n ctx: Context,\n args: {\n url: string;\n deploymentName: string;\n },\n): Promise<void> {\n logVerbose(`Checking local backend at ${args.url} is running`);\n const result = await fetchLocalBackendStatus(args);\n switch (result.kind) {\n case \"running\":\n return;\n case \"different\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${result.name} is running at ${args.url}`,\n });\n case \"error\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Error response code received from local backend ${result.resp.status} ${result.resp.statusText}`,\n });\n case \"not-running\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Local backend isn't running. (it's not listening at ${args.url})\\nRun \\`npx convex dev\\` in another terminal first.`,\n });\n }\n}\n\n/** Wait for up to maxTimeSecs for the correct local backend to be running on the expected port. */\nexport async function ensureBackendRunning(\n ctx: Context,\n args: {\n cloudPort: number;\n deploymentName: string;\n maxTimeSecs: number;\n },\n): Promise<void> {\n logVerbose(`Ensuring backend running on port ${args.cloudPort} is running`);\n const deploymentUrl = localDeploymentUrl(args.cloudPort);\n let timeElapsedSecs = 0;\n let hasShownWaiting = false;\n while (timeElapsedSecs <= args.maxTimeSecs) {\n if (!hasShownWaiting && timeElapsedSecs > 2) {\n logMessage(\"waiting for local backend to start...\");\n hasShownWaiting = true;\n }\n try {\n const resp = await fetch(`${deploymentUrl}/instance_name`);\n if (resp.status === 200) {\n const text = await resp.text();\n if (text !== args.deploymentName) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${text} is running on selected port ${args.cloudPort}`,\n });\n } else {\n // The backend is running!\n return;\n }\n } else {\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n } catch {\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n }\n const base = `Local backend did not start on port ${args.cloudPort} within ${args.maxTimeSecs} seconds.`;\n const message =\n args.maxTimeSecs >= DEFAULT_STARTUP_TIMEOUT_SECS\n ? `${base} If your local database is large, increase the timeout by setting CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS (e.g. CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS=120).`\n : base;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n}\n\nexport async function ensureBackendStopped(\n ctx: Context,\n args: {\n ports: {\n cloud: number;\n site?: number;\n };\n maxTimeSecs: number;\n deploymentName: string;\n // Whether to allow a deployment with a different name to run on this port\n allowOtherDeployments: boolean;\n },\n) {\n logVerbose(`Ensuring backend running on port ${args.ports.cloud} is stopped`);\n let timeElapsedSecs = 0;\n while (timeElapsedSecs < args.maxTimeSecs) {\n const cloudPort = await detect(args.ports.cloud);\n const sitePort =\n args.ports.site === undefined ? undefined : await detect(args.ports.site);\n // Both ports are free\n if (cloudPort === args.ports.cloud && sitePort === args.ports.site) {\n return;\n }\n try {\n const instanceNameResp = await fetch(\n `${localDeploymentUrl(args.ports.cloud)}/instance_name`,\n );\n if (instanceNameResp.ok) {\n const instanceName = await instanceNameResp.text();\n if (instanceName !== args.deploymentName) {\n if (args.allowOtherDeployments) {\n return;\n }\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${instanceName} is running on selected port ${args.ports.cloud}`,\n });\n }\n }\n } catch (error: any) {\n logVerbose(`Error checking if backend is running: ${error.message}`);\n // Backend is probably not running\n continue;\n }\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A local backend is still running on port ${args.ports.cloud}. Please stop it and run this command again.`,\n });\n}\n\nexport function localDeploymentUrl(cloudPort: number): string {\n return `http://127.0.0.1:${cloudPort}`;\n}\n\nexport function selfHostedEventTag(\n deploymentKind: LocalDeploymentKind,\n): string {\n return deploymentKind === \"local\" ? \"cli-local-dev\" : \"cli-anonymous-dev\";\n}\n\ntype LocalBackendStatus =\n | { kind: \"running\" }\n | { kind: \"error\"; resp: Response }\n | { kind: \"different\"; name: string }\n | { kind: \"not-running\" };\n\nexport async function fetchLocalBackendStatus(args: {\n url: string;\n deploymentName: string;\n}): Promise<LocalBackendStatus> {\n logVerbose(`Checking local backend at ${args.url} is running`);\n try {\n const resp = await fetch(`${args.url}/instance_name`);\n if (resp.status === 200) {\n const text = await resp.text();\n if (text !== args.deploymentName) {\n return { kind: \"different\", name: text };\n } else {\n return { kind: \"running\" };\n }\n } else {\n return { kind: \"error\", resp };\n }\n } catch {\n return { kind: \"not-running\" };\n }\n}\n\n/** Returns true if the correct local backend is listening. */\nexport async function isLocalBackendRunning(\n url: string,\n deploymentName: string,\n): Promise<boolean> {\n return (\n \"running\" === (await fetchLocalBackendStatus({ url, deploymentName })).kind\n );\n}\n\nexport function shouldUseLocalDeployment(deploymentType: DeploymentType) {\n return deploymentType === \"local\" || deploymentType === \"anonymous\";\n}\n\ninterface WithRunningBackendArgs {\n ctx: Context;\n deployment: {\n deploymentUrl: string;\n deploymentFields: DetailedDeploymentCredentials[\"deploymentFields\"];\n };\n action: () => Promise<void>;\n}\n\n/**\n * If the deployment is a local deployment and not already running, start it\n * for the duration of the action, then stop it.\n */\nexport async function withRunningBackend({\n ctx,\n deployment,\n action,\n}: WithRunningBackendArgs) {\n let cleanup: (() => Promise<void>) | null = null;\n\n if (\n deployment.deploymentFields &&\n shouldUseLocalDeployment(deployment.deploymentFields.deploymentType)\n ) {\n const isRunning = await isLocalBackendRunning(\n deployment.deploymentUrl,\n deployment.deploymentFields.deploymentName,\n );\n if (!isRunning) {\n ({ cleanup } = await startEphemeralLocalBackend(ctx, {\n deploymentType: deployment.deploymentFields.deploymentType,\n deploymentName: deployment.deploymentFields.deploymentName,\n }));\n }\n }\n\n try {\n await action();\n } finally {\n await cleanup?.();\n }\n}\n\n/**\n * Start a local backend for a one-off command using saved deployment config.\n * Returns a cleanup function that stops the backend.\n */\nasync function startEphemeralLocalBackend(\n ctx: Context,\n args: {\n deploymentType: string;\n deploymentName: string;\n },\n): Promise<{ cleanup: () => Promise<void> }> {\n const deploymentKind: LocalDeploymentKind =\n args.deploymentType === \"anonymous\" ? \"anonymous\" : \"local\";\n\n const config = loadDeploymentConfig(ctx, deploymentKind, args.deploymentName);\n if (config === null) {\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Local backend isn't running and no saved configuration found.\\nRun \\`npx convex dev\\` first.`,\n });\n }\n\n const { binaryPath } = await ensureBackendBinaryDownloaded(ctx, {\n kind: \"version\",\n version: config.backendVersion,\n });\n\n const instanceSecret = config.instanceSecret ?? LOCAL_BACKEND_INSTANCE_SECRET;\n\n const { cleanupHandle } = await runLocalBackend(ctx, {\n binaryPath,\n ports: config.ports,\n deploymentKind,\n deploymentName: args.deploymentName,\n instanceSecret,\n isLatestVersion: true,\n });\n\n return {\n cleanup: async () => {\n const fn = ctx.removeCleanup(cleanupHandle);\n if (fn) {\n await fn(0);\n }\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Context } from \"../../../bundler/context.js\";\nimport { logVerbose, logMessage } from \"../../../bundler/log.js\";\nimport {\n LocalDeploymentKind,\n deploymentStateDir,\n loadDeploymentConfig,\n loadUuidForAnonymousUser,\n} from \"./filePaths.js\";\nimport { ensureBackendBinaryDownloaded } from \"./download.js\";\nimport path from \"path\";\nimport child_process from \"child_process\";\nimport detect from \"detect-port\";\nimport { LOCAL_BACKEND_SENTRY_DSN } from \"../utils/sentry.js\";\nimport { createHash } from \"crypto\";\nimport { LocalDeploymentError } from \"./errors.js\";\nimport { LOCAL_BACKEND_INSTANCE_SECRET } from \"./utils.js\";\nimport { DeploymentType, DetailedDeploymentCredentials } from \"../api.js\";\n\nconst DEFAULT_STARTUP_TIMEOUT_SECS = 30;\n\nasync function parseStartupTimeoutSecs(ctx: Context): Promise<number> {\n const raw = process.env.CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS;\n if (raw === undefined) {\n return DEFAULT_STARTUP_TIMEOUT_SECS;\n }\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Invalid CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS=${JSON.stringify(raw)}: expected a positive number.`,\n });\n }\n return parsed;\n}\n\nexport async function runLocalBackend(\n ctx: Context,\n args: {\n ports: {\n cloud: number;\n site: number;\n };\n deploymentKind: LocalDeploymentKind;\n deploymentName: string;\n binaryPath: string;\n instanceSecret: string;\n isLatestVersion: boolean;\n },\n): Promise<{\n cleanupHandle: string;\n}> {\n const { ports } = args;\n const deploymentDir = deploymentStateDir(\n ctx,\n args.deploymentKind,\n args.deploymentName,\n );\n ctx.fs.mkdir(deploymentDir, { recursive: true });\n const deploymentNameSha = createHash(\"sha256\")\n .update(args.deploymentName)\n .digest(\"hex\");\n const commandArgs = [\n \"--port\",\n ports.cloud.toString(),\n \"--site-proxy-port\",\n ports.site.toString(),\n \"--sentry-identifier\",\n deploymentNameSha,\n \"--instance-name\",\n args.deploymentName,\n \"--instance-secret\",\n args.instanceSecret,\n \"--local-storage\",\n path.join(deploymentDir, \"convex_local_storage\"),\n \"--beacon-tag\",\n selfHostedEventTag(args.deploymentKind),\n path.join(deploymentDir, \"convex_local_backend.sqlite3\"),\n ];\n if (args.isLatestVersion) {\n // CLI args that were added in later versions of backend go here instead of above\n // since the CLI may run older versions of backend (e.g. when upgrading).\n if (args.deploymentKind === \"anonymous\") {\n const uuid = loadUuidForAnonymousUser(ctx);\n if (uuid !== null) {\n commandArgs.push(\n \"--beacon-fields\",\n JSON.stringify({\n override_uuid: uuid,\n }),\n );\n }\n }\n }\n\n // Check that binary works by running with --help\n try {\n const result = child_process.spawnSync(args.binaryPath, [\n ...commandArgs,\n \"--help\",\n ]);\n if (result.status === 3221225781) {\n const message =\n \"Local backend exited because shared libraries are missing. These may include libraries installed via 'Microsoft Visual C++ Redistributable for Visual Studio.'\";\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(\n \"Local backend exited with code 3221225781\",\n ),\n });\n } else if (result.status !== 0) {\n const message = `Failed to run backend binary, exit code ${result.status}, error: ${result.stderr === null ? \"null\" : result.stderr.toString()}`;\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n }\n } catch (e) {\n const message = `Failed to run backend binary: ${(e as any).toString()}`;\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n }\n const commandStr = `${args.binaryPath} ${commandArgs.join(\" \")}`;\n logVerbose(`Starting local backend: \\`${commandStr}\\``);\n const p = child_process\n .spawn(args.binaryPath, commandArgs, {\n stdio: \"ignore\",\n env: {\n ...process.env,\n SENTRY_DSN: LOCAL_BACKEND_SENTRY_DSN,\n },\n })\n .on(\"exit\", (code) => {\n const why = code === null ? \"from signal\" : `with code ${code}`;\n logVerbose(`Local backend exited ${why}, full command \\`${commandStr}\\``);\n });\n const cleanupHandle = ctx.registerCleanup(async () => {\n logVerbose(`Stopping local backend on port ${ports.cloud}`);\n p.kill(\"SIGTERM\");\n });\n\n await ensureBackendRunning(ctx, {\n cloudPort: ports.cloud,\n deploymentName: args.deploymentName,\n maxTimeSecs: await parseStartupTimeoutSecs(ctx),\n });\n\n return {\n cleanupHandle,\n };\n}\n\n/** Crash if correct local backend is not currently listening on the expected port. */\nexport async function assertLocalBackendRunning(\n ctx: Context,\n args: {\n url: string;\n deploymentName: string;\n },\n): Promise<void> {\n logVerbose(`Checking local backend at ${args.url} is running`);\n const result = await fetchLocalBackendStatus(args);\n switch (result.kind) {\n case \"running\":\n return;\n case \"different\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${result.name} is running at ${args.url}`,\n });\n case \"error\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Error response code received from local backend ${result.resp.status} ${result.resp.statusText}`,\n });\n case \"not-running\":\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Local backend isn't running. (it's not listening at ${args.url})\\nRun \\`npx convex dev\\` in another terminal first.`,\n });\n }\n}\n\n/** Wait for up to maxTimeSecs for the correct local backend to be running on the expected port. */\nexport async function ensureBackendRunning(\n ctx: Context,\n args: {\n cloudPort: number;\n deploymentName: string;\n maxTimeSecs: number;\n },\n): Promise<void> {\n logVerbose(`Ensuring backend running on port ${args.cloudPort} is running`);\n const deploymentUrl = localDeploymentUrl(args.cloudPort);\n let timeElapsedSecs = 0;\n let hasShownWaiting = false;\n while (timeElapsedSecs <= args.maxTimeSecs) {\n if (!hasShownWaiting && timeElapsedSecs > 2) {\n logMessage(\"waiting for local backend to start...\");\n hasShownWaiting = true;\n }\n try {\n const resp = await fetch(`${deploymentUrl}/instance_name`);\n if (resp.status === 200) {\n const text = await resp.text();\n if (text !== args.deploymentName) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${text} is running on selected port ${args.cloudPort}`,\n });\n } else {\n // The backend is running!\n return;\n }\n } else {\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n } catch {\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n }\n const base = `Local backend did not start on port ${args.cloudPort} within ${args.maxTimeSecs} seconds.`;\n const message =\n args.maxTimeSecs >= DEFAULT_STARTUP_TIMEOUT_SECS\n ? `${base} If your local database is large, increase the timeout by setting CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS (e.g. CONVEX_LOCAL_BACKEND_STARTUP_TIMEOUT_SECS=120).`\n : base;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: message,\n errForSentry: new LocalDeploymentError(message),\n });\n}\n\nexport async function ensureBackendStopped(\n ctx: Context,\n args: {\n ports: {\n cloud: number;\n site?: number;\n };\n maxTimeSecs: number;\n deploymentName: string;\n // Whether to allow a deployment with a different name to run on this port\n allowOtherDeployments: boolean;\n },\n) {\n logVerbose(`Ensuring backend running on port ${args.ports.cloud} is stopped`);\n let timeElapsedSecs = 0;\n while (timeElapsedSecs < args.maxTimeSecs) {\n const cloudPort = await detect(args.ports.cloud);\n const sitePort =\n args.ports.site === undefined ? undefined : await detect(args.ports.site);\n // Both ports are free\n if (cloudPort === args.ports.cloud && sitePort === args.ports.site) {\n return;\n }\n try {\n const instanceNameResp = await fetch(\n `${localDeploymentUrl(args.ports.cloud)}/instance_name`,\n );\n if (instanceNameResp.ok) {\n const instanceName = await instanceNameResp.text();\n if (instanceName !== args.deploymentName) {\n if (args.allowOtherDeployments) {\n return;\n }\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A different local backend ${instanceName} is running on selected port ${args.ports.cloud}`,\n });\n }\n }\n } catch (error: any) {\n logVerbose(`Error checking if backend is running: ${error.message}`);\n // Backend is probably not running\n continue;\n }\n await new Promise((resolve) => setTimeout(resolve, 500));\n timeElapsedSecs += 0.5;\n }\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `A local backend is still running on port ${args.ports.cloud}. Please stop it and run this command again.`,\n });\n}\n\nexport function localDeploymentUrl(cloudPort: number): string {\n return `http://127.0.0.1:${cloudPort}`;\n}\n\nexport function selfHostedEventTag(\n deploymentKind: LocalDeploymentKind,\n): string {\n return deploymentKind === \"local\" ? \"cli-local-dev\" : \"cli-anonymous-dev\";\n}\n\ntype LocalBackendStatus =\n | { kind: \"running\" }\n | { kind: \"error\"; resp: Response }\n | { kind: \"different\"; name: string }\n | { kind: \"not-running\" };\n\nexport async function fetchLocalBackendStatus(args: {\n url: string;\n deploymentName: string;\n}): Promise<LocalBackendStatus> {\n logVerbose(`Checking local backend at ${args.url} is running`);\n try {\n const resp = await fetch(`${args.url}/instance_name`);\n if (resp.status === 200) {\n const text = await resp.text();\n if (text !== args.deploymentName) {\n return { kind: \"different\", name: text };\n } else {\n return { kind: \"running\" };\n }\n } else {\n return { kind: \"error\", resp };\n }\n } catch {\n return { kind: \"not-running\" };\n }\n}\n\n/** Returns true if the correct local backend is listening. */\nexport async function isLocalBackendRunning(\n url: string,\n deploymentName: string,\n): Promise<boolean> {\n return (\n \"running\" === (await fetchLocalBackendStatus({ url, deploymentName })).kind\n );\n}\n\nexport function shouldUseLocalDeployment(deploymentType: DeploymentType) {\n return deploymentType === \"local\" || deploymentType === \"anonymous\";\n}\n\ninterface WithRunningBackendArgs {\n ctx: Context;\n deployment: {\n deploymentUrl: string;\n deploymentFields: DetailedDeploymentCredentials[\"deploymentFields\"];\n };\n action: () => Promise<void>;\n}\n\n/**\n * If the deployment is a local deployment and not already running, start it\n * for the duration of the action, then stop it.\n */\nexport async function withRunningBackend({\n ctx,\n deployment,\n action,\n}: WithRunningBackendArgs) {\n let cleanup: (() => Promise<void>) | null = null;\n\n if (\n deployment.deploymentFields &&\n shouldUseLocalDeployment(deployment.deploymentFields.deploymentType)\n ) {\n const isRunning = await isLocalBackendRunning(\n deployment.deploymentUrl,\n deployment.deploymentFields.deploymentName,\n );\n if (!isRunning) {\n ({ cleanup } = await startEphemeralLocalBackend(ctx, {\n deploymentType: deployment.deploymentFields.deploymentType,\n deploymentName: deployment.deploymentFields.deploymentName,\n }));\n }\n }\n\n try {\n await action();\n } finally {\n await cleanup?.();\n }\n}\n\n/**\n * Start a local backend for a one-off command using saved deployment config.\n * Returns a cleanup function that stops the backend.\n */\nasync function startEphemeralLocalBackend(\n ctx: Context,\n args: {\n deploymentType: string;\n deploymentName: string;\n },\n): Promise<{ cleanup: () => Promise<void> }> {\n const deploymentKind: LocalDeploymentKind =\n args.deploymentType === \"anonymous\" ? \"anonymous\" : \"local\";\n\n const config = loadDeploymentConfig(ctx, deploymentKind, args.deploymentName);\n if (config === null) {\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Local backend isn't running and no saved configuration found.\\nRun \\`npx convex dev\\` first.`,\n });\n }\n\n const { binaryPath } = await ensureBackendBinaryDownloaded(ctx, {\n kind: \"version\",\n version: config.backendVersion,\n });\n\n const instanceSecret = config.instanceSecret ?? LOCAL_BACKEND_INSTANCE_SECRET;\n\n const { cleanupHandle } = await runLocalBackend(ctx, {\n binaryPath,\n ports: config.ports,\n deploymentKind,\n deploymentName: args.deploymentName,\n instanceSecret,\n isLatestVersion: true,\n });\n\n return {\n cleanup: async () => {\n const fn = ctx.removeCleanup(cleanupHandle);\n if (fn) {\n await fn(0);\n }\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path", "child_process", "detect"]
7
7
  }
@@ -30,6 +30,7 @@ var login_exports = {};
30
30
  __export(login_exports, {
31
31
  checkAuthorization: () => checkAuthorization,
32
32
  ensureLoggedIn: () => ensureLoggedIn,
33
+ isAuthorizedHeader: () => isAuthorizedHeader,
33
34
  performLogin: () => performLogin
34
35
  });
35
36
  module.exports = __toCommonJS(login_exports);
@@ -49,11 +50,7 @@ var import_deploymentSelection = require("./deploymentSelection.js");
49
50
  import_openid_client.custom.setHttpOptionsDefaults({
50
51
  timeout: parseInt(process.env.OPENID_CLIENT_TIMEOUT || "10000")
51
52
  });
52
- async function checkAuthorization(ctx, acceptOptIns) {
53
- const header = ctx.bigBrainAuth()?.header ?? null;
54
- if (header === null) {
55
- return false;
56
- }
53
+ async function isAuthorizedHeader(ctx, header) {
57
54
  try {
58
55
  const resp = await fetch(`${import_config.provisionHost}/api/authorize`, {
59
56
  method: "HEAD",
@@ -62,15 +59,22 @@ async function checkAuthorization(ctx, acceptOptIns) {
62
59
  "Convex-Client": `npm-cli-${import_version.version}`
63
60
  }
64
61
  });
65
- if (resp.status !== 200) {
66
- return false;
67
- }
62
+ return resp.status === 200;
68
63
  } catch (e) {
69
64
  (0, import_log.logError)(
70
65
  `Unexpected error when authorizing - are you connected to the internet?`
71
66
  );
72
67
  return await (0, import_utils.logAndHandleFetchError)(ctx, e);
73
68
  }
69
+ }
70
+ async function checkAuthorization(ctx, acceptOptIns) {
71
+ const header = ctx.bigBrainAuth()?.header ?? null;
72
+ if (header === null) {
73
+ return false;
74
+ }
75
+ if (!await isAuthorizedHeader(ctx, header)) {
76
+ return false;
77
+ }
74
78
  const shouldContinue = await optins(ctx, acceptOptIns);
75
79
  if (!shouldContinue) {
76
80
  return await ctx.crash({
@@ -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 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 const clientId = overrideAuthClient ?? \"HFtA247jp9iNs08NTLIB7JsNPMmRIyfi\";\n let accessToken: string;\n\n if (overrideAccessToken) {\n // Access token was supplied directly.\n accessToken = overrideAccessToken;\n } else if (overrideAuthUsername && overrideAuthPassword) {\n // Username/Password auth\n accessToken = await performPasswordAuthentication(\n ctx,\n clientId,\n overrideAuthUsername,\n overrideAuthPassword,\n );\n } else if (\n loginFlow === \"paste\" ||\n (loginFlow === \"auto\" && isWebContainer())\n ) {\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 // Device authorization flow. Contact OIDC issuer.\n let authIssuer;\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 authIssuer = undefined;\n }\n if (authIssuer) {\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 accessToken = await performDeviceAuthorization(\n ctx,\n authClient,\n open ?? true,\n vercel,\n vercelOverride,\n );\n } else {\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 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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA2C;AAC3C,mBAOO;AACP,kBAAiB;AACjB,mBAA4B;AAC5B,oBAA8B;AAC9B,qBAAwB;AAExB,iBASO;AACP,IAAAA,wBAAuB;AACvB,gBAAyB;AACzB,2BAAyB;AACzB,qBAA0C;AAC1C,0BAIO;AACP,iCAA6C;AAG7C,4BAAO,uBAAuB;AAAA,EAC5B,SAAS,SAAS,QAAQ,IAAI,yBAAyB,OAAO;AAChE,CAAC;AAED,eAAsB,mBACpB,KACA,cACkB;AAClB,QAAM,SAAS,IAAI,aAAa,GAAG,UAAU;AAC7C,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,GAAG,2BAAa,kBAAkB;AAAA,MACzD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe;AAAA,QACf,iBAAiB,WAAW,sBAAO;AAAA,MACrC;AAAA,IACF,CAAC;AAID,QAAI,KAAK,WAAW,KAAK;AACvB,aAAO;AAAA,IACT;AAAA,EACF,SAAS,GAAQ;AAEf;AAAA,MACE;AAAA,IACF;AACA,WAAO,UAAM,qCAAuB,KAAK,CAAC;AAAA,EAC5C;AAGA,QAAM,iBAAiB,MAAM,OAAO,KAAK,YAAY;AACrD,MAAI,CAAC,gBAAgB;AACnB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,eAAe,2BACb,KACA,YACA,YACA,QACA,gBACiB;AA8BjB,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,WAAW,oBAAoB;AAAA,EAChD,QAAQ;AAEN,eAAO,6BAAa,KAAK;AAAA,MACvB,SACE;AAAA,IACJ,CAAC;AAAA,EACH;AAIA,QAAM,EAAE,2BAA2B,WAAW,WAAW,IAAI;AAG7D,QAAM,YAAY,SACd,uCAAuC,kBAAkB,QAAQ,QAAQ,yBAAyB,KAClG;AAEJ;AAAA,IACE,SAAS,SAAS;AAAA,qDAEd,aAAa,OAAO,IAChB,GAAG,aAAa,EAAE,aAClB,GAAG,UAAU,UACnB,KAAK,SAAS;AAAA,EAClB;AACA,MAAI,YAAY;AACd,iBAAa,UAAM,4BAAY,KAAK;AAAA,MAClC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,YAAY;AACd,gCAAY,WAAW,SAAS;AAAA,CAAiC;AACjE,QAAI;AACF,YAAM,IAAI,UAAM,YAAAC,SAAK,SAAS;AAC9B,QAAE,KAAK,SAAS,MAAM;AACpB,sCAAc,iBAAiB,SAAS,6BAA6B;AAAA,MACvE,CAAC;AACD,oCAAc,iCAAiC;AAAA,IACjD,QAAQ;AACN,+BAAS,yBAAY,IAAI,yBAAyB,CAAC;AACnD,oCAAc,iBAAiB,SAAS,6BAA6B;AAAA,IACvE;AAAA,EACF,OAAO;AACL,gCAAY,QAAQ,SAAS,6BAA6B;AAAA,EAC5D;AAIA,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,KAAK;AACjC,QAAI,OAAO,OAAO,iBAAiB,UAAU;AAC3C,aAAO,OAAO;AAAA,IAChB,OAAO;AAGL,YAAM,MAAM,yBAAyB;AAAA,IACvC;AAAA,EACF,SAAS,KAAU;AACjB,YAAQ,IAAI,OAAO;AAAA,MACjB,KAAK;AACH,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH,KAAK;AACH,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH,SAAS;AACP,cAAM,UACJ,eAAe,4BAAO,UAClB,WAAW,IAAI,KAAK,yBAAyB,IAAI,iBAAiB,KAClE,4BAA4B,GAAG;AACrC,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,8BACb,KACA,UACA,UACA,UACiB;AACjB,MAAI,CAAC,QAAQ,IAAI,mBAAmB;AAClC,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,QAAM,UAA+C;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY;AAAA,MACZ,OAAO;AAAA,MACP;AAAA,MACA,WAAW;AAAA,MACX,eAAe,QAAQ,IAAI;AAAA,IAC7B,CAAC;AAAA,EACH;AAEA,MAAI;AACF,UAAM,WAAW,UAAM;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,OAAO,KAAK,iBAAiB,UAAU;AACzC,aAAO,KAAK;AAAA,IACd,OAAO;AAGL,YAAM,MAAM,yBAAyB;AAAA,IACvC;AAAA,EACF,SAAS,KAAU;AACjB,+BAAW,yBAAyB,GAAG,EAAE;AACzC,QAAI,IAAI,UAAU;AAChB,+BAAS,yBAAY,IAAI,GAAG,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;AAAA,IAClE;AACA,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,aACpB,KACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,IAgBI,CAAC,GACL;AACA,cAAY,aAAa;AAIzB,MAAI,aAAa,sBAAsB;AACvC,MAAI,CAAC,cAAc,QAAQ,aAAa,UAAU;AAChD,QAAI;AACF,uBAAa,+BAAS,2BAA2B,EAAE,SAAS,EAAE,KAAK;AAAA,IACrE,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,CAAC,YAAY;AACf,qBAAa,oBAAS;AAAA,EACxB;AACA,MAAI,CAAC,oBAAoB;AACvB;AAAA,MACE,yBAAY;AAAA,QACV;AAAA,MACF;AAAA,IACF;AACA,iBAAa,UAAM,6BAAa,KAAK;AAAA,MACnC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,mBAAmB;AAClC,QAAM,WAAW,sBAAsB;AACvC,MAAI;AAEJ,MAAI,qBAAqB;AAEvB,kBAAc;AAAA,EAChB,WAAW,wBAAwB,sBAAsB;AAEvD,kBAAc,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,WACE,cAAc,WACb,cAAc,cAAU,6BAAe,GACxC;AACA,kBAAc,UAAM,6BAAa,KAAK;AAAA,MACpC,SACE;AAAA,IACJ,CAAC;AAAA,EACH,OAAO;AAEL,QAAI;AACJ,QAAI;AACF,mBAAa,MAAM,6BAAO,SAAS,MAAM;AAAA,IAC3C,QAAQ;AAGN,mBAAa;AAAA,IACf;AACA,QAAI,YAAY;AACd,YAAM,aAAa,IAAI,WAAW,OAAO;AAAA,QACvC,WAAW;AAAA,QACX,4BAA4B;AAAA,QAC5B,8BAA8B;AAAA,MAChC,CAAC;AACD,oBAAc,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACAA,SAAQ;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,oBAAc,UAAM,6BAAa,KAAK;AAAA,QACpC,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,iBAAiB;AACnB,8BAAU,GAAG,WAAW,EAAE;AAC1B,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,MAAI,oBAAoB;AAAA,IACtB;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,UAAU,WAAW;AAAA,EAC/B,CAAC;AACD,QAAM,WAAW,UAAM,kCAAoB,GAAG,EAAE;AAAA,IAC9C;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,MAIE,MAAM,EAAE,MAAM,YAAY,YAAY;AAAA,IACxC;AAAA,EACF;AACA,QAAM,iBAAiB,SAAS,KAAM;AACtC,QAAM,eAAe,EAAE,aAAa,eAAe;AACnD,MAAI;AACF,cAAM,wCAAmB,KAAK,YAAY;AAC1C,UAAM,WAAO,sCAAiB;AAC9B,oCAAgB,4BAAwB,2CAAsB,IAAI,CAAC,EAAE;AAAA,EACvE,SAAS,KAAc;AACrB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,6BAAW,mDAAmD;AAC9D,YAAM,yDAA6B,KAAK,cAAc;AAEtD,6BAAW,iDAAiD,YAAY,EAAE;AAE1E,QAAM,iBAAiB,MAAM,OAAO,KAAK,gBAAgB,KAAK;AAC9D,MAAI,CAAC,gBAAgB;AACnB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ;AACV,UAAM,sBAAsB,GAAG;AAAA,EACjC;AACF;AAaA,eAAe,sBAAsB,KAA6B;AAChE,QAAMC,aAAQ,4BAAc,GAAG;AAC/B,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAMA;AAAA,MAChB,IAAI,IAAI,0BAA0B,GAAG,2BAAa,GAAG;AAAA,IACvD;AACA,QAAI,CAAC,IAAI,IAAI;AACX;AAAA,QACE,mCAAmC,IAAI,MAAM;AAAA,MAC/C;AACA;AAAA,IACF;AACA,YAAQ,MAAM,IAAI,KAAK;AAAA,EACzB,SAAS,KAAK;AACZ,+BAAW,2CAA2C,OAAO,GAAG,CAAC,EAAE;AACnE;AAAA,EACF;AACA,MAAI,MAAM,WAAW,EAAG;AAExB,aAAW,CAAC,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC3C,UAAM,cAAc,KAAK,SAAS,QAAQ,gBAAgB,EAAE;AAC5D,UAAM,UAAU,MAAM,SAAS,IAAI,IAAI,QAAQ,CAAC,IAAI,MAAM,MAAM,OAAO;AACvE,UAAM,QAAQ;AAAA,MACZ,yBAAY,KAAK,GAAG,OAAO,+BAA+B,WAAW,EAAE,IACrE,KAAK,KAAK,QAAQ;AAAA,IACtB;AACA,QAAI,KAAK,eAAe;AACtB,YAAM,KAAK,yBAAY,OAAO,KAAK,aAAa,CAAC;AAAA,IACnD;AACA,UAAM,KAAK,SAAS,WAAW,IAAI;AACnC,UAAM,OAAO,UAAM,4BAAY,KAAK;AAAA,MAClC,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,KAAM;AACX,QAAI;AACF,YAAMA;AAAA,QACJ,IAAI;AAAA,UACF,0BAA0B,KAAK,MAAM;AAAA,UACrC,GAAG,2BAAa;AAAA,QAClB;AAAA,QACA,EAAE,QAAQ,OAAO;AAAA,MACnB;AACA,sCAAgB,UAAU,WAAW,EAAE;AAAA,IACzC,SAAS,KAAK;AACZ,iCAAW,kBAAkB,WAAW,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAC5D;AAAA,EACF;AACF;AAeA,eAAe,OAAO,KAAc,cAAyC;AAC3E,QAAM,SAAS,IAAI,aAAa;AAChC,MAAI,WAAW,MAAM;AAEnB,WAAO;AAAA,EACT;AACA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEH,aAAO;AAAA,IACT,SAAS;AACP;AACA,aAAO,MAAM,IAAI,MAAM;AAAA,QACrB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,cAAc,wBAAyB,OAAe,IAAI;AAAA,QAC1D,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,OAAO,UAAM,0BAAY;AAAA,IAC7B;AAAA,IACA,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AACD,MAAI,KAAK,eAAe,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AACA,aAAW,iBAAiB,KAAK,gBAAgB;AAC/C,UAAM,YACJ,gBACC,UAAM,4BAAY,KAAK;AAAA,MACtB,SAAS,cAAc;AAAA,IACzB,CAAC;AACH,QAAI,CAAC,WAAW;AACd,iCAAW,mDAAmD;AAC9D,aAAO,QAAQ,QAAQ,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,iBAAiB,KAAK,eAAe,IAAI,CAAC,MAAqB,EAAE,KAAK;AAC5E,QAAM,OAAyB,EAAE,eAAe;AAChD,YAAM,0BAAY;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,eACpB,KACA,SAOA;AACA,QAAM,aAAa,MAAM,mBAAmB,KAAK,KAAK;AACtD,MAAI,CAAC,YAAY;AACf,QAAI,SAAS,SAAS;AACpB,iCAAW,QAAQ,OAAO;AAAA,IAC5B;AACA,UAAM,aAAa,KAAK;AAAA,MACtB,cAAc;AAAA,MACd,iBAAiB,SAAS;AAAA,MAC1B,oBAAoB,SAAS;AAAA,MAC7B,sBAAsB,SAAS;AAAA,MAC/B,sBAAsB,SAAS;AAAA,IACjC,CAAC;AAAA,EACH;AACF;",
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\n/**\n * Whether Big Brain accepts this credential. Takes the header explicitly so\n * callers can check a credential other than the one `ctx` resolved to.\n */\nexport async function isAuthorizedHeader(\n ctx: Context,\n header: string,\n): Promise<boolean> {\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 return resp.status === 200;\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\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 if (!(await isAuthorizedHeader(ctx, header))) {\n return false;\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 const clientId = overrideAuthClient ?? \"HFtA247jp9iNs08NTLIB7JsNPMmRIyfi\";\n let accessToken: string;\n\n if (overrideAccessToken) {\n // Access token was supplied directly.\n accessToken = overrideAccessToken;\n } else if (overrideAuthUsername && overrideAuthPassword) {\n // Username/Password auth\n accessToken = await performPasswordAuthentication(\n ctx,\n clientId,\n overrideAuthUsername,\n overrideAuthPassword,\n );\n } else if (\n loginFlow === \"paste\" ||\n (loginFlow === \"auto\" && isWebContainer())\n ) {\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 // Device authorization flow. Contact OIDC issuer.\n let authIssuer;\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 authIssuer = undefined;\n }\n if (authIssuer) {\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 accessToken = await performDeviceAuthorization(\n ctx,\n authClient,\n open ?? true,\n vercel,\n vercelOverride,\n );\n } else {\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 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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA2C;AAC3C,mBAOO;AACP,kBAAiB;AACjB,mBAA4B;AAC5B,oBAA8B;AAC9B,qBAAwB;AAExB,iBASO;AACP,IAAAA,wBAAuB;AACvB,gBAAyB;AACzB,2BAAyB;AACzB,qBAA0C;AAC1C,0BAIO;AACP,iCAA6C;AAG7C,4BAAO,uBAAuB;AAAA,EAC5B,SAAS,SAAS,QAAQ,IAAI,yBAAyB,OAAO;AAChE,CAAC;AAMD,eAAsB,mBACpB,KACA,QACkB;AAClB,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,GAAG,2BAAa,kBAAkB;AAAA,MACzD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe;AAAA,QACf,iBAAiB,WAAW,sBAAO;AAAA,MACrC;AAAA,IACF,CAAC;AAID,WAAO,KAAK,WAAW;AAAA,EACzB,SAAS,GAAQ;AAEf;AAAA,MACE;AAAA,IACF;AACA,WAAO,UAAM,qCAAuB,KAAK,CAAC;AAAA,EAC5C;AACF;AAEA,eAAsB,mBACpB,KACA,cACkB;AAClB,QAAM,SAAS,IAAI,aAAa,GAAG,UAAU;AAC7C,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,EACT;AACA,MAAI,CAAE,MAAM,mBAAmB,KAAK,MAAM,GAAI;AAC5C,WAAO;AAAA,EACT;AAGA,QAAM,iBAAiB,MAAM,OAAO,KAAK,YAAY;AACrD,MAAI,CAAC,gBAAgB;AACnB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,eAAe,2BACb,KACA,YACA,YACA,QACA,gBACiB;AA8BjB,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,WAAW,oBAAoB;AAAA,EAChD,QAAQ;AAEN,eAAO,6BAAa,KAAK;AAAA,MACvB,SACE;AAAA,IACJ,CAAC;AAAA,EACH;AAIA,QAAM,EAAE,2BAA2B,WAAW,WAAW,IAAI;AAG7D,QAAM,YAAY,SACd,uCAAuC,kBAAkB,QAAQ,QAAQ,yBAAyB,KAClG;AAEJ;AAAA,IACE,SAAS,SAAS;AAAA,qDAEd,aAAa,OAAO,IAChB,GAAG,aAAa,EAAE,aAClB,GAAG,UAAU,UACnB,KAAK,SAAS;AAAA,EAClB;AACA,MAAI,YAAY;AACd,iBAAa,UAAM,4BAAY,KAAK;AAAA,MAClC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,YAAY;AACd,gCAAY,WAAW,SAAS;AAAA,CAAiC;AACjE,QAAI;AACF,YAAM,IAAI,UAAM,YAAAC,SAAK,SAAS;AAC9B,QAAE,KAAK,SAAS,MAAM;AACpB,sCAAc,iBAAiB,SAAS,6BAA6B;AAAA,MACvE,CAAC;AACD,oCAAc,iCAAiC;AAAA,IACjD,QAAQ;AACN,+BAAS,yBAAY,IAAI,yBAAyB,CAAC;AACnD,oCAAc,iBAAiB,SAAS,6BAA6B;AAAA,IACvE;AAAA,EACF,OAAO;AACL,gCAAY,QAAQ,SAAS,6BAA6B;AAAA,EAC5D;AAIA,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,KAAK;AACjC,QAAI,OAAO,OAAO,iBAAiB,UAAU;AAC3C,aAAO,OAAO;AAAA,IAChB,OAAO;AAGL,YAAM,MAAM,yBAAyB;AAAA,IACvC;AAAA,EACF,SAAS,KAAU;AACjB,YAAQ,IAAI,OAAO;AAAA,MACjB,KAAK;AACH,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH,KAAK;AACH,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH,SAAS;AACP,cAAM,UACJ,eAAe,4BAAO,UAClB,WAAW,IAAI,KAAK,yBAAyB,IAAI,iBAAiB,KAClE,4BAA4B,GAAG;AACrC,eAAO,MAAM,IAAI,MAAM;AAAA,UACrB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,8BACb,KACA,UACA,UACA,UACiB;AACjB,MAAI,CAAC,QAAQ,IAAI,mBAAmB;AAClC,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,QAAM,UAA+C;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY;AAAA,MACZ,OAAO;AAAA,MACP;AAAA,MACA,WAAW;AAAA,MACX,eAAe,QAAQ,IAAI;AAAA,IAC7B,CAAC;AAAA,EACH;AAEA,MAAI;AACF,UAAM,WAAW,UAAM;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,OAAO,KAAK,iBAAiB,UAAU;AACzC,aAAO,KAAK;AAAA,IACd,OAAO;AAGL,YAAM,MAAM,yBAAyB;AAAA,IACvC;AAAA,EACF,SAAS,KAAU;AACjB,+BAAW,yBAAyB,GAAG,EAAE;AACzC,QAAI,IAAI,UAAU;AAChB,+BAAS,yBAAY,IAAI,GAAG,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;AAAA,IAClE;AACA,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,aACpB,KACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,IAgBI,CAAC,GACL;AACA,cAAY,aAAa;AAIzB,MAAI,aAAa,sBAAsB;AACvC,MAAI,CAAC,cAAc,QAAQ,aAAa,UAAU;AAChD,QAAI;AACF,uBAAa,+BAAS,2BAA2B,EAAE,SAAS,EAAE,KAAK;AAAA,IACrE,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,CAAC,YAAY;AACf,qBAAa,oBAAS;AAAA,EACxB;AACA,MAAI,CAAC,oBAAoB;AACvB;AAAA,MACE,yBAAY;AAAA,QACV;AAAA,MACF;AAAA,IACF;AACA,iBAAa,UAAM,6BAAa,KAAK;AAAA,MACnC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,mBAAmB;AAClC,QAAM,WAAW,sBAAsB;AACvC,MAAI;AAEJ,MAAI,qBAAqB;AAEvB,kBAAc;AAAA,EAChB,WAAW,wBAAwB,sBAAsB;AAEvD,kBAAc,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,WACE,cAAc,WACb,cAAc,cAAU,6BAAe,GACxC;AACA,kBAAc,UAAM,6BAAa,KAAK;AAAA,MACpC,SACE;AAAA,IACJ,CAAC;AAAA,EACH,OAAO;AAEL,QAAI;AACJ,QAAI;AACF,mBAAa,MAAM,6BAAO,SAAS,MAAM;AAAA,IAC3C,QAAQ;AAGN,mBAAa;AAAA,IACf;AACA,QAAI,YAAY;AACd,YAAM,aAAa,IAAI,WAAW,OAAO;AAAA,QACvC,WAAW;AAAA,QACX,4BAA4B;AAAA,QAC5B,8BAA8B;AAAA,MAChC,CAAC;AACD,oBAAc,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACAA,SAAQ;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,oBAAc,UAAM,6BAAa,KAAK;AAAA,QACpC,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,iBAAiB;AACnB,8BAAU,GAAG,WAAW,EAAE;AAC1B,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,MAAI,oBAAoB;AAAA,IACtB;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,UAAU,WAAW;AAAA,EAC/B,CAAC;AACD,QAAM,WAAW,UAAM,kCAAoB,GAAG,EAAE;AAAA,IAC9C;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,MAIE,MAAM,EAAE,MAAM,YAAY,YAAY;AAAA,IACxC;AAAA,EACF;AACA,QAAM,iBAAiB,SAAS,KAAM;AACtC,QAAM,eAAe,EAAE,aAAa,eAAe;AACnD,MAAI;AACF,cAAM,wCAAmB,KAAK,YAAY;AAC1C,UAAM,WAAO,sCAAiB;AAC9B,oCAAgB,4BAAwB,2CAAsB,IAAI,CAAC,EAAE;AAAA,EACvE,SAAS,KAAc;AACrB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,6BAAW,mDAAmD;AAC9D,YAAM,yDAA6B,KAAK,cAAc;AAEtD,6BAAW,iDAAiD,YAAY,EAAE;AAE1E,QAAM,iBAAiB,MAAM,OAAO,KAAK,gBAAgB,KAAK;AAC9D,MAAI,CAAC,gBAAgB;AACnB,WAAO,MAAM,IAAI,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ;AACV,UAAM,sBAAsB,GAAG;AAAA,EACjC;AACF;AAaA,eAAe,sBAAsB,KAA6B;AAChE,QAAMC,aAAQ,4BAAc,GAAG;AAC/B,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAMA;AAAA,MAChB,IAAI,IAAI,0BAA0B,GAAG,2BAAa,GAAG;AAAA,IACvD;AACA,QAAI,CAAC,IAAI,IAAI;AACX;AAAA,QACE,mCAAmC,IAAI,MAAM;AAAA,MAC/C;AACA;AAAA,IACF;AACA,YAAQ,MAAM,IAAI,KAAK;AAAA,EACzB,SAAS,KAAK;AACZ,+BAAW,2CAA2C,OAAO,GAAG,CAAC,EAAE;AACnE;AAAA,EACF;AACA,MAAI,MAAM,WAAW,EAAG;AAExB,aAAW,CAAC,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC3C,UAAM,cAAc,KAAK,SAAS,QAAQ,gBAAgB,EAAE;AAC5D,UAAM,UAAU,MAAM,SAAS,IAAI,IAAI,QAAQ,CAAC,IAAI,MAAM,MAAM,OAAO;AACvE,UAAM,QAAQ;AAAA,MACZ,yBAAY,KAAK,GAAG,OAAO,+BAA+B,WAAW,EAAE,IACrE,KAAK,KAAK,QAAQ;AAAA,IACtB;AACA,QAAI,KAAK,eAAe;AACtB,YAAM,KAAK,yBAAY,OAAO,KAAK,aAAa,CAAC;AAAA,IACnD;AACA,UAAM,KAAK,SAAS,WAAW,IAAI;AACnC,UAAM,OAAO,UAAM,4BAAY,KAAK;AAAA,MAClC,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,KAAM;AACX,QAAI;AACF,YAAMA;AAAA,QACJ,IAAI;AAAA,UACF,0BAA0B,KAAK,MAAM;AAAA,UACrC,GAAG,2BAAa;AAAA,QAClB;AAAA,QACA,EAAE,QAAQ,OAAO;AAAA,MACnB;AACA,sCAAgB,UAAU,WAAW,EAAE;AAAA,IACzC,SAAS,KAAK;AACZ,iCAAW,kBAAkB,WAAW,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAC5D;AAAA,EACF;AACF;AAeA,eAAe,OAAO,KAAc,cAAyC;AAC3E,QAAM,SAAS,IAAI,aAAa;AAChC,MAAI,WAAW,MAAM;AAEnB,WAAO;AAAA,EACT;AACA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEH,aAAO;AAAA,IACT,SAAS;AACP;AACA,aAAO,MAAM,IAAI,MAAM;AAAA,QACrB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,cAAc,wBAAyB,OAAe,IAAI;AAAA,QAC1D,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,OAAO,UAAM,0BAAY;AAAA,IAC7B;AAAA,IACA,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AACD,MAAI,KAAK,eAAe,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AACA,aAAW,iBAAiB,KAAK,gBAAgB;AAC/C,UAAM,YACJ,gBACC,UAAM,4BAAY,KAAK;AAAA,MACtB,SAAS,cAAc;AAAA,IACzB,CAAC;AACH,QAAI,CAAC,WAAW;AACd,iCAAW,mDAAmD;AAC9D,aAAO,QAAQ,QAAQ,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,iBAAiB,KAAK,eAAe,IAAI,CAAC,MAAqB,EAAE,KAAK;AAC5E,QAAM,OAAyB,EAAE,eAAe;AAChD,YAAM,0BAAY;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,eACpB,KACA,SAOA;AACA,QAAM,aAAa,MAAM,mBAAmB,KAAK,KAAK;AACtD,MAAI,CAAC,YAAY;AACf,QAAI,SAAS,SAAS;AACpB,iCAAW,QAAQ,OAAO;AAAA,IAC5B;AACA,UAAM,aAAa,KAAK;AAAA,MACtB,cAAc;AAAA,MACd,iBAAiB,SAAS;AAAA,MAC1B,oBAAoB,SAAS;AAAA,MAC7B,sBAAsB,SAAS;AAAA,MAC/B,sBAAsB,SAAS;AAAA,IACjC,CAAC;AAAA,EACH;AACF;",
6
6
  "names": ["import_openid_client", "open", "fetch"]
7
7
  }
@@ -28,6 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var sentry_exports = {};
30
30
  __export(sentry_exports, {
31
+ LOCAL_BACKEND_SENTRY_DSN: () => LOCAL_BACKEND_SENTRY_DSN,
31
32
  SENTRY_DSN: () => SENTRY_DSN,
32
33
  initSentry: () => initSentry
33
34
  });
@@ -38,6 +39,7 @@ var Sentry = __toESM(require("@sentry/node"), 1);
38
39
  var import__ = require("../../../index.js");
39
40
  var import_util = require("util");
40
41
  const SENTRY_DSN = "https://f9fa0306e3d540079cf40ce8c2ad9644@o1192621.ingest.sentry.io/6390839";
42
+ const LOCAL_BACKEND_SENTRY_DSN = "https://1c77542933b4002e48934a351c84dd38@o1192621.ingest.us.sentry.io/4511826465587200";
41
43
  function initSentry() {
42
44
  if ((!process.env.CI || process.env.VERCEL === "1") && import_config.provisionHost === import_config.productionProvisionHost) {
43
45
  Sentry.init({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/lib/utils/sentry.ts"],
4
- "sourcesContent": ["import \"@sentry/tracing\";\nimport { productionProvisionHost, provisionHost } from \"../config.js\";\nimport * as Sentry from \"@sentry/node\";\nimport { version } from \"../../../index.js\";\nimport { stripVTControlCharacters } from \"util\";\n\nexport const SENTRY_DSN =\n \"https://f9fa0306e3d540079cf40ce8c2ad9644@o1192621.ingest.sentry.io/6390839\";\n\nexport function initSentry() {\n if (\n (!process.env.CI || process.env.VERCEL === \"1\") &&\n provisionHost === productionProvisionHost\n ) {\n Sentry.init({\n dsn: SENTRY_DSN,\n release: \"cli@\" + version,\n tracesSampleRate: 0.2,\n beforeBreadcrumb: (breadcrumb) => {\n // Strip ANSI color codes from log lines that are sent as breadcrumbs.\n if (breadcrumb.message) {\n breadcrumb.message = stripVTControlCharacters(breadcrumb.message);\n }\n return breadcrumb;\n },\n });\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAO;AACP,oBAAuD;AACvD,aAAwB;AACxB,eAAwB;AACxB,kBAAyC;AAElC,MAAM,aACX;AAEK,SAAS,aAAa;AAC3B,OACG,CAAC,QAAQ,IAAI,MAAM,QAAQ,IAAI,WAAW,QAC3C,gCAAkB,uCAClB;AACA,WAAO,KAAK;AAAA,MACV,KAAK;AAAA,MACL,SAAS,SAAS;AAAA,MAClB,kBAAkB;AAAA,MAClB,kBAAkB,CAAC,eAAe;AAEhC,YAAI,WAAW,SAAS;AACtB,qBAAW,cAAU,sCAAyB,WAAW,OAAO;AAAA,QAClE;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
4
+ "sourcesContent": ["import \"@sentry/tracing\";\nimport { productionProvisionHost, provisionHost } from \"../config.js\";\nimport * as Sentry from \"@sentry/node\";\nimport { version } from \"../../../index.js\";\nimport { stripVTControlCharacters } from \"util\";\n\nexport const SENTRY_DSN =\n \"https://f9fa0306e3d540079cf40ce8c2ad9644@o1192621.ingest.sentry.io/6390839\";\n\nexport const LOCAL_BACKEND_SENTRY_DSN =\n \"https://1c77542933b4002e48934a351c84dd38@o1192621.ingest.us.sentry.io/4511826465587200\";\n\nexport function initSentry() {\n if (\n (!process.env.CI || process.env.VERCEL === \"1\") &&\n provisionHost === productionProvisionHost\n ) {\n Sentry.init({\n dsn: SENTRY_DSN,\n release: \"cli@\" + version,\n tracesSampleRate: 0.2,\n beforeBreadcrumb: (breadcrumb) => {\n // Strip ANSI color codes from log lines that are sent as breadcrumbs.\n if (breadcrumb.message) {\n breadcrumb.message = stripVTControlCharacters(breadcrumb.message);\n }\n return breadcrumb;\n },\n });\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAO;AACP,oBAAuD;AACvD,aAAwB;AACxB,eAAwB;AACxB,kBAAyC;AAElC,MAAM,aACX;AAEK,MAAM,2BACX;AAEK,SAAS,aAAa;AAC3B,OACG,CAAC,QAAQ,IAAI,MAAM,QAAQ,IAAI,WAAW,QAC3C,gCAAkB,uCAClB;AACA,WAAO,KAAK;AAAA,MACV,KAAK;AAAA,MACL,SAAS,SAAS;AAAA,MAClB,kBAAkB;AAAA,MAClB,kBAAkB,CAAC,eAAe;AAEhC,YAAI,WAAW,SAAS;AACtB,qBAAW,cAAU,sCAAyB,WAAW,OAAO;AAAA,QAClE;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
6
6
  "names": []
7
7
  }