@estifanos-sh/convex-auth 0.0.1-preview.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 (387) hide show
  1. package/README.md +52 -0
  2. package/dist/_generated/component.d.ts +2981 -0
  3. package/dist/bin.js +7194 -0
  4. package/dist/browser/index.d.ts +22 -0
  5. package/dist/browser/index.js +61 -0
  6. package/dist/browser/locks.js +20 -0
  7. package/dist/browser/navigation.js +14 -0
  8. package/dist/browser/runtime.js +90 -0
  9. package/dist/browser/webauthn.js +99 -0
  10. package/dist/client/core/types.d.ts +615 -0
  11. package/dist/client/core/types.js +23 -0
  12. package/dist/client/errors.js +30 -0
  13. package/dist/client/factors/device.js +100 -0
  14. package/dist/client/factors/totp.js +111 -0
  15. package/dist/client/factors/webauthn.js +69 -0
  16. package/dist/client/index.d.ts +60 -0
  17. package/dist/client/index.js +976 -0
  18. package/dist/client/runtime/invite.js +50 -0
  19. package/dist/client/runtime/mutex.js +25 -0
  20. package/dist/client/runtime/proxy.js +75 -0
  21. package/dist/client/runtime/storage.js +65 -0
  22. package/dist/component/_generated/api.js +26 -0
  23. package/dist/component/_generated/component.d.ts +2981 -0
  24. package/dist/component/_generated/component.js +1 -0
  25. package/dist/component/_generated/dataModel.js +1 -0
  26. package/dist/component/_generated/server.js +74 -0
  27. package/dist/component/account.js +197 -0
  28. package/dist/component/connection/audit.js +152 -0
  29. package/dist/component/connection/cache.js +205 -0
  30. package/dist/component/connection/domain/verification.js +63 -0
  31. package/dist/component/connection/domain.js +108 -0
  32. package/dist/component/connection/saml/assertion.js +41 -0
  33. package/dist/component/connection/saml/request.js +61 -0
  34. package/dist/component/connection/scim/config.js +55 -0
  35. package/dist/component/connection/scim/identity.js +162 -0
  36. package/dist/component/connection/secret.js +65 -0
  37. package/dist/component/connection/webhook/delivery.js +396 -0
  38. package/dist/component/connection/webhook/endpoint.js +77 -0
  39. package/dist/component/connection.js +204 -0
  40. package/dist/component/convex.config.d.ts +7 -0
  41. package/dist/component/convex.config.js +15 -0
  42. package/dist/component/crons.js +27 -0
  43. package/dist/component/event.js +341 -0
  44. package/dist/component/factor/device.js +141 -0
  45. package/dist/component/factor/passkey.js +385 -0
  46. package/dist/component/factor/totp.js +253 -0
  47. package/dist/component/functions.js +3 -0
  48. package/dist/component/group/active.js +63 -0
  49. package/dist/component/group/invite.js +300 -0
  50. package/dist/component/group/member.js +188 -0
  51. package/dist/component/group.js +431 -0
  52. package/dist/component/http.js +9 -0
  53. package/dist/component/index.d.ts +5 -0
  54. package/dist/component/index.js +3 -0
  55. package/dist/component/limits.js +103 -0
  56. package/dist/component/maintenance.js +205 -0
  57. package/dist/component/migrations.js +277 -0
  58. package/dist/component/model.d.ts +384 -0
  59. package/dist/component/model.js +709 -0
  60. package/dist/component/modules.js +53 -0
  61. package/dist/component/oauth/client.js +196 -0
  62. package/dist/component/oauth/code.js +97 -0
  63. package/dist/component/oauth/refresh.js +230 -0
  64. package/dist/component/schema.d.ts +1530 -0
  65. package/dist/component/schema.js +401 -0
  66. package/dist/component/session.js +134 -0
  67. package/dist/component/token/pkce.js +121 -0
  68. package/dist/component/token/refresh.js +189 -0
  69. package/dist/component/token/verification.js +155 -0
  70. package/dist/component/user/email.js +147 -0
  71. package/dist/component/user/key.js +273 -0
  72. package/dist/component/user.js +173 -0
  73. package/dist/core/index.d.ts +531 -0
  74. package/dist/core/index.js +81 -0
  75. package/dist/expo/index.d.ts +43 -0
  76. package/dist/expo/index.js +131 -0
  77. package/dist/expo/webauthn.js +88 -0
  78. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/NoopLogger.d.ts +2 -0
  79. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/api/logs.d.ts +3 -0
  80. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/index.d.ts +7 -0
  81. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/types/AnyValue.d.ts +21 -0
  82. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/types/LogRecord.d.ts +36 -0
  83. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/types/Logger.d.ts +1 -0
  84. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/types/LoggerOptions.d.ts +1 -0
  85. package/dist/node_modules/.pnpm/@opentelemetry_api-logs@0.214.0/node_modules/@opentelemetry/api-logs/build/src/types/LoggerProvider.d.ts +2 -0
  86. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/baggage/propagation/W3CBaggagePropagator.d.ts +1 -0
  87. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/baggage/utils.d.ts +1 -0
  88. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/common/attributes.d.ts +1 -0
  89. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/common/global-error-handler.d.ts +2 -0
  90. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/common/logging-error-handler.d.ts +1 -0
  91. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/common/time.d.ts +1 -0
  92. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/common/types.d.ts +16 -0
  93. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/index.d.ts +13 -0
  94. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/propagation/composite.d.ts +1 -0
  95. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/trace/TraceState.d.ts +1 -0
  96. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/trace/W3CTraceContextPropagator.d.ts +1 -0
  97. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/trace/rpc-metadata.d.ts +1 -0
  98. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/trace/suppress-tracing.d.ts +1 -0
  99. package/dist/node_modules/.pnpm/@opentelemetry_core@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/core/build/src/utils/configuration.d.ts +1 -0
  100. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/LogRecordProcessor.d.ts +24 -0
  101. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/LoggerProvider.d.ts +2 -0
  102. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/config/LoggerConfigurators.d.ts +1 -0
  103. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.d.ts +4 -0
  104. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/ConsoleLogRecordExporter.d.ts +3 -0
  105. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/InMemoryLogRecordExporter.d.ts +3 -0
  106. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/LogRecordExporter.d.ts +2 -0
  107. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/ReadableLogRecord.d.ts +4 -0
  108. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/SdkLogRecord.d.ts +71 -0
  109. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/SimpleLogRecordProcessor.d.ts +3 -0
  110. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/index.d.ts +11 -0
  111. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/platform/index.d.ts +1 -0
  112. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/platform/node/export/BatchLogRecordProcessor.d.ts +2 -0
  113. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/platform/node/index.d.ts +1 -0
  114. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/types.d.ts +4 -0
  115. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/InstrumentDescriptor.d.ts +3 -0
  116. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/MeterProvider.d.ts +4 -0
  117. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/Drop.d.ts +4 -0
  118. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/ExponentialHistogram.d.ts +5 -0
  119. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/Histogram.d.ts +5 -0
  120. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/LastValue.d.ts +5 -0
  121. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/Sum.d.ts +5 -0
  122. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/index.d.ts +6 -0
  123. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/aggregator/types.d.ts +53 -0
  124. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/AggregationSelector.d.ts +16 -0
  125. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/AggregationTemporality.d.ts +11 -0
  126. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/CardinalitySelector.d.ts +10 -0
  127. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/ConsoleMetricExporter.d.ts +4 -0
  128. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/InMemoryMetricExporter.d.ts +3 -0
  129. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricData.d.ts +148 -0
  130. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricExporter.d.ts +3 -0
  131. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricProducer.d.ts +27 -0
  132. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricReader.d.ts +138 -0
  133. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/PeriodicExportingMetricReader.d.ts +3 -0
  134. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/index.d.ts +15 -0
  135. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/types.d.ts +10 -0
  136. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/utils.d.ts +2 -0
  137. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/view/Aggregation.d.ts +4 -0
  138. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/view/AggregationOption.d.ts +41 -0
  139. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/view/AttributesProcessor.d.ts +1 -0
  140. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/view/InstrumentSelector.d.ts +1 -0
  141. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/view/View.d.ts +5 -0
  142. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/BasicTracerProvider.d.ts +2 -0
  143. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/IdGenerator.d.ts +11 -0
  144. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/Sampler.d.ts +74 -0
  145. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/Span.d.ts +17 -0
  146. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/SpanProcessor.d.ts +43 -0
  147. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/TimedEvent.d.ts +19 -0
  148. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/BatchSpanProcessorBase.d.ts +6 -0
  149. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ConsoleSpanExporter.d.ts +3 -0
  150. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/InMemorySpanExporter.d.ts +3 -0
  151. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/NoopSpanProcessor.d.ts +4 -0
  152. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ReadableSpan.d.ts +29 -0
  153. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/SimpleSpanProcessor.d.ts +5 -0
  154. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/SpanExporter.d.ts +2 -0
  155. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/index.d.ts +18 -0
  156. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/platform/index.d.ts +1 -0
  157. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/platform/node/export/BatchSpanProcessor.d.ts +2 -0
  158. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/platform/node/index.d.ts +1 -0
  159. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/sampler/AlwaysOffSampler.d.ts +1 -0
  160. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/sampler/AlwaysOnSampler.d.ts +1 -0
  161. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/sampler/ParentBasedSampler.d.ts +2 -0
  162. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/sampler/TraceIdRatioBasedSampler.d.ts +1 -0
  163. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/types.d.ts +66 -0
  164. package/dist/otel.d.ts +73 -0
  165. package/dist/otel.js +82 -0
  166. package/dist/permissions/index.d.ts +81 -0
  167. package/dist/permissions/index.js +18 -0
  168. package/dist/providers/anonymous.d.ts +35 -0
  169. package/dist/providers/anonymous.js +40 -0
  170. package/dist/providers/apple.d.ts +61 -0
  171. package/dist/providers/apple.js +57 -0
  172. package/dist/providers/connection.d.ts +30 -0
  173. package/dist/providers/connection.js +33 -0
  174. package/dist/providers/credentials.d.ts +78 -0
  175. package/dist/providers/credentials.js +31 -0
  176. package/dist/providers/custom.d.ts +96 -0
  177. package/dist/providers/custom.js +108 -0
  178. package/dist/providers/device.d.ts +33 -0
  179. package/dist/providers/device.js +30 -0
  180. package/dist/providers/email.d.ts +45 -0
  181. package/dist/providers/email.js +52 -0
  182. package/dist/providers/github.d.ts +56 -0
  183. package/dist/providers/github.js +79 -0
  184. package/dist/providers/google.d.ts +56 -0
  185. package/dist/providers/google.js +59 -0
  186. package/dist/providers/index.d.ts +16 -0
  187. package/dist/providers/index.js +16 -0
  188. package/dist/providers/microsoft.d.ts +59 -0
  189. package/dist/providers/microsoft.js +98 -0
  190. package/dist/providers/password.d.ts +68 -0
  191. package/dist/providers/password.js +348 -0
  192. package/dist/providers/phone.d.ts +33 -0
  193. package/dist/providers/phone.js +35 -0
  194. package/dist/providers/redirect.d.ts +1 -0
  195. package/dist/providers/redirect.js +11 -0
  196. package/dist/providers/totp.d.ts +29 -0
  197. package/dist/providers/totp.js +29 -0
  198. package/dist/providers/webauthn/attestation.d.ts +42 -0
  199. package/dist/providers/webauthn/attestation.js +167 -0
  200. package/dist/providers/webauthn.d.ts +83 -0
  201. package/dist/providers/webauthn.js +57 -0
  202. package/dist/react/index.d.ts +55 -0
  203. package/dist/react/index.js +80 -0
  204. package/dist/server/auth.d.ts +443 -0
  205. package/dist/server/auth.js +178 -0
  206. package/dist/server/cache/context.js +94 -0
  207. package/dist/server/component/api.d.ts +14 -0
  208. package/dist/server/component/api.js +13 -0
  209. package/dist/server/component/context.d.ts +16 -0
  210. package/dist/server/component/context.js +1 -0
  211. package/dist/server/component/factor/db.js +71 -0
  212. package/dist/server/config.d.ts +3 -0
  213. package/dist/server/config.js +78 -0
  214. package/dist/server/connection/config.js +101 -0
  215. package/dist/server/connection/domain.d.ts +878 -0
  216. package/dist/server/connection/domain.js +1122 -0
  217. package/dist/server/connection/group/service.d.ts +25 -0
  218. package/dist/server/connection/group/service.js +250 -0
  219. package/dist/server/connection/http.js +1485 -0
  220. package/dist/server/connection/oidc.js +366 -0
  221. package/dist/server/connection/policy/domain.js +59 -0
  222. package/dist/server/connection/policy.d.ts +1 -0
  223. package/dist/server/connection/policy.js +163 -0
  224. package/dist/server/connection/profile.js +22 -0
  225. package/dist/server/connection/provision.js +182 -0
  226. package/dist/server/connection/saml/api.js +70 -0
  227. package/dist/server/connection/saml/binding/post.js +140 -0
  228. package/dist/server/connection/saml/binding/redirect.js +139 -0
  229. package/dist/server/connection/saml/binding/shared.js +18 -0
  230. package/dist/server/connection/saml/c14n.js +224 -0
  231. package/dist/server/connection/saml/constants.js +100 -0
  232. package/dist/server/connection/saml/crypto.js +170 -0
  233. package/dist/server/connection/saml/dom/select.js +299 -0
  234. package/dist/server/connection/saml/encoding.js +93 -0
  235. package/dist/server/connection/saml/encryption.js +34 -0
  236. package/dist/server/connection/saml/entity.js +24 -0
  237. package/dist/server/connection/saml/extractor.js +408 -0
  238. package/dist/server/connection/saml/flow.js +150 -0
  239. package/dist/server/connection/saml/identity/provider.js +66 -0
  240. package/dist/server/connection/saml/index.js +5 -0
  241. package/dist/server/connection/saml/metadata.js +294 -0
  242. package/dist/server/connection/saml/service/provider.js +117 -0
  243. package/dist/server/connection/saml/signature.js +214 -0
  244. package/dist/server/connection/saml/template.js +68 -0
  245. package/dist/server/connection/saml/types.js +1 -0
  246. package/dist/server/connection/saml/validator.js +32 -0
  247. package/dist/server/connection/saml/xml/builder.js +68 -0
  248. package/dist/server/connection/saml/xmldsig.js +598 -0
  249. package/dist/server/connection/saml/xmlenc.js +162 -0
  250. package/dist/server/connection/saml.d.ts +56 -0
  251. package/dist/server/connection/saml.js +762 -0
  252. package/dist/server/connection/scim.js +115 -0
  253. package/dist/server/connection/shared.js +74 -0
  254. package/dist/server/connection/webhook.js +163 -0
  255. package/dist/server/context.d.ts +137 -0
  256. package/dist/server/context.js +108 -0
  257. package/dist/server/contract.d.ts +48 -0
  258. package/dist/server/contract.js +107 -0
  259. package/dist/server/cookies.js +90 -0
  260. package/dist/server/core.js +163 -0
  261. package/dist/server/cors.d.ts +22 -0
  262. package/dist/server/cors.js +93 -0
  263. package/dist/server/crypto.js +43 -0
  264. package/dist/server/db.js +88 -0
  265. package/dist/server/device.js +140 -0
  266. package/dist/server/domains/access.js +29 -0
  267. package/dist/server/domains/account.d.ts +16 -0
  268. package/dist/server/domains/account.js +92 -0
  269. package/dist/server/domains/factor.d.ts +28 -0
  270. package/dist/server/domains/factor.js +115 -0
  271. package/dist/server/domains/group.js +87 -0
  272. package/dist/server/domains/invite.js +76 -0
  273. package/dist/server/domains/key.js +253 -0
  274. package/dist/server/domains/member.js +149 -0
  275. package/dist/server/domains/session.js +29 -0
  276. package/dist/server/domains/user.js +119 -0
  277. package/dist/server/env.d.ts +46 -0
  278. package/dist/server/env.js +96 -0
  279. package/dist/server/errors.js +38 -0
  280. package/dist/server/events.d.ts +880 -0
  281. package/dist/server/events.js +406 -0
  282. package/dist/server/facade.d.ts +83 -0
  283. package/dist/server/facade.js +124 -0
  284. package/dist/server/http.d.ts +125 -0
  285. package/dist/server/http.js +566 -0
  286. package/dist/server/identity/claims.js +58 -0
  287. package/dist/server/identity/convex.d.ts +15 -0
  288. package/dist/server/identity/convex.js +1 -0
  289. package/dist/server/index.d.ts +17 -0
  290. package/dist/server/index.js +11 -0
  291. package/dist/server/keys.js +60 -0
  292. package/dist/server/limits.js +41 -0
  293. package/dist/server/log.js +28 -0
  294. package/dist/server/mcp.d.ts +19 -0
  295. package/dist/server/mcp.js +250 -0
  296. package/dist/server/mutations/account.js +47 -0
  297. package/dist/server/mutations/calls.js +16 -0
  298. package/dist/server/mutations/code.js +91 -0
  299. package/dist/server/mutations/credentials/signin.js +210 -0
  300. package/dist/server/mutations/invalidate.js +60 -0
  301. package/dist/server/mutations/oauth.js +251 -0
  302. package/dist/server/mutations/refresh.js +152 -0
  303. package/dist/server/mutations/register.js +93 -0
  304. package/dist/server/mutations/retrieve.js +66 -0
  305. package/dist/server/mutations/signature.js +36 -0
  306. package/dist/server/mutations/signin.js +81 -0
  307. package/dist/server/mutations/signout.js +61 -0
  308. package/dist/server/mutations/store/refs.js +15 -0
  309. package/dist/server/mutations/store.js +82 -0
  310. package/dist/server/mutations/verifier.js +25 -0
  311. package/dist/server/mutations/verify.js +199 -0
  312. package/dist/server/oauth/authorize.js +98 -0
  313. package/dist/server/oauth/client.d.ts +93 -0
  314. package/dist/server/oauth/client.js +115 -0
  315. package/dist/server/oauth/code.d.ts +63 -0
  316. package/dist/server/oauth/code.js +124 -0
  317. package/dist/server/oauth/domain.d.ts +23 -0
  318. package/dist/server/oauth/domain.js +1 -0
  319. package/dist/server/oauth/factory.js +46 -0
  320. package/dist/server/oauth/grant.js +46 -0
  321. package/dist/server/oauth/handlers.js +108 -0
  322. package/dist/server/oauth/manage.js +121 -0
  323. package/dist/server/oauth/normalize.js +27 -0
  324. package/dist/server/oauth/refresh.d.ts +71 -0
  325. package/dist/server/oauth/refresh.js +132 -0
  326. package/dist/server/oauth/register.js +147 -0
  327. package/dist/server/oauth/runtime.js +280 -0
  328. package/dist/server/oauth/token.js +355 -0
  329. package/dist/server/payloads.d.ts +16 -0
  330. package/dist/server/payloads.js +30 -0
  331. package/dist/server/preload.d.ts +249 -0
  332. package/dist/server/preload.js +673 -0
  333. package/dist/server/random.js +25 -0
  334. package/dist/server/redirects.js +85 -0
  335. package/dist/server/runtime.d.ts +845 -0
  336. package/dist/server/runtime.js +387 -0
  337. package/dist/server/secret.js +46 -0
  338. package/dist/server/services/factors.js +117 -0
  339. package/dist/server/services/providers.js +23 -0
  340. package/dist/server/services/resolve.js +17 -0
  341. package/dist/server/session/lifecycle.d.ts +23 -0
  342. package/dist/server/session/lifecycle.js +139 -0
  343. package/dist/server/signin/flow.js +359 -0
  344. package/dist/server/telemetry.js +68 -0
  345. package/dist/server/templates.js +91 -0
  346. package/dist/server/token/refresh.js +35 -0
  347. package/dist/server/tokens.js +164 -0
  348. package/dist/server/totp.js +282 -0
  349. package/dist/server/types.d.ts +1154 -0
  350. package/dist/server/types.js +1 -0
  351. package/dist/server/url.js +43 -0
  352. package/dist/server/user/account.js +325 -0
  353. package/dist/server/utils/bearer.js +24 -0
  354. package/dist/server/utils/cache.js +51 -0
  355. package/dist/server/utils/retry.js +3 -0
  356. package/dist/server/utils/span.js +59 -0
  357. package/dist/server/validators.d.ts +2061 -0
  358. package/dist/server/validators.js +320 -0
  359. package/dist/server/webauthn.js +699 -0
  360. package/dist/server/wellknown.d.ts +74 -0
  361. package/dist/server/wellknown.js +195 -0
  362. package/dist/shared/brand.d.ts +28 -0
  363. package/dist/shared/brand.js +13 -0
  364. package/dist/shared/codes.d.ts +99 -0
  365. package/dist/shared/codes.js +98 -0
  366. package/dist/shared/compare.js +23 -0
  367. package/dist/shared/errors.js +24 -0
  368. package/dist/shared/event/kinds.d.ts +188 -0
  369. package/dist/shared/event/kinds.js +103 -0
  370. package/dist/shared/fetch/guard.js +189 -0
  371. package/dist/shared/log.js +62 -0
  372. package/dist/shared/results.d.ts +58 -0
  373. package/dist/shared/retry.js +27 -0
  374. package/dist/shared/webauthn.js +9 -0
  375. package/dist/svelte/AuthLoading.svelte +13 -0
  376. package/dist/svelte/AuthLoading.svelte.d.ts +8 -0
  377. package/dist/svelte/SignedIn.svelte +14 -0
  378. package/dist/svelte/SignedIn.svelte.d.ts +8 -0
  379. package/dist/svelte/SignedOut.svelte +13 -0
  380. package/dist/svelte/SignedOut.svelte.d.ts +8 -0
  381. package/dist/svelte/context.svelte.d.ts +26 -0
  382. package/dist/svelte/context.svelte.js +61 -0
  383. package/dist/svelte/index.d.ts +5 -0
  384. package/dist/svelte/index.js +4 -0
  385. package/dist/test.d.ts +48 -0
  386. package/dist/test.js +54 -0
  387. package/package.json +247 -0
@@ -0,0 +1,1122 @@
1
+ import { retryWithBackoff } from "../../shared/retry.js";
2
+ import { ErrorCode } from "../../shared/codes.js";
3
+ import { log } from "../log.js";
4
+ import { convexError } from "../errors.js";
5
+ import { createConnectionDomain, createGroupConnection, getConnectionDomainVerification, getGroupConnection, getGroupConnectionByDomain, getScimConfigByConnection, listConnectionDomains, listGroupConnections, removeConnectionDomain, removeConnectionDomainVerification, removeGroupConnection, updateGroupConnection, upsertConnectionDomainVerification, upsertGroupConnectionSecret, verifyConnectionDomain } from "../contract.js";
6
+ import { assertSafeIdpFetchUrl } from "../../shared/fetch/guard.js";
7
+ import { getGroupOidcUrls, getGroupSamlUrls, groupOidcProviderId, groupSamlProviderId, normalizeDomain } from "./shared.js";
8
+ import { getOidcConfig, getPublicConnectionConfig, getPublicOidcConfig, getPublicSamlConfig, getSamlConfig, upsertProtocolConfig, withOidcSecretState } from "./config.js";
9
+ import { createGroupPolicyDomain } from "./policy/domain.js";
10
+ import { createGroupScimDomain } from "./provision.js";
11
+ import { createServiceProviderMetadata, getSamlServiceProviderOptions, parseSamlIdpMetadataChecked } from "./saml.js";
12
+ import { createGroupWebhookDomain } from "./webhook.js";
13
+
14
+ //#region src/server/connection/domain.ts
15
+ /**
16
+ * Build the connection and Connection management domain.
17
+ */
18
+ function createGroupConnectionDomain(deps) {
19
+ const { config, getGroupConnectionSecret, loadConnectionOrThrow, validateGroupConnectionPolicy, emitGroupAuthEvent, connectionNotFoundError, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND, requireEnv, generateRandomString, INVITE_TOKEN_ALPHABET, sha256, encryptSecret, loadGroupPolicyOrThrow } = deps;
20
+ const webhook = createGroupWebhookDomain({
21
+ config,
22
+ encryptSecret,
23
+ loadConnectionOrThrow,
24
+ emitGroupAuthEvent
25
+ });
26
+ const scim = createGroupScimDomain({
27
+ config,
28
+ requireEnv,
29
+ generateRandomString,
30
+ INVITE_TOKEN_ALPHABET,
31
+ sha256,
32
+ loadGroupPolicyOrThrow,
33
+ emitGroupAuthEvent
34
+ });
35
+ const policy = createGroupPolicyDomain({
36
+ config,
37
+ loadGroupPolicyOrThrow,
38
+ validateGroupConnectionPolicy,
39
+ emitGroupAuthEvent
40
+ });
41
+ const resolveGroupConnectionProtocol = (connection) => {
42
+ if (connection.protocol === "oidc") return "oidc";
43
+ if (connection.protocol === "saml") return "saml";
44
+ throw convexError(ErrorCode.PROVIDER_NOT_CONFIGURED, "Group connection protocol is not configured.");
45
+ };
46
+ const GROUP_CONNECTION_DOMAIN_VERIFICATION_PREFIX = "_convex-auth-verification";
47
+ const GROUP_CONNECTION_DOMAIN_VERIFICATION_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
48
+ const toDomainSummary = (domain) => ({
49
+ domainId: domain._id,
50
+ domain: domain.domain,
51
+ isPrimary: domain.isPrimary,
52
+ verified: domain.verifiedAt !== void 0,
53
+ verifiedAt: domain.verifiedAt ?? null
54
+ });
55
+ const getDomainVerificationRecordName = (domain) => `${GROUP_CONNECTION_DOMAIN_VERIFICATION_PREFIX}.${normalizeDomain(domain)}`;
56
+ const parseTxtAnswer = (value) => {
57
+ const quoted = [...value.matchAll(/"([^"]*)"/g)].map((match) => match[1]);
58
+ if (quoted.length > 0) return quoted.join("");
59
+ return value.replace(/^"|"$/g, "").trim();
60
+ };
61
+ const resolveTxtValues = async (recordName) => {
62
+ const url = new URL("https://dns.google/resolve");
63
+ url.searchParams.set("name", recordName);
64
+ url.searchParams.set("type", "TXT");
65
+ const response = await fetch(url, { headers: { accept: "application/json" } });
66
+ if (!response.ok) throw new Error(`DNS TXT lookup failed with status ${response.status}.`);
67
+ const data = await response.json();
68
+ const normalizeName = (name) => name.replace(/\.$/, "").toLowerCase();
69
+ const expectedName = normalizeName(recordName);
70
+ return (data.Answer ?? []).filter((answer) => answer.type === 16 && typeof answer.name === "string" && normalizeName(answer.name) === expectedName).map((answer) => typeof answer.data === "string" ? parseTxtAnswer(answer.data) : null).filter((value) => value !== null && value.length > 0);
71
+ };
72
+ async function getConnection(ctx, args) {
73
+ if (args.id !== void 0) {
74
+ const record = await getGroupConnection(ctx, config.component.connection, args.id);
75
+ return record === null ? null : {
76
+ ...record,
77
+ config: getPublicConnectionConfig(record.config)
78
+ };
79
+ }
80
+ if (args.domain !== void 0) {
81
+ const lookup = await getGroupConnectionByDomain(ctx, config.component.connection, normalizeDomain(args.domain));
82
+ if (lookup === null || lookup.connection === null) return lookup;
83
+ return {
84
+ ...lookup,
85
+ connection: {
86
+ ...lookup.connection,
87
+ config: getPublicConnectionConfig(lookup.connection.config)
88
+ }
89
+ };
90
+ }
91
+ throw convexError(ErrorCode.INVALID_PARAMETERS, "Connection id or domain is required.");
92
+ }
93
+ return {
94
+ connection: {
95
+ create: async (ctx, data) => {
96
+ const connectionId = await createGroupConnection(ctx, config.component.connection, data);
97
+ await emitGroupAuthEvent(ctx, {
98
+ connectionId,
99
+ groupId: data.groupId,
100
+ kind: "connection.created",
101
+ actor: { type: "system" },
102
+ subject: {
103
+ type: "connection",
104
+ id: connectionId
105
+ },
106
+ outcome: "success",
107
+ data: {
108
+ connectionId,
109
+ protocol: data.protocol
110
+ },
111
+ webhook: false
112
+ });
113
+ return {
114
+ connectionId,
115
+ groupId: data.groupId
116
+ };
117
+ },
118
+ get: getConnection,
119
+ list: async (ctx, opts) => {
120
+ const result = await listGroupConnections(ctx, config.component.connection, {
121
+ where: opts.where,
122
+ paginationOpts: opts.paginationOpts,
123
+ orderBy: opts.orderBy,
124
+ order: opts.order
125
+ });
126
+ return {
127
+ ...result,
128
+ page: result.page.map((record) => ({
129
+ ...record,
130
+ config: getPublicConnectionConfig(record.config)
131
+ }))
132
+ };
133
+ },
134
+ update: async (ctx, args) => {
135
+ await updateGroupConnection(ctx, config.component.connection, {
136
+ connectionId: args.id,
137
+ patch: args.patch
138
+ });
139
+ const updated = await getConnection(ctx, { id: args.id });
140
+ if (updated !== null) await emitGroupAuthEvent(ctx, {
141
+ connectionId: args.id,
142
+ groupId: updated.groupId,
143
+ kind: "connection.updated",
144
+ actor: { type: "system" },
145
+ subject: {
146
+ type: "connection",
147
+ id: args.id
148
+ },
149
+ outcome: "success",
150
+ data: {
151
+ connectionId: args.id,
152
+ changed: Object.keys(args.patch)
153
+ },
154
+ webhook: false
155
+ });
156
+ return { connectionId: args.id };
157
+ },
158
+ remove: async (ctx, args) => {
159
+ const connection = await getConnection(ctx, { id: args.id });
160
+ await removeGroupConnection(ctx, config.component.connection, args.id);
161
+ if (connection !== null) await emitGroupAuthEvent(ctx, {
162
+ connectionId: args.id,
163
+ groupId: connection.groupId,
164
+ kind: "connection.removed",
165
+ actor: { type: "system" },
166
+ subject: {
167
+ type: "connection",
168
+ id: args.id
169
+ },
170
+ outcome: "success",
171
+ data: { connectionId: args.id },
172
+ webhook: false
173
+ });
174
+ return { connectionId: args.id };
175
+ },
176
+ status: async (ctx, args) => {
177
+ const connectionId = args.id;
178
+ const connection = await getGroupConnection(ctx, config.component.connection, connectionId);
179
+ if (!connection) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
180
+ const policy$1 = await loadGroupPolicyOrThrow(ctx, connection.groupId);
181
+ const oidcConfig = getOidcConfig(connection.config);
182
+ const oidcSecret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
183
+ const samlConfig = getSamlConfig(connection.config);
184
+ const scimConfig = await getScimConfigByConnection(ctx, config.component.connection, connectionId);
185
+ const domains = await listConnectionDomains(ctx, config.component.connection, connectionId);
186
+ const oidcReady = oidcConfig?.enabled === true && typeof oidcConfig?.client?.id === "string" && oidcConfig.client.id.length > 0 && oidcSecret !== null && (typeof oidcConfig?.discovery?.issuer === "string" || typeof oidcConfig?.discovery?.discoveryUrl === "string");
187
+ const samlReady = samlConfig?.enabled === true && typeof samlConfig?.idp?.entityId === "string";
188
+ const scimReady = scimConfig?.status === "active";
189
+ const ready = connection.status === "active" && (connection.protocol === "oidc" ? oidcReady : samlReady);
190
+ return {
191
+ connectionId: connection._id,
192
+ status: connection.status,
193
+ ready,
194
+ domainCount: domains.length,
195
+ protocols: {
196
+ oidc: {
197
+ configured: connection.protocol === "oidc" ? oidcReady : false,
198
+ ready: connection.protocol === "oidc" ? oidcReady : false,
199
+ clientId: oidcConfig?.client?.id ?? null,
200
+ issuer: oidcConfig?.discovery?.issuer ?? oidcConfig?.discovery?.discoveryUrl ?? null
201
+ },
202
+ saml: {
203
+ configured: connection.protocol === "saml" ? samlReady : false,
204
+ ready: connection.protocol === "saml" ? samlReady : false,
205
+ entityId: samlConfig?.idp?.entityId ?? samlConfig?.idp?.issuer ?? null
206
+ },
207
+ scim: {
208
+ configured: scimReady,
209
+ ready: scimReady,
210
+ basePath: scimConfig?.basePath ?? null,
211
+ deprovisionMode: policy$1.provisioning.deprovision.mode
212
+ }
213
+ }
214
+ };
215
+ }
216
+ },
217
+ domain: {
218
+ create: async (ctx, data) => {
219
+ return await createConnectionDomain(ctx, config.component.connection, {
220
+ ...data,
221
+ domain: normalizeDomain(data.domain)
222
+ });
223
+ },
224
+ list: async (ctx, args) => {
225
+ return await listConnectionDomains(ctx, config.component.connection, args.connectionId);
226
+ },
227
+ validate: async (ctx, args) => {
228
+ const { connectionId } = args;
229
+ const connection = await getGroupConnection(ctx, config.component.connection, connectionId);
230
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
231
+ const domains = await listConnectionDomains(ctx, config.component.connection, connectionId);
232
+ const primaryDomains = domains.filter((domain) => domain.isPrimary);
233
+ const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
234
+ const warnings = [];
235
+ if (domains.length === 0) warnings.push("No domains configured.");
236
+ if (primaryDomains.length === 0 && domains.length > 0) warnings.push("No primary domain configured.");
237
+ if (primaryDomains.length > 1) warnings.push("Multiple primary domains configured.");
238
+ if (verifiedDomains.length === 0 && domains.length > 0) warnings.push("No verified domains yet.");
239
+ return {
240
+ connectionId,
241
+ ready: connection.status === "active" && domains.length > 0 && primaryDomains.length === 1 && verifiedDomains.length > 0,
242
+ summary: {
243
+ domainCount: domains.length,
244
+ primaryCount: primaryDomains.length,
245
+ verifiedCount: verifiedDomains.length
246
+ },
247
+ domains: domains.map((domain) => toDomainSummary(domain)),
248
+ warnings
249
+ };
250
+ },
251
+ status: async (ctx, args) => {
252
+ const { connectionId } = args;
253
+ const [connection, domains] = await Promise.all([getGroupConnection(ctx, config.component.connection, connectionId), listConnectionDomains(ctx, config.component.connection, connectionId)]);
254
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
255
+ const primaryDomain = domains.find((domain) => domain.isPrimary) ?? null;
256
+ const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
257
+ const pendingChallenges = (await Promise.all(domains.map(async (domain) => {
258
+ const verification = await getConnectionDomainVerification(ctx, config.component.connection, domain._id);
259
+ if (!verification || verification.expiresAt < Date.now()) return null;
260
+ return {
261
+ domain: domain.domain,
262
+ recordName: verification.recordName,
263
+ expiresAt: verification.expiresAt
264
+ };
265
+ }))).filter((challenge) => challenge !== null);
266
+ const warnings = [];
267
+ const nextSteps = [];
268
+ if (domains.length === 0) {
269
+ warnings.push("No domains configured.");
270
+ nextSteps.push("Attach at least one domain to this connection.");
271
+ }
272
+ if (primaryDomain === null && domains.length > 0) {
273
+ warnings.push("No primary domain configured.");
274
+ nextSteps.push("Mark one attached domain as the primary domain.");
275
+ }
276
+ if (verifiedDomains.length === 0 && domains.length > 0) {
277
+ warnings.push("No verified domains yet.");
278
+ nextSteps.push("Request a TXT challenge and confirm verification for at least one domain.");
279
+ }
280
+ if (primaryDomain !== null && primaryDomain.verifiedAt === void 0 && domains.length > 0) nextSteps.push(`Verify the primary domain ${primaryDomain.domain} to establish trusted ownership.`);
281
+ if (pendingChallenges.length > 0) nextSteps.push("If DNS is already updated, confirm the pending TXT challenge to complete verification.");
282
+ const primaryDomainVerified = primaryDomain?.verifiedAt !== void 0;
283
+ return {
284
+ connectionId,
285
+ ready: connection.status === "active" && domains.length > 0 && primaryDomain !== null && verifiedDomains.length > 0,
286
+ primaryDomain: primaryDomain === null ? null : {
287
+ domainId: primaryDomain._id,
288
+ domain: primaryDomain.domain,
289
+ isPrimary: true,
290
+ verified: primaryDomain.verifiedAt !== void 0,
291
+ verifiedAt: primaryDomain.verifiedAt ?? null
292
+ },
293
+ trustedDomains: verifiedDomains.map((domain) => ({
294
+ domainId: domain._id,
295
+ domain: domain.domain,
296
+ isPrimary: Boolean(domain.isPrimary),
297
+ verified: true,
298
+ verifiedAt: domain.verifiedAt ?? null
299
+ })),
300
+ pendingChallenges,
301
+ trust: {
302
+ domainDiscoveryReady: verifiedDomains.length > 0,
303
+ primaryDomainVerified,
304
+ automaticLinkingEligible: primaryDomainVerified && connection.status === "active" && verifiedDomains.length > 0
305
+ },
306
+ warnings,
307
+ nextSteps
308
+ };
309
+ },
310
+ remove: async (ctx, args) => {
311
+ await removeConnectionDomain(ctx, config.component.connection, args.id);
312
+ },
313
+ verification: {
314
+ request: async (ctx, args) => {
315
+ const connection = await loadConnectionOrThrow(ctx, args.connectionId);
316
+ const normalizedDomain = normalizeDomain(args.domain);
317
+ const domain = (await listConnectionDomains(ctx, config.component.connection, connection._id)).find((entry) => entry.domain === normalizedDomain);
318
+ if (!domain) throw convexError(ErrorCode.INVALID_PARAMETERS, "Domain is not attached to this connection.");
319
+ const requestedAt = Date.now();
320
+ const expiresAt = requestedAt + GROUP_CONNECTION_DOMAIN_VERIFICATION_TTL_MS;
321
+ const token = generateRandomString(32, INVITE_TOKEN_ALPHABET);
322
+ const tokenHash = await sha256(token);
323
+ const recordName = getDomainVerificationRecordName(normalizedDomain);
324
+ await upsertConnectionDomainVerification(ctx, config.component.connection, {
325
+ connectionId: connection._id,
326
+ groupId: connection.groupId,
327
+ domainId: domain._id,
328
+ domain: normalizedDomain,
329
+ recordName,
330
+ token,
331
+ tokenHash,
332
+ requestedAt,
333
+ expiresAt
334
+ });
335
+ await emitGroupAuthEvent(ctx, {
336
+ connectionId: connection._id,
337
+ groupId: connection.groupId,
338
+ kind: "connection.domain.verification_requested",
339
+ actor: { type: "system" },
340
+ subject: {
341
+ type: "connection",
342
+ id: domain._id
343
+ },
344
+ data: {
345
+ connectionId: connection._id,
346
+ domain: normalizedDomain,
347
+ recordName,
348
+ expiresAt
349
+ }
350
+ });
351
+ return {
352
+ connectionId: connection._id,
353
+ domain: normalizedDomain,
354
+ requestedAt,
355
+ expiresAt,
356
+ challenge: {
357
+ recordType: "TXT",
358
+ recordName,
359
+ recordValue: token
360
+ }
361
+ };
362
+ },
363
+ confirm: async (ctx, args) => {
364
+ const connection = await loadConnectionOrThrow(ctx, args.connectionId);
365
+ const normalizedDomain = normalizeDomain(args.domain);
366
+ const domain = (await listConnectionDomains(ctx, config.component.connection, connection._id)).find((entry) => entry.domain === normalizedDomain);
367
+ if (!domain) throw convexError(ErrorCode.INVALID_PARAMETERS, "Domain is not attached to this connection.");
368
+ if (domain.verifiedAt !== void 0) return {
369
+ connectionId: connection._id,
370
+ domain: normalizedDomain,
371
+ verifiedAt: domain.verifiedAt,
372
+ checks: [{
373
+ name: "domain_verified",
374
+ ok: true,
375
+ message: "Domain is already verified."
376
+ }]
377
+ };
378
+ const verification = await getConnectionDomainVerification(ctx, config.component.connection, domain._id);
379
+ const checks = [];
380
+ if (!verification) {
381
+ checks.push({
382
+ name: "verification_requested",
383
+ ok: false,
384
+ message: "No active domain verification challenge exists."
385
+ });
386
+ return {
387
+ connectionId: connection._id,
388
+ domain: normalizedDomain,
389
+ checks
390
+ };
391
+ }
392
+ checks.push({
393
+ name: "verification_requested",
394
+ ok: true
395
+ });
396
+ if (verification.expiresAt < Date.now()) {
397
+ await removeConnectionDomainVerification(ctx, config.component.connection, domain._id);
398
+ checks.push({
399
+ name: "challenge_active",
400
+ ok: false,
401
+ message: "The verification challenge expired. Request a new one."
402
+ });
403
+ return {
404
+ connectionId: connection._id,
405
+ domain: normalizedDomain,
406
+ checks
407
+ };
408
+ }
409
+ checks.push({
410
+ name: "challenge_active",
411
+ ok: true
412
+ });
413
+ let txtValues;
414
+ try {
415
+ txtValues = await resolveTxtValues(verification.recordName);
416
+ } catch (error) {
417
+ throw convexError(ErrorCode.INTERNAL_ERROR, error instanceof Error ? error.message : "Failed to resolve DNS TXT records.");
418
+ }
419
+ checks.push({
420
+ name: "dns_record_present",
421
+ ok: txtValues.length > 0,
422
+ message: txtValues.length > 0 ? void 0 : `No TXT records found at ${verification.recordName}.`
423
+ });
424
+ const matches = txtValues.includes(verification.token);
425
+ checks.push({
426
+ name: "dns_record_matches",
427
+ ok: matches,
428
+ message: matches ? void 0 : `TXT record at ${verification.recordName} does not match the expected value.`
429
+ });
430
+ if (!checks.every((check) => check.ok)) return {
431
+ connectionId: connection._id,
432
+ domain: normalizedDomain,
433
+ checks
434
+ };
435
+ const verifiedAt = Date.now();
436
+ await verifyConnectionDomain(ctx, config.component.connection, {
437
+ domainId: domain._id,
438
+ verifiedAt
439
+ });
440
+ await emitGroupAuthEvent(ctx, {
441
+ connectionId: connection._id,
442
+ groupId: connection.groupId,
443
+ kind: "connection.domain.verified",
444
+ actor: { type: "system" },
445
+ subject: {
446
+ type: "connection",
447
+ id: domain._id
448
+ },
449
+ data: {
450
+ connectionId: connection._id,
451
+ domain: normalizedDomain,
452
+ verifiedAt
453
+ }
454
+ });
455
+ return {
456
+ connectionId: connection._id,
457
+ domain: normalizedDomain,
458
+ verifiedAt,
459
+ checks
460
+ };
461
+ }
462
+ }
463
+ },
464
+ saml: {
465
+ upsert: async (ctx, data) => {
466
+ let connection;
467
+ try {
468
+ connection = await getGroupConnection(ctx, config.component.connection, data.connectionId);
469
+ } catch {
470
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
471
+ }
472
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
473
+ if (connection.protocol !== "saml") throw convexError(ErrorCode.INVALID_PARAMETERS, "This connection is not a SAML connection.");
474
+ const metadataUrl = typeof data.metadata.url === "string" && data.metadata.url.length > 0 ? data.metadata.url : void 0;
475
+ let metadataXml;
476
+ if (metadataUrl) {
477
+ assertSafeIdpFetchUrl(metadataUrl);
478
+ try {
479
+ metadataXml = await retryWithBackoff(async () => ctx.runAction(config.component.connection.cache.samlMetadata, { url: metadataUrl }));
480
+ } catch (error) {
481
+ throw convexError(ErrorCode.INVALID_PARAMETERS, error instanceof Error ? error.message : "Failed to fetch SAML metadata");
482
+ }
483
+ } else if (data.metadata.xml) metadataXml = data.metadata.xml;
484
+ else throw convexError(ErrorCode.INVALID_PARAMETERS, "SAML registration requires metadataXml or metadataUrl.");
485
+ let parsed;
486
+ try {
487
+ parsed = parseSamlIdpMetadataChecked({
488
+ metadataXml,
489
+ config: { protocols: { saml: { security: data.security } } }
490
+ });
491
+ } catch (error) {
492
+ throw convexError(ErrorCode.INVALID_PARAMETERS, error instanceof Error ? `Failed to parse SAML metadata: ${error.message}` : "Failed to parse SAML metadata.");
493
+ }
494
+ const setIdpSigningCert = parsed.signingCert;
495
+ if (!(typeof setIdpSigningCert === "string" ? setIdpSigningCert.trim().length > 0 : Array.isArray(setIdpSigningCert) && setIdpSigningCert.some((cert) => typeof cert === "string" && cert.trim().length > 0))) throw convexError(ErrorCode.INVALID_PARAMETERS, "SAML IdP metadata has no usable signing certificate. A signing certificate is required to verify assertions before the connection can be activated.");
496
+ log("DEBUG", "[group-connection] saml:configure:parsed", {
497
+ connectionId: data.connectionId,
498
+ metadataUrl,
499
+ entityId: parsed.entityId,
500
+ issuer: parsed.issuer
501
+ });
502
+ const baseConfig = upsertProtocolConfig(connection.config, "saml", {
503
+ enabled: true,
504
+ idp: {
505
+ metadataUrl,
506
+ metadataXml,
507
+ ...parsed
508
+ },
509
+ serviceProvider: data.serviceProvider,
510
+ request: {
511
+ signAuthnRequests: data.request?.signAuthnRequests ?? parsed.wantsSignedAuthnRequests,
512
+ nameIdFormat: data.request?.nameIdFormat,
513
+ forceAuthn: data.request?.forceAuthn,
514
+ authnContextClassRefs: data.request?.authnContextClassRefs
515
+ },
516
+ profile: {
517
+ mapping: data.profile?.mapping,
518
+ extraFields: data.profile?.extraFields
519
+ },
520
+ security: data.security
521
+ });
522
+ const normalizedDomains = data.domains?.map(normalizeDomain);
523
+ const nextConfig = normalizedDomains ? {
524
+ ...baseConfig,
525
+ domains: normalizedDomains
526
+ } : baseConfig;
527
+ const nextSamlConfig = nextConfig.protocols?.saml ?? void 0;
528
+ log("DEBUG", "[group-connection] saml:configure:nextConfig", {
529
+ connectionId: data.connectionId,
530
+ entityId: nextSamlConfig?.idp?.entityId ?? null,
531
+ issuer: nextSamlConfig?.idp?.issuer ?? null,
532
+ metadataUrl: nextSamlConfig?.idp?.metadataUrl ?? null,
533
+ hasMetadataXml: typeof nextSamlConfig?.idp?.metadataXml === "string"
534
+ });
535
+ try {
536
+ await updateGroupConnection(ctx, config.component.connection, {
537
+ connectionId: connection._id,
538
+ patch: {
539
+ status: "active",
540
+ config: nextConfig
541
+ }
542
+ });
543
+ } catch {
544
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to persist SAML registration.");
545
+ }
546
+ if (normalizedDomains) for (const [index, domain] of normalizedDomains.entries()) try {
547
+ await createConnectionDomain(ctx, config.component.connection, {
548
+ connectionId: connection._id,
549
+ groupId: connection.groupId,
550
+ domain,
551
+ isPrimary: index === 0
552
+ });
553
+ } catch {
554
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to persist connection domain.");
555
+ }
556
+ try {
557
+ await emitGroupAuthEvent(ctx, {
558
+ connectionId: connection._id,
559
+ groupId: connection.groupId,
560
+ kind: "connection.saml.set",
561
+ actor: { type: "system" },
562
+ subject: {
563
+ type: "connection",
564
+ id: connection._id
565
+ },
566
+ data: {
567
+ connectionId: connection._id,
568
+ metadataUrl,
569
+ domains: normalizedDomains
570
+ }
571
+ });
572
+ } catch {
573
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to record SAML registration audit event.");
574
+ }
575
+ return {
576
+ connectionId: connection._id,
577
+ groupId: connection.groupId
578
+ };
579
+ },
580
+ refresh: async (ctx, data) => {
581
+ let connection;
582
+ try {
583
+ connection = await getGroupConnection(ctx, config.component.connection, data.connectionId);
584
+ } catch {
585
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
586
+ }
587
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
588
+ const samlConfig = connection.config?.protocols?.saml;
589
+ if (connection.protocol !== "saml") throw convexError(ErrorCode.INVALID_PARAMETERS, "This connection is not a SAML connection.");
590
+ if (typeof samlConfig?.idp?.metadataUrl !== "string") throw convexError(ErrorCode.INVALID_PARAMETERS, "SAML metadataUrl is not configured.");
591
+ const metadataUrl = samlConfig.idp.metadataUrl;
592
+ assertSafeIdpFetchUrl(metadataUrl);
593
+ let metadataXml;
594
+ try {
595
+ metadataXml = await retryWithBackoff(async () => ctx.runAction(config.component.connection.cache.samlMetadata, { url: metadataUrl }));
596
+ } catch (error) {
597
+ throw convexError(ErrorCode.INVALID_PARAMETERS, error instanceof Error ? error.message : "Failed to fetch SAML metadata");
598
+ }
599
+ let parsed;
600
+ try {
601
+ parsed = parseSamlIdpMetadataChecked({
602
+ metadataXml,
603
+ config: connection.config
604
+ });
605
+ } catch (error) {
606
+ throw convexError(ErrorCode.INVALID_PARAMETERS, error instanceof Error ? `Failed to parse SAML metadata: ${error.message}` : "Failed to parse SAML metadata.");
607
+ }
608
+ const refreshIdpSigningCert = parsed.signingCert;
609
+ if (!(typeof refreshIdpSigningCert === "string" ? refreshIdpSigningCert.trim().length > 0 : Array.isArray(refreshIdpSigningCert) && refreshIdpSigningCert.some((cert) => typeof cert === "string" && cert.trim().length > 0))) throw convexError(ErrorCode.INVALID_PARAMETERS, "SAML IdP metadata has no usable signing certificate. A signing certificate is required to verify assertions.");
610
+ const nextConfig = upsertProtocolConfig(connection.config, "saml", {
611
+ enabled: true,
612
+ idp: {
613
+ metadataUrl,
614
+ metadataXml,
615
+ ...parsed
616
+ },
617
+ serviceProvider: samlConfig.serviceProvider,
618
+ request: samlConfig.request,
619
+ profile: samlConfig.profile,
620
+ security: samlConfig.security
621
+ });
622
+ try {
623
+ await updateGroupConnection(ctx, config.component.connection, {
624
+ connectionId: connection._id,
625
+ patch: {
626
+ status: connection.status,
627
+ config: nextConfig
628
+ }
629
+ });
630
+ } catch {
631
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to persist refreshed SAML metadata.");
632
+ }
633
+ try {
634
+ await emitGroupAuthEvent(ctx, {
635
+ connectionId: connection._id,
636
+ groupId: connection.groupId,
637
+ kind: "connection.saml.refreshed",
638
+ actor: { type: "system" },
639
+ subject: {
640
+ type: "connection",
641
+ id: connection._id
642
+ },
643
+ data: {
644
+ connectionId: connection._id,
645
+ metadataUrl
646
+ }
647
+ });
648
+ } catch {
649
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to record SAML refresh audit event.");
650
+ }
651
+ return {
652
+ connectionId: connection._id,
653
+ groupId: connection.groupId
654
+ };
655
+ },
656
+ get: async (ctx, args) => {
657
+ const { connectionId } = args;
658
+ let connection;
659
+ try {
660
+ connection = await getGroupConnection(ctx, config.component.connection, connectionId);
661
+ } catch {
662
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
663
+ }
664
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
665
+ return getPublicSamlConfig(connection.config);
666
+ },
667
+ status: (ctx, args) => {
668
+ const { connectionId } = args;
669
+ return getGroupConnection(ctx, config.component.connection, connectionId).then((connection) => {
670
+ if (!connection) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
671
+ const currentConfig = getPublicSamlConfig(connection.config);
672
+ const configured = currentConfig.enabled === true;
673
+ return {
674
+ connectionId,
675
+ configured,
676
+ ready: configured && typeof currentConfig.idp?.entityId === "string",
677
+ config: currentConfig,
678
+ checks: [{
679
+ name: "saml_configured",
680
+ ok: configured,
681
+ message: configured ? void 0 : "SAML is not configured."
682
+ }]
683
+ };
684
+ });
685
+ },
686
+ metadata: async (ctx, opts) => {
687
+ const connection = await getGroupConnection(ctx, config.component.connection, opts.connectionId);
688
+ if (!connection) throw convexError(ErrorCode.INVALID_PARAMETERS, "Connection not found.");
689
+ return createServiceProviderMetadata(getSamlServiceProviderOptions({
690
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
691
+ source: {
692
+ kind: "connection",
693
+ id: connection._id
694
+ },
695
+ config: connection.config,
696
+ overrides: {
697
+ entityId: opts.entityId,
698
+ acsUrl: opts.acsUrl,
699
+ sloUrl: opts.sloUrl
700
+ }
701
+ }));
702
+ },
703
+ validate: async (ctx, args) => {
704
+ const { connectionId } = args;
705
+ const checks = [];
706
+ const connection = await getGroupConnection(ctx, config.component.connection, connectionId);
707
+ if (!connection) return {
708
+ ok: false,
709
+ connectionId,
710
+ checks: [{
711
+ name: "group_connection_exists",
712
+ ok: false,
713
+ message: "Connection not found."
714
+ }]
715
+ };
716
+ const samlConfig = connection.config?.protocols?.saml;
717
+ const samlConfigured = samlConfig?.enabled === true && typeof samlConfig?.idp?.metadataXml === "string";
718
+ checks.push({
719
+ name: "saml_configured",
720
+ ok: samlConfigured,
721
+ message: samlConfigured ? void 0 : "SAML is not configured."
722
+ });
723
+ const hasIdpMetadata = typeof samlConfig?.idp?.metadataXml === "string" && samlConfig.idp.metadataXml.length > 0;
724
+ checks.push({
725
+ name: "idp_metadata_present",
726
+ ok: hasIdpMetadata,
727
+ message: hasIdpMetadata ? void 0 : "IdP metadata XML is missing."
728
+ });
729
+ const reparsedIdp = hasIdpMetadata && typeof samlConfig?.idp?.metadataXml === "string" ? (() => {
730
+ try {
731
+ return parseSamlIdpMetadataChecked({
732
+ metadataXml: samlConfig.idp.metadataXml,
733
+ config: connection.config
734
+ });
735
+ } catch {
736
+ return null;
737
+ }
738
+ })() : null;
739
+ log("DEBUG", "[group-connection] saml:validate:idp", {
740
+ connectionId,
741
+ entityId: samlConfig?.idp?.entityId ?? null,
742
+ issuer: samlConfig?.idp?.issuer ?? null,
743
+ metadataUrl: samlConfig?.idp?.metadataUrl ?? null,
744
+ reparsedEntityId: reparsedIdp?.entityId ?? null,
745
+ reparsedIssuer: reparsedIdp?.issuer ?? null
746
+ });
747
+ const hasEntityId = typeof samlConfig?.idp?.entityId === "string" && samlConfig.idp.entityId.length > 0 || typeof samlConfig?.idp?.issuer === "string" && samlConfig.idp.issuer.length > 0 || typeof reparsedIdp?.entityId === "string" && reparsedIdp.entityId.length > 0 || typeof reparsedIdp?.issuer === "string" && reparsedIdp.issuer.length > 0;
748
+ checks.push({
749
+ name: "idp_entity_id",
750
+ ok: hasEntityId,
751
+ message: hasEntityId ? void 0 : "IdP entityId could not be parsed from metadata."
752
+ });
753
+ let spMetadataOk = false;
754
+ let spMetadataMessage;
755
+ if (samlConfigured) try {
756
+ createServiceProviderMetadata(getSamlServiceProviderOptions({
757
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
758
+ source: {
759
+ kind: "connection",
760
+ id: connection._id
761
+ },
762
+ config: connection.config,
763
+ overrides: {}
764
+ }));
765
+ spMetadataOk = true;
766
+ } catch (e) {
767
+ spMetadataMessage = e instanceof Error ? e.message : "SP metadata generation failed.";
768
+ }
769
+ else spMetadataMessage = "Skipped — SAML not configured.";
770
+ checks.push({
771
+ name: "sp_metadata_generates",
772
+ ok: spMetadataOk,
773
+ message: spMetadataMessage
774
+ });
775
+ const requiresSignedAssertions = samlConfig?.security?.requireSignedAssertions === true;
776
+ const hasSigningCert = reparsedIdp?.signingCert !== null;
777
+ checks.push({
778
+ name: "signed_assertions_compatible",
779
+ ok: !requiresSignedAssertions || hasSigningCert,
780
+ message: !requiresSignedAssertions || hasSigningCert ? void 0 : "Signed assertions are required but the IdP metadata has no signing certificate."
781
+ });
782
+ const signAuthnRequests = samlConfig?.request?.signAuthnRequests === true;
783
+ const hasSpPrivateKey = typeof samlConfig?.serviceProvider?.privateKey === "string";
784
+ checks.push({
785
+ name: "authn_request_signing_compatible",
786
+ ok: !signAuthnRequests || hasSpPrivateKey,
787
+ message: !signAuthnRequests || hasSpPrivateKey ? void 0 : "signAuthnRequests is enabled but no SP privateKey is configured."
788
+ });
789
+ checks.push({
790
+ name: "timestamp_validation_configured",
791
+ ok: true,
792
+ message: samlConfig?.security?.requireTimestamps === true ? `Timestamp validation enabled with clock skew ${samlConfig.security.clockSkewSeconds ?? 300} seconds.` : "Timestamp validation uses compatibility defaults."
793
+ });
794
+ return {
795
+ ok: checks.every((c) => c.ok),
796
+ connectionId: connection._id,
797
+ checks
798
+ };
799
+ }
800
+ },
801
+ policy,
802
+ oidc: {
803
+ upsert: async (ctx, data) => {
804
+ if (data.discovery.issuer === void 0 && data.discovery.discoveryUrl === void 0) throw convexError(ErrorCode.INVALID_PARAMETERS, "OIDC registration requires issuer or discoveryUrl.");
805
+ let connection;
806
+ try {
807
+ connection = await getGroupConnection(ctx, config.component.connection, data.connectionId);
808
+ } catch {
809
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
810
+ }
811
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
812
+ if (connection.protocol !== "oidc") throw convexError(ErrorCode.INVALID_PARAMETERS, "This connection is not an OIDC connection.");
813
+ const nextConfig = upsertProtocolConfig(connection.config, "oidc", {
814
+ enabled: true,
815
+ discovery: {
816
+ issuer: data.discovery.issuer,
817
+ discoveryUrl: data.discovery.discoveryUrl,
818
+ jwksUri: data.discovery.jwksUri,
819
+ audience: data.discovery.audience
820
+ },
821
+ client: {
822
+ id: data.client.id,
823
+ authMethod: data.client.authMethod
824
+ },
825
+ request: {
826
+ scopes: data.request?.scopes ?? [
827
+ "openid",
828
+ "profile",
829
+ "email"
830
+ ],
831
+ loginHint: data.request?.loginHint,
832
+ authorizationParams: data.request?.authorizationParams
833
+ },
834
+ security: {
835
+ clockToleranceSeconds: data.security?.clockToleranceSeconds,
836
+ strictIssuer: data.security?.strictIssuer
837
+ },
838
+ profile: {
839
+ mapping: data.profile?.mapping,
840
+ extraFields: data.profile?.extraFields
841
+ }
842
+ });
843
+ try {
844
+ await updateGroupConnection(ctx, config.component.connection, {
845
+ connectionId: data.connectionId,
846
+ patch: { config: nextConfig }
847
+ });
848
+ } catch {
849
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to persist OIDC registration.");
850
+ }
851
+ if (data.client.secret !== void 0) {
852
+ let ciphertext;
853
+ try {
854
+ ciphertext = await encryptSecret(data.client.secret);
855
+ } catch {
856
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to encrypt OIDC client secret.");
857
+ }
858
+ try {
859
+ await upsertGroupConnectionSecret(ctx, config.component.connection, {
860
+ connectionId: data.connectionId,
861
+ groupId: connection.groupId,
862
+ kind: GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND,
863
+ ciphertext,
864
+ updatedAt: Date.now()
865
+ });
866
+ } catch {
867
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to persist OIDC client secret.");
868
+ }
869
+ }
870
+ try {
871
+ await emitGroupAuthEvent(ctx, {
872
+ connectionId: data.connectionId,
873
+ groupId: connection.groupId,
874
+ kind: "connection.oidc.set",
875
+ actor: { type: "system" },
876
+ subject: {
877
+ type: "connection",
878
+ id: data.connectionId
879
+ },
880
+ data: {
881
+ connectionId: data.connectionId,
882
+ issuer: data.discovery.issuer,
883
+ discoveryUrl: data.discovery.discoveryUrl,
884
+ jwksUri: data.discovery.jwksUri,
885
+ audience: data.discovery.audience,
886
+ tokenEndpointAuthMethod: data.client.authMethod
887
+ }
888
+ });
889
+ } catch {
890
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to record OIDC registration audit event.");
891
+ }
892
+ let secret;
893
+ try {
894
+ secret = await getGroupConnectionSecret(ctx, data.connectionId, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
895
+ } catch {
896
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load OIDC secret metadata.");
897
+ }
898
+ return withOidcSecretState(getPublicOidcConfig(nextConfig), secret !== null);
899
+ },
900
+ get: async (ctx, args) => {
901
+ const { connectionId } = args;
902
+ let connection;
903
+ try {
904
+ connection = await getGroupConnection(ctx, config.component.connection, connectionId);
905
+ } catch {
906
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
907
+ }
908
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
909
+ let secret;
910
+ try {
911
+ secret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
912
+ } catch {
913
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load OIDC secret metadata.");
914
+ }
915
+ return withOidcSecretState(getPublicOidcConfig(connection.config), secret !== null);
916
+ },
917
+ status: (ctx, args) => {
918
+ const { connectionId } = args;
919
+ return Promise.all([getGroupConnection(ctx, config.component.connection, connectionId), getGroupConnectionSecret(ctx, connectionId, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND)]).then(([connection, secret]) => {
920
+ if (!connection) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
921
+ const currentConfig = getPublicOidcConfig(connection.config);
922
+ const oidcConfig = getOidcConfig(connection.config);
923
+ const configured = currentConfig.enabled === true && typeof oidcConfig.client?.id === "string" && (typeof oidcConfig.discovery?.issuer === "string" || typeof oidcConfig.discovery?.discoveryUrl === "string");
924
+ return {
925
+ connectionId,
926
+ configured,
927
+ ready: configured && secret !== null,
928
+ config: withOidcSecretState(currentConfig, secret !== null),
929
+ checks: [{
930
+ name: "oidc_configured",
931
+ ok: configured,
932
+ message: configured ? void 0 : "OIDC is not configured."
933
+ }, {
934
+ name: "client_secret_stored",
935
+ ok: secret !== null,
936
+ message: secret !== null ? void 0 : "OIDC client secret is missing."
937
+ }]
938
+ };
939
+ });
940
+ },
941
+ signIn: async (ctx, data) => {
942
+ log("DEBUG", "[group-connection] resolver:start", {
943
+ connectionId: data.connectionId,
944
+ email: data.email,
945
+ domain: data.domain,
946
+ redirectTo: data.redirectTo
947
+ });
948
+ let connection;
949
+ if (data.connectionId !== void 0) {
950
+ try {
951
+ connection = await getGroupConnection(ctx, config.component.connection, data.connectionId);
952
+ } catch {
953
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to load connection.");
954
+ }
955
+ if (connection === null) throw convexError(ErrorCode.INVALID_PARAMETERS, connectionNotFoundError);
956
+ } else if (data.domain !== void 0 || data.email !== void 0) {
957
+ let result;
958
+ try {
959
+ result = await getGroupConnectionByDomain(ctx, config.component.connection, normalizeDomain(data.domain ?? String(data.email).split("@").pop() ?? ""));
960
+ } catch {
961
+ throw convexError(ErrorCode.INTERNAL_ERROR, "Failed to resolve connection by domain.");
962
+ }
963
+ log("DEBUG", "[group-connection] resolver:domainLookup", result);
964
+ if (result?.connection && result.domain?.verifiedAt !== void 0) connection = result.connection;
965
+ else throw convexError(ErrorCode.INVALID_PARAMETERS, "No group connection matched the provided input.");
966
+ } else throw convexError(ErrorCode.INVALID_PARAMETERS, "No group connection matched the provided input.");
967
+ if (connection.status !== "active") throw convexError(ErrorCode.INVALID_PARAMETERS, "Group connection is not active.");
968
+ const protocol = resolveGroupConnectionProtocol(connection);
969
+ log("DEBUG", "[group-connection] resolver:connection", {
970
+ connectionId: connection._id,
971
+ status: connection.status,
972
+ protocol
973
+ });
974
+ const { signInPath, callbackPath, providerId } = protocol === "oidc" ? (() => {
975
+ const urls = getGroupOidcUrls({
976
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
977
+ connectionId: connection._id,
978
+ sharedRedirectURI: deps.sharedOidcRedirectURI
979
+ });
980
+ return {
981
+ signInPath: urls.signInUrl,
982
+ callbackPath: urls.callbackUrl,
983
+ providerId: groupOidcProviderId(connection._id)
984
+ };
985
+ })() : (() => {
986
+ const urls = getGroupSamlUrls({
987
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
988
+ source: {
989
+ kind: "connection",
990
+ id: connection._id
991
+ }
992
+ });
993
+ return {
994
+ signInPath: `${requireEnv("CONVEX_SITE_URL")}/connections/${connection._id}/saml/signin`,
995
+ callbackPath: urls.acsUrl,
996
+ providerId: groupSamlProviderId(connection._id)
997
+ };
998
+ })();
999
+ log("DEBUG", "[group-connection] resolver:paths", {
1000
+ connectionId: connection._id,
1001
+ signInPath,
1002
+ callbackPath
1003
+ });
1004
+ return {
1005
+ connectionId: connection._id,
1006
+ protocol,
1007
+ providerId,
1008
+ signInPath: protocol === "oidc" && typeof data.loginHint === "string" ? (() => {
1009
+ const signInUrl = new URL(signInPath);
1010
+ signInUrl.searchParams.set("loginHint", data.loginHint);
1011
+ return signInUrl.toString();
1012
+ })() : signInPath,
1013
+ callbackPath,
1014
+ redirectTo: data.redirectTo
1015
+ };
1016
+ },
1017
+ validate: async (ctx, args) => {
1018
+ const { connectionId } = args;
1019
+ const checks = [];
1020
+ const connection = await getGroupConnection(ctx, config.component.connection, connectionId);
1021
+ if (!connection) return {
1022
+ ok: false,
1023
+ connectionId,
1024
+ checks: [{
1025
+ name: "group_connection_exists",
1026
+ ok: false,
1027
+ message: "Connection not found."
1028
+ }]
1029
+ };
1030
+ const oidc = getOidcConfig(connection.config);
1031
+ const secret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
1032
+ const oidcConfigured = oidc.enabled === true && typeof oidc.client?.id === "string" && oidc.client.id.length > 0;
1033
+ checks.push({
1034
+ name: "oidc_configured",
1035
+ ok: oidcConfigured,
1036
+ message: oidcConfigured ? void 0 : "OIDC is not configured."
1037
+ });
1038
+ const hasClientId = typeof oidc.client?.id === "string" && oidc.client.id.length > 0;
1039
+ checks.push({
1040
+ name: "client_id_present",
1041
+ ok: hasClientId,
1042
+ message: hasClientId ? void 0 : "clientId is missing."
1043
+ });
1044
+ checks.push({
1045
+ name: "client_secret_stored",
1046
+ ok: secret !== null,
1047
+ message: secret !== null ? void 0 : "OIDC client secret is missing."
1048
+ });
1049
+ const discoveryConfig = typeof oidc.discovery === "object" && oidc.discovery !== null ? oidc.discovery : {};
1050
+ const clientConfig = typeof oidc.client === "object" && oidc.client !== null ? oidc.client : {};
1051
+ const discoveryTarget = discoveryConfig.discoveryUrl ?? discoveryConfig.issuer;
1052
+ const hasDiscovery = typeof discoveryTarget === "string" && discoveryTarget.length > 0;
1053
+ checks.push({
1054
+ name: "issuer_or_discovery_url_present",
1055
+ ok: hasDiscovery,
1056
+ message: hasDiscovery ? void 0 : "issuer or discoveryUrl is missing."
1057
+ });
1058
+ let discoveryOk = false;
1059
+ let discoveryMessage;
1060
+ if (hasDiscovery) {
1061
+ const discoveryUrl = typeof discoveryConfig.discoveryUrl === "string" && discoveryConfig.discoveryUrl.length > 0 ? discoveryConfig.discoveryUrl : `${String(discoveryConfig.issuer)}/.well-known/openid-configuration`;
1062
+ try {
1063
+ assertSafeIdpFetchUrl(discoveryUrl);
1064
+ const res = await fetch(discoveryUrl, {
1065
+ headers: { Accept: "application/json" },
1066
+ redirect: "manual",
1067
+ signal: AbortSignal.timeout(8e3)
1068
+ });
1069
+ if (!res.ok) discoveryMessage = `Discovery endpoint returned ${res.status}.`;
1070
+ else {
1071
+ const json = await res.json();
1072
+ if (typeof json.issuer !== "string") discoveryMessage = "Discovery document is missing issuer field.";
1073
+ else if (typeof json.authorization_endpoint !== "string") discoveryMessage = "Discovery document is missing authorization_endpoint.";
1074
+ else if (typeof json.token_endpoint !== "string") discoveryMessage = "Discovery document is missing token_endpoint.";
1075
+ else if (discoveryConfig.jwksUri === void 0 && typeof json.jwks_uri !== "string") discoveryMessage = "Discovery document is missing jwks_uri and no jwksUri override is configured.";
1076
+ else discoveryOk = true;
1077
+ }
1078
+ } catch (e) {
1079
+ discoveryMessage = e instanceof Error ? `Discovery fetch failed: ${e.message}` : "Discovery fetch failed.";
1080
+ }
1081
+ } else discoveryMessage = "Skipped — issuer or discoveryUrl not set.";
1082
+ checks.push({
1083
+ name: "discovery_reachable",
1084
+ ok: discoveryOk,
1085
+ message: discoveryMessage
1086
+ });
1087
+ const hasValidTokenAuthMethod = clientConfig.authMethod === void 0 || clientConfig.authMethod === "client_secret_post" || clientConfig.authMethod === "client_secret_basic";
1088
+ checks.push({
1089
+ name: "token_endpoint_auth_method_supported",
1090
+ ok: hasValidTokenAuthMethod,
1091
+ message: hasValidTokenAuthMethod ? void 0 : "tokenEndpointAuthMethod must be client_secret_post or client_secret_basic."
1092
+ });
1093
+ const hasJwksUri = discoveryConfig.jwksUri === void 0 || typeof discoveryConfig.jwksUri === "string" && discoveryConfig.jwksUri.length > 0;
1094
+ checks.push({
1095
+ name: "jwks_uri_present",
1096
+ ok: hasJwksUri,
1097
+ message: hasJwksUri ? void 0 : "jwksUri is empty."
1098
+ });
1099
+ const hasAudience = discoveryConfig.audience === void 0 || typeof discoveryConfig.audience === "string" || Array.isArray(discoveryConfig.audience) && discoveryConfig.audience.every((value) => typeof value === "string");
1100
+ checks.push({
1101
+ name: "audience_valid",
1102
+ ok: hasAudience,
1103
+ message: hasAudience ? void 0 : "audience must be a string or string array."
1104
+ });
1105
+ return {
1106
+ ok: checks.every((c) => c.ok),
1107
+ connectionId: connection._id,
1108
+ checks
1109
+ };
1110
+ }
1111
+ },
1112
+ scim,
1113
+ audit: { list: async (ctx, data) => {
1114
+ return await ctx.runQuery(config.component.connection.audit.list, data);
1115
+ } },
1116
+ webhook
1117
+ };
1118
+ }
1119
+
1120
+ //#endregion
1121
+ export { createGroupConnectionDomain };
1122
+ //# sourceMappingURL=domain.js.map