@hexclave/js 1.0.29 → 1.0.32

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 (53) hide show
  1. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
  2. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  3. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  4. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  5. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +4 -8
  6. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  7. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
  8. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +14 -0
  9. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  10. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -14
  11. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  12. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js +8 -1
  14. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  15. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  16. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  17. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  18. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.d.ts +13 -0
  19. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.d.ts.map +1 -1
  20. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.js.map +1 -1
  21. package/dist/esm/lib/hexclave-app/teams/index.d.ts +4 -0
  22. package/dist/esm/lib/hexclave-app/teams/index.d.ts.map +1 -1
  23. package/dist/esm/lib/hexclave-app/teams/index.js.map +1 -1
  24. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
  25. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  26. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  27. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  28. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +4 -8
  29. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  30. package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
  31. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +14 -0
  32. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  33. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -14
  34. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  35. package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  36. package/dist/lib/hexclave-app/apps/implementations/session-replay.js +8 -1
  37. package/dist/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  38. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  39. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  40. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  41. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +13 -0
  42. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts.map +1 -1
  43. package/dist/lib/hexclave-app/apps/interfaces/server-app.js.map +1 -1
  44. package/dist/lib/hexclave-app/teams/index.d.ts +4 -0
  45. package/dist/lib/hexclave-app/teams/index.d.ts.map +1 -1
  46. package/dist/lib/hexclave-app/teams/index.js.map +1 -1
  47. package/package.json +2 -2
  48. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +3 -5
  49. package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +33 -18
  50. package/src/lib/hexclave-app/apps/implementations/session-replay.ts +16 -1
  51. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
  52. package/src/lib/hexclave-app/apps/interfaces/server-app.ts +5 -0
  53. package/src/lib/hexclave-app/teams/index.ts +4 -0
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/session-replay.ts"],"mappings":";;;KAUY,sBAAA;;AAAZ;;;;EAME,OAAA;EAMA;;;;;EAAA,aAAA;EAiBU;;;;;;EAVV,UAAA,YAAsB,MAAA;EAqBU;;AAGlC;;;;EAjBE,aAAA;AAAA;AAAA,KAGU,gBAAA;EAcmG;;AAa/G;;;EArBE,OAAA;EAqB8C;;;;EAhB9C,OAAA,GAAU,sBAAA;AAAA;AAAA,iBAGI,uBAAA,CAAwB,gBAAA,EAAkB,gBAAA,eAA+B,sBAAA;;;;;;;iBAazE,sBAAA,CAAuB,OAAA,EAAS,gBAAA,eAA+B,gBAAA;AAkD/E;;;;AAAA,iBAhCgB,wBAAA,CAAyB,IAAA,EAAM,gBAAA,eAA+B,gBAAA;AAAA,KAgClE,aAAA;EACV,UAAA;EACA,aAAA;EACA,gBAAA;AAAA;AAAA,iBAGc,sBAAA,CAAuB,GAAA,kBAAqB,aAAA;AAAA,iBAc5C,cAAA,CAAe,SAAA;AAAA,iBAKf,oBAAA,CAAqB,SAAA;AAAA,iBAIrB,YAAA,CAAA;AAAA,iBAIA,kBAAA,CAAmB,OAAA;EAAW,GAAA;EAAa,SAAA;EAAoB,KAAA;AAAA,IAAkB,aAAA;AAAA,KAiBrF,mBAAA;EACV,SAAA;EACA,SAAA,GAAY,IAAA,UAAc,OAAA;IAAW,SAAA;EAAA,MAAyB,OAAA,CAAQ,MAAA,CAAO,QAAA,EAAU,KAAA;AAAA;AAAA,iBAGzE,0BAAA,CAA2B,KAAA;;;;AAtB3C;;iBA+BgB,uBAAA,CAAwB,KAAA;AAAA,cAU3B,eAAA;EAAA,QACH,QAAA;EAAA,QACA,UAAA;EAAA,QACA,SAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,WAAA;EAAA,QACA,OAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;EAAA,QACA,YAAA;EAAA,QACA,qBAAA;EAAA,QACA,eAAA;EAAA,QACA,gBAAA;EAAA,iBACS,uBAAA;EAAA,iBACA,WAAA;EAAA,iBAEA,iBAAA;EAAA,iBACA,KAAA;EAAA,iBACA,cAAA;cAEL,IAAA,EAAM,mBAAA,EAAqB,aAAA,EAAe,sBAAA;EA7CQ;;;EAwD9D,KAAA,CAAA;EAYA,IAAA,CAAA;EAWA,WAAA,CAAA;EAAA,QAMQ,gBAAA;EAAA,QASM,MAAA;EAAA,QAiFN,QAAA;EAAA,QAUM,eAAA;EAAA,QA+DN,qBAAA;EAAA,QAeA,KAAA;AAAA"}
1
+ {"version":3,"file":"session-replay.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/session-replay.ts"],"mappings":";;;KAUY,sBAAA;;AAAZ;;;;EAME,OAAA;EAMA;;;;;EAAA,aAAA;EAiBU;;;;;;EAVV,UAAA,YAAsB,MAAA;EAqBU;;AAGlC;;;;EAjBE,aAAA;AAAA;AAAA,KAGU,gBAAA;EAcmG;;AAa/G;;;EArBE,OAAA;EAqB8C;;;;EAhB9C,OAAA,GAAU,sBAAA;AAAA;AAAA,iBAGI,uBAAA,CAAwB,gBAAA,EAAkB,gBAAA,eAA+B,sBAAA;;;;;;;iBAazE,sBAAA,CAAuB,OAAA,EAAS,gBAAA,eAA+B,gBAAA;AAqD/E;;;;AAAA,iBAnCgB,wBAAA,CAAyB,IAAA,EAAM,gBAAA,eAA+B,gBAAA;AAAA,KAmClE,aAAA;EACV,UAAA;EACA,aAAA;EACA,gBAAA;AAAA;AAAA,iBAGc,sBAAA,CAAuB,GAAA,kBAAqB,aAAA;AAAA,iBAc5C,cAAA,CAAe,SAAA;AAAA,iBAKf,oBAAA,CAAqB,SAAA;AAAA,iBAIrB,YAAA,CAAA;AAAA,iBAIA,kBAAA,CAAmB,OAAA;EAAW,GAAA;EAAa,SAAA;EAAoB,KAAA;AAAA,IAAkB,aAAA;AAAA,KAiBrF,mBAAA;EACV,SAAA;EACA,SAAA,GAAY,IAAA,UAAc,OAAA;IAAW,SAAA;EAAA,MAAyB,OAAA,CAAQ,MAAA,CAAO,QAAA,EAAU,KAAA;AAAA;AAAA,iBAGzE,0BAAA,CAA2B,KAAA;;;;AAtB3C;;iBA+BgB,uBAAA,CAAwB,KAAA;AAAA,cAU3B,eAAA;EAAA,QACH,QAAA;EAAA,QACA,UAAA;EAAA,QACA,SAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,WAAA;EAAA,QACA,OAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;EAAA,QACA,YAAA;EAAA,QACA,qBAAA;EAAA,QACA,eAAA;EAAA,QACA,gBAAA;EAAA,iBACS,uBAAA;EAAA,iBACA,WAAA;EAAA,iBAEA,iBAAA;EAAA,iBACA,KAAA;EAAA,iBACA,cAAA;cAEL,IAAA,EAAM,mBAAA,EAAqB,aAAA,EAAe,sBAAA;EA7CQ;;;EAwD9D,KAAA,CAAA;EAYA,IAAA,CAAA;EAWA,WAAA,CAAA;EAAA,QAMQ,gBAAA;EAAA,QASM,MAAA;EAAA,QA4FN,QAAA;EAAA,QAUM,eAAA;EAAA,QAgEN,qBAAA;EAAA,QAeA,KAAA;AAAA"}
@@ -60,6 +60,7 @@ const FLUSH_INTERVAL_MS = 5e3;
60
60
  const MAX_EVENTS_PER_BATCH = 200;
61
61
  const MAX_APPROX_BYTES_PER_BATCH = 512e3;
62
62
  const MAX_FLUSH_PAYLOAD_BYTES = 9e5;
63
+ const textEncoder = new TextEncoder();
63
64
  function safeParseStoredSession(raw) {
64
65
  if (!raw) return null;
65
66
  try {
@@ -186,6 +187,12 @@ var SessionRecorder = class {
186
187
  try {
187
188
  let offset = 0;
188
189
  while (offset < allEvents.length) {
190
+ const firstSize = allSizes[offset] ?? (0, _hexclave_shared_dist_utils_errors.throwErr)("_eventSizes out of sync with _events — this should never happen");
191
+ if (firstSize > MAX_FLUSH_PAYLOAD_BYTES) {
192
+ (0, _hexclave_shared_dist_utils_errors.captureWarning)("SessionRecorder.flush", /* @__PURE__ */ new Error(`Dropping oversized session replay event (${firstSize} bytes > ${MAX_FLUSH_PAYLOAD_BYTES} byte limit); it cannot be sent without a 413.`));
193
+ offset += 1;
194
+ continue;
195
+ }
189
196
  let batchBytes = 0;
190
197
  let batchEnd = offset;
191
198
  for (let i = offset; i < allEvents.length; i++) {
@@ -258,7 +265,7 @@ var SessionRecorder = class {
258
265
  this._takingSnapshot = false;
259
266
  }
260
267
  }
261
- const eventSize = JSON.stringify(event).length;
268
+ const eventSize = textEncoder.encode(JSON.stringify(event)).byteLength;
262
269
  this._events.push(event);
263
270
  this._eventSizes.push(eventSize);
264
271
  this._approxBytes += eventSize;
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.js","names":["KnownErrors","Result"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/session-replay.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared/dist/known-errors\";\nimport { isBrowserLike } from \"@hexclave/shared/dist/utils/env\";\nimport { captureWarning, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\n\nexport type AnalyticsReplayOptions = {\n /**\n * Whether session replays are enabled.\n *\n * @default true\n */\n enabled?: boolean,\n /**\n * Whether to mask the content of all `<input>` elements.\n *\n * @default true\n */\n maskAllInputs?: boolean,\n /**\n * A CSS class name or RegExp. Elements with a matching class will be blocked\n * (replaced with a placeholder in the recording).\n *\n * @default undefined\n */\n blockClass?: string | RegExp,\n /**\n * A CSS selector string. Elements matching this selector will be blocked\n * (replaced with a placeholder in the recording).\n *\n * @default undefined\n */\n blockSelector?: string,\n};\n\nexport type AnalyticsOptions = {\n /**\n * Whether SDK-managed analytics capture is enabled.\n *\n * @default true\n */\n enabled?: boolean,\n /**\n * Options for session replay recording. Replays are enabled by default;\n * set `enabled: false` to opt out.\n */\n replays?: AnalyticsReplayOptions,\n};\n\nexport function getSessionReplayOptions(analyticsOptions: AnalyticsOptions | undefined): AnalyticsReplayOptions {\n return {\n ...analyticsOptions?.replays,\n enabled: analyticsOptions?.replays?.enabled ?? true,\n };\n}\n\n/**\n * Converts AnalyticsOptions to a JSON-safe representation.\n * RegExp blockClass values are serialized as `{ __regexp, __flags }` objects.\n * The return type is AnalyticsOptions to keep StackClientAppJson simple;\n * the actual runtime value is JSON-safe.\n */\nexport function analyticsOptionsToJson(options: AnalyticsOptions | undefined): AnalyticsOptions | undefined {\n if (!options?.replays?.blockClass) return options;\n const { blockClass, ...rest } = options.replays;\n if (!(blockClass instanceof RegExp)) return options;\n return {\n ...options,\n replays: {\n ...rest,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n blockClass: { __regexp: blockClass.source, __flags: blockClass.flags } as any,\n },\n };\n}\n\n/**\n * Reconstructs AnalyticsOptions from a JSON-deserialized value.\n * Converts `{ __regexp, __flags }` objects back to RegExp instances.\n */\nexport function analyticsOptionsFromJson(json: AnalyticsOptions | undefined): AnalyticsOptions | undefined {\n if (!json?.replays?.blockClass) return json;\n const { blockClass, ...rest } = json.replays;\n if (typeof blockClass === 'object' && '__regexp' in blockClass) {\n const bc = blockClass as unknown as { __regexp: string, __flags: string };\n return {\n ...json,\n replays: {\n ...rest,\n blockClass: new RegExp(bc.__regexp, bc.__flags),\n },\n };\n }\n return json;\n}\n\n// ---------- Recording internals ----------\n\n// Hexclave rebrand: canonical localStorage prefix (colon delimiters preserved).\nconst LOCAL_STORAGE_PREFIX = \"hexclave:session-replay:v1\";\n// Hexclave rebrand: legacy prefix — dual-read only, so a recording session active\n// across an SDK upgrade is not orphaned. Never written.\nconst LEGACY_LOCAL_STORAGE_PREFIX = \"stack:session-replay:v1\";\nconst IDLE_TTL_MS = 3 * 60 * 1000;\n\nconst FLUSH_INTERVAL_MS = 5_000;\nconst MAX_EVENTS_PER_BATCH = 200;\nconst MAX_APPROX_BYTES_PER_BATCH = 512_000;\n// The server rejects payloads > 1MB. Stay well under to account for JSON\n// envelope overhead (browser_session_id, timestamps, wrapper keys, etc.).\nconst MAX_FLUSH_PAYLOAD_BYTES = 900_000;\n\nexport type StoredSession = {\n session_id: string,\n created_at_ms: number,\n last_activity_ms: number,\n};\n\nexport function safeParseStoredSession(raw: string | null): StoredSession | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n if (typeof parsed.session_id !== \"string\") return null;\n if (typeof parsed.created_at_ms !== \"number\") return null;\n if (typeof parsed.last_activity_ms !== \"number\") return null;\n return parsed as StoredSession;\n } catch {\n return null;\n }\n}\n\nexport function makeStorageKey(projectId: string) {\n return `${LOCAL_STORAGE_PREFIX}:${projectId}`;\n}\n\n// Hexclave rebrand: legacy key, dual-read only (never written).\nexport function makeLegacyStorageKey(projectId: string) {\n return `${LEGACY_LOCAL_STORAGE_PREFIX}:${projectId}`;\n}\n\nexport function generateUuid() {\n return crypto.randomUUID();\n}\n\nexport function getOrRotateSession(options: { key: string, legacyKey?: string, nowMs: number }): StoredSession {\n // Hexclave rebrand: prefer the new key; fall back to the legacy key so a\n // recording session active across an SDK upgrade is not orphaned.\n const existing = safeParseStoredSession(localStorage.getItem(options.key))\n ?? (options.legacyKey ? safeParseStoredSession(localStorage.getItem(options.legacyKey)) : null);\n if (existing && options.nowMs - existing.last_activity_ms <= IDLE_TTL_MS) {\n return existing;\n }\n const next: StoredSession = {\n session_id: generateUuid(),\n created_at_ms: options.nowMs,\n last_activity_ms: options.nowMs,\n };\n localStorage.setItem(options.key, JSON.stringify(next));\n return next;\n}\n\nexport type SessionRecorderDeps = {\n projectId: string,\n sendBatch: (body: string, options: { keepalive: boolean }) => Promise<Result<Response, Error>>,\n};\n\nexport function isAnalyticsNotEnabledError(error: unknown): boolean {\n return KnownErrors.AnalyticsNotEnabled.isInstance(error);\n}\n\n/**\n * Whether the error looks like a network failure caused by an ad blocker or\n * similar extension blocking analytics requests. These are expected in\n * production and should be silently ignored rather than logged as warnings.\n */\nexport function isAdBlockerNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.includes(\"Failed to fetch\")\n || error.message.includes(\"NetworkError\")\n || error.message.includes(\"Load failed\")\n || error.message.includes(\"network connection\");\n }\n return false;\n}\n\nexport class SessionRecorder {\n private _started = false;\n private _cancelled = false;\n private _disabled = false;\n private _stopRecording: (() => void) | null = null;\n private _detachListeners: (() => void) | null = null;\n private _flushTimer: ReturnType<typeof setInterval> | null = null;\n private _events: unknown[] = [];\n private _eventSizes: number[] = [];\n private _approxBytes = 0;\n private _lastPersistActivity = 0;\n private _recording = false;\n private _rrwebModule: typeof import(\"rrweb\") | null = null;\n private _lastBrowserSessionId: string | null = null;\n private _takingSnapshot = false;\n private _flushInProgress = false;\n private readonly _sessionReplaySegmentId: string;\n private readonly _storageKey: string;\n // Hexclave rebrand: legacy key used for dual-read fallback only.\n private readonly _legacyStorageKey: string;\n private readonly _deps: SessionRecorderDeps;\n private readonly _replayOptions: AnalyticsReplayOptions;\n\n constructor(deps: SessionRecorderDeps, replayOptions: AnalyticsReplayOptions) {\n this._deps = deps;\n this._replayOptions = replayOptions;\n this._sessionReplaySegmentId = generateUuid();\n this._storageKey = makeStorageKey(deps.projectId);\n this._legacyStorageKey = makeLegacyStorageKey(deps.projectId);\n }\n\n /**\n * Starts recording. Idempotent — calling multiple times is safe.\n */\n start() {\n if (this._started) return;\n if (!isBrowserLike()) return;\n this._started = true;\n\n // Kick off rrweb recording\n runAsynchronously(() => this._startRecording(), { noErrorLogging: true });\n\n // Periodic flush\n this._flushTimer = setInterval(() => this._tick(), FLUSH_INTERVAL_MS);\n }\n\n stop() {\n this._cancelled = true;\n if (this._flushTimer !== null) {\n clearInterval(this._flushTimer);\n this._flushTimer = null;\n }\n // Flush remaining events before cleanup\n runAsynchronously(() => this._flush({ keepalive: true }));\n this._stopCurrentRecording();\n }\n\n clearBuffer() {\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n }\n\n private _persistActivity(nowMs: number): StoredSession {\n const stored = getOrRotateSession({ key: this._storageKey, legacyKey: this._legacyStorageKey, nowMs });\n if (nowMs - this._lastPersistActivity < 5_000) return stored;\n this._lastPersistActivity = nowMs;\n const updated: StoredSession = { ...stored, last_activity_ms: nowMs };\n localStorage.setItem(this._storageKey, JSON.stringify(updated));\n return stored;\n }\n\n private async _flush(options: { keepalive: boolean }) {\n if (this._disabled) return;\n if (this._events.length === 0) return;\n // Prevent concurrent in-flight HTTP requests. When a flush is already\n // in-flight, a second batch could race on the server (both call\n // findRecentSessionReplay before either upsert commits) and create\n // duplicate SessionReplay records. Events stay in _events and will be\n // picked up by the next tick or batch-size check.\n if (this._flushInProgress) return;\n\n const nowMs = Date.now();\n const stored = getOrRotateSession({ key: this._storageKey, legacyKey: this._legacyStorageKey, nowMs });\n\n // Capture all buffered events upfront (before any await) so that\n // stop() / _stopCurrentRecording() clearing this._events cannot race\n // with the async send loop below and silently discard overflow batches.\n const allEvents = this._events;\n const allSizes = this._eventSizes;\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n\n this._flushInProgress = true;\n try {\n let offset = 0;\n while (offset < allEvents.length) {\n // Build a batch that fits under the server's payload limit.\n // When _flushInProgress blocked earlier flushes, events can accumulate\n // well past MAX_APPROX_BYTES_PER_BATCH; sending them all at once would\n // exceed the server's 1MB body limit (413).\n let batchBytes = 0;\n let batchEnd = offset;\n for (let i = offset; i < allEvents.length; i++) {\n const nextSize = allSizes[i] ?? throwErr(\"_eventSizes out of sync with _events — this should never happen\");\n if (batchBytes + nextSize > MAX_FLUSH_PAYLOAD_BYTES && batchEnd > offset) break;\n batchBytes += nextSize;\n batchEnd = i + 1;\n }\n\n const batchEvents = allEvents.slice(offset, batchEnd);\n offset = batchEnd;\n\n const batchId = generateUuid();\n const payload = {\n browser_session_id: stored.session_id,\n session_replay_segment_id: this._sessionReplaySegmentId,\n batch_id: batchId,\n started_at_ms: stored.created_at_ms,\n sent_at_ms: nowMs,\n events: batchEvents,\n };\n\n const res = await this._deps.sendBatch(\n JSON.stringify(payload),\n { keepalive: options.keepalive },\n );\n\n if (res.status === \"error\") {\n if (isAnalyticsNotEnabledError(res.error)) {\n this._disable();\n return;\n }\n // Ad blockers commonly block analytics endpoints, causing network\n // errors. These are expected and should not pollute the console.\n if (isAdBlockerNetworkError(res.error)) {\n return;\n }\n captureWarning(\"SessionRecorder.flush\", res.error);\n return;\n }\n\n if (!res.data.ok) {\n captureWarning(\"SessionRecorder.flush\", new Error(`SessionRecorder flush failed: ${res.data.status} ${await res.data.text()}`));\n return;\n }\n }\n } finally {\n this._flushInProgress = false;\n }\n }\n\n private _disable() {\n this._disabled = true;\n this.clearBuffer();\n if (this._flushTimer !== null) {\n clearInterval(this._flushTimer);\n this._flushTimer = null;\n }\n this._stopCurrentRecording();\n }\n\n private async _startRecording() {\n if (this._recording || this._cancelled) return;\n\n if (!this._rrwebModule) {\n const rrwebImport = await Result.fromPromise(import(\"rrweb\"));\n if (rrwebImport.status === \"error\") {\n console.warn(\"SessionRecorder: rrweb import failed. Is rrweb installed?\", rrwebImport.error);\n return;\n }\n this._rrwebModule = rrwebImport.data;\n }\n\n // cancelled may change during the await above\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (this._cancelled) return;\n\n this._stopRecording = this._rrwebModule.record({\n emit: (event) => {\n const nowMs = Date.now();\n const stored = this._persistActivity(nowMs);\n\n // Detect session rotation: after 3+ minutes idle, getOrRotateSession\n // creates a new session ID. We need to inject a FullSnapshot so the\n // new server-side SessionReplay record is playable.\n if (this._lastBrowserSessionId === null) {\n this._lastBrowserSessionId = stored.session_id;\n } else if (stored.session_id !== this._lastBrowserSessionId && !this._takingSnapshot) {\n this._lastBrowserSessionId = stored.session_id;\n // Inject a FullSnapshot for the new session (calls emit synchronously)\n this._takingSnapshot = true;\n try {\n this._rrwebModule!.record.takeFullSnapshot();\n } finally {\n this._takingSnapshot = false;\n }\n }\n\n const eventSize = JSON.stringify(event).length;\n this._events.push(event);\n this._eventSizes.push(eventSize);\n this._approxBytes += eventSize;\n if (this._events.length >= MAX_EVENTS_PER_BATCH || this._approxBytes >= MAX_APPROX_BYTES_PER_BATCH) {\n runAsynchronously(() => this._flush({ keepalive: false }));\n }\n },\n maskAllInputs: this._replayOptions.maskAllInputs ?? true,\n ...(this._replayOptions.blockClass !== undefined ? { blockClass: this._replayOptions.blockClass } : {}),\n ...(this._replayOptions.blockSelector !== undefined ? { blockSelector: this._replayOptions.blockSelector } : {}),\n }) ?? null;\n\n this._recording = true;\n\n const onPageHide = () => {\n runAsynchronously(() => this._flush({ keepalive: true }));\n };\n window.addEventListener(\"pagehide\", onPageHide);\n document.addEventListener(\"visibilitychange\", onPageHide);\n this._detachListeners = () => {\n window.removeEventListener(\"pagehide\", onPageHide);\n document.removeEventListener(\"visibilitychange\", onPageHide);\n };\n }\n\n private _stopCurrentRecording() {\n if (this._detachListeners) {\n this._detachListeners();\n this._detachListeners = null;\n }\n if (this._stopRecording) {\n this._stopRecording();\n this._stopRecording = null;\n }\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n this._recording = false;\n }\n\n private _tick() {\n if (this._cancelled) return;\n if (this._events.length > 0) {\n runAsynchronously(() => this._flush({ keepalive: false }));\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session-replay.js","names":["KnownErrors","Result"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/session-replay.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared/dist/known-errors\";\nimport { isBrowserLike } from \"@hexclave/shared/dist/utils/env\";\nimport { captureWarning, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\n\nexport type AnalyticsReplayOptions = {\n /**\n * Whether session replays are enabled.\n *\n * @default true\n */\n enabled?: boolean,\n /**\n * Whether to mask the content of all `<input>` elements.\n *\n * @default true\n */\n maskAllInputs?: boolean,\n /**\n * A CSS class name or RegExp. Elements with a matching class will be blocked\n * (replaced with a placeholder in the recording).\n *\n * @default undefined\n */\n blockClass?: string | RegExp,\n /**\n * A CSS selector string. Elements matching this selector will be blocked\n * (replaced with a placeholder in the recording).\n *\n * @default undefined\n */\n blockSelector?: string,\n};\n\nexport type AnalyticsOptions = {\n /**\n * Whether SDK-managed analytics capture is enabled.\n *\n * @default true\n */\n enabled?: boolean,\n /**\n * Options for session replay recording. Replays are enabled by default;\n * set `enabled: false` to opt out.\n */\n replays?: AnalyticsReplayOptions,\n};\n\nexport function getSessionReplayOptions(analyticsOptions: AnalyticsOptions | undefined): AnalyticsReplayOptions {\n return {\n ...analyticsOptions?.replays,\n enabled: analyticsOptions?.replays?.enabled ?? true,\n };\n}\n\n/**\n * Converts AnalyticsOptions to a JSON-safe representation.\n * RegExp blockClass values are serialized as `{ __regexp, __flags }` objects.\n * The return type is AnalyticsOptions to keep StackClientAppJson simple;\n * the actual runtime value is JSON-safe.\n */\nexport function analyticsOptionsToJson(options: AnalyticsOptions | undefined): AnalyticsOptions | undefined {\n if (!options?.replays?.blockClass) return options;\n const { blockClass, ...rest } = options.replays;\n if (!(blockClass instanceof RegExp)) return options;\n return {\n ...options,\n replays: {\n ...rest,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n blockClass: { __regexp: blockClass.source, __flags: blockClass.flags } as any,\n },\n };\n}\n\n/**\n * Reconstructs AnalyticsOptions from a JSON-deserialized value.\n * Converts `{ __regexp, __flags }` objects back to RegExp instances.\n */\nexport function analyticsOptionsFromJson(json: AnalyticsOptions | undefined): AnalyticsOptions | undefined {\n if (!json?.replays?.blockClass) return json;\n const { blockClass, ...rest } = json.replays;\n if (typeof blockClass === 'object' && '__regexp' in blockClass) {\n const bc = blockClass as unknown as { __regexp: string, __flags: string };\n return {\n ...json,\n replays: {\n ...rest,\n blockClass: new RegExp(bc.__regexp, bc.__flags),\n },\n };\n }\n return json;\n}\n\n// ---------- Recording internals ----------\n\n// Hexclave rebrand: canonical localStorage prefix (colon delimiters preserved).\nconst LOCAL_STORAGE_PREFIX = \"hexclave:session-replay:v1\";\n// Hexclave rebrand: legacy prefix — dual-read only, so a recording session active\n// across an SDK upgrade is not orphaned. Never written.\nconst LEGACY_LOCAL_STORAGE_PREFIX = \"stack:session-replay:v1\";\nconst IDLE_TTL_MS = 3 * 60 * 1000;\n\nconst FLUSH_INTERVAL_MS = 5_000;\nconst MAX_EVENTS_PER_BATCH = 200;\nconst MAX_APPROX_BYTES_PER_BATCH = 512_000;\n// The server rejects payloads > 1MB. Stay well under to account for JSON\n// envelope overhead (browser_session_id, timestamps, wrapper keys, etc.).\nconst MAX_FLUSH_PAYLOAD_BYTES = 900_000;\n\n// Reused across the emit hot path to avoid per-event allocation.\nconst textEncoder = new TextEncoder();\n\nexport type StoredSession = {\n session_id: string,\n created_at_ms: number,\n last_activity_ms: number,\n};\n\nexport function safeParseStoredSession(raw: string | null): StoredSession | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n if (typeof parsed.session_id !== \"string\") return null;\n if (typeof parsed.created_at_ms !== \"number\") return null;\n if (typeof parsed.last_activity_ms !== \"number\") return null;\n return parsed as StoredSession;\n } catch {\n return null;\n }\n}\n\nexport function makeStorageKey(projectId: string) {\n return `${LOCAL_STORAGE_PREFIX}:${projectId}`;\n}\n\n// Hexclave rebrand: legacy key, dual-read only (never written).\nexport function makeLegacyStorageKey(projectId: string) {\n return `${LEGACY_LOCAL_STORAGE_PREFIX}:${projectId}`;\n}\n\nexport function generateUuid() {\n return crypto.randomUUID();\n}\n\nexport function getOrRotateSession(options: { key: string, legacyKey?: string, nowMs: number }): StoredSession {\n // Hexclave rebrand: prefer the new key; fall back to the legacy key so a\n // recording session active across an SDK upgrade is not orphaned.\n const existing = safeParseStoredSession(localStorage.getItem(options.key))\n ?? (options.legacyKey ? safeParseStoredSession(localStorage.getItem(options.legacyKey)) : null);\n if (existing && options.nowMs - existing.last_activity_ms <= IDLE_TTL_MS) {\n return existing;\n }\n const next: StoredSession = {\n session_id: generateUuid(),\n created_at_ms: options.nowMs,\n last_activity_ms: options.nowMs,\n };\n localStorage.setItem(options.key, JSON.stringify(next));\n return next;\n}\n\nexport type SessionRecorderDeps = {\n projectId: string,\n sendBatch: (body: string, options: { keepalive: boolean }) => Promise<Result<Response, Error>>,\n};\n\nexport function isAnalyticsNotEnabledError(error: unknown): boolean {\n return KnownErrors.AnalyticsNotEnabled.isInstance(error);\n}\n\n/**\n * Whether the error looks like a network failure caused by an ad blocker or\n * similar extension blocking analytics requests. These are expected in\n * production and should be silently ignored rather than logged as warnings.\n */\nexport function isAdBlockerNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.includes(\"Failed to fetch\")\n || error.message.includes(\"NetworkError\")\n || error.message.includes(\"Load failed\")\n || error.message.includes(\"network connection\");\n }\n return false;\n}\n\nexport class SessionRecorder {\n private _started = false;\n private _cancelled = false;\n private _disabled = false;\n private _stopRecording: (() => void) | null = null;\n private _detachListeners: (() => void) | null = null;\n private _flushTimer: ReturnType<typeof setInterval> | null = null;\n private _events: unknown[] = [];\n private _eventSizes: number[] = [];\n private _approxBytes = 0;\n private _lastPersistActivity = 0;\n private _recording = false;\n private _rrwebModule: typeof import(\"rrweb\") | null = null;\n private _lastBrowserSessionId: string | null = null;\n private _takingSnapshot = false;\n private _flushInProgress = false;\n private readonly _sessionReplaySegmentId: string;\n private readonly _storageKey: string;\n // Hexclave rebrand: legacy key used for dual-read fallback only.\n private readonly _legacyStorageKey: string;\n private readonly _deps: SessionRecorderDeps;\n private readonly _replayOptions: AnalyticsReplayOptions;\n\n constructor(deps: SessionRecorderDeps, replayOptions: AnalyticsReplayOptions) {\n this._deps = deps;\n this._replayOptions = replayOptions;\n this._sessionReplaySegmentId = generateUuid();\n this._storageKey = makeStorageKey(deps.projectId);\n this._legacyStorageKey = makeLegacyStorageKey(deps.projectId);\n }\n\n /**\n * Starts recording. Idempotent — calling multiple times is safe.\n */\n start() {\n if (this._started) return;\n if (!isBrowserLike()) return;\n this._started = true;\n\n // Kick off rrweb recording\n runAsynchronously(() => this._startRecording(), { noErrorLogging: true });\n\n // Periodic flush\n this._flushTimer = setInterval(() => this._tick(), FLUSH_INTERVAL_MS);\n }\n\n stop() {\n this._cancelled = true;\n if (this._flushTimer !== null) {\n clearInterval(this._flushTimer);\n this._flushTimer = null;\n }\n // Flush remaining events before cleanup\n runAsynchronously(() => this._flush({ keepalive: true }));\n this._stopCurrentRecording();\n }\n\n clearBuffer() {\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n }\n\n private _persistActivity(nowMs: number): StoredSession {\n const stored = getOrRotateSession({ key: this._storageKey, legacyKey: this._legacyStorageKey, nowMs });\n if (nowMs - this._lastPersistActivity < 5_000) return stored;\n this._lastPersistActivity = nowMs;\n const updated: StoredSession = { ...stored, last_activity_ms: nowMs };\n localStorage.setItem(this._storageKey, JSON.stringify(updated));\n return stored;\n }\n\n private async _flush(options: { keepalive: boolean }) {\n if (this._disabled) return;\n if (this._events.length === 0) return;\n // Prevent concurrent in-flight HTTP requests. When a flush is already\n // in-flight, a second batch could race on the server (both call\n // findRecentSessionReplay before either upsert commits) and create\n // duplicate SessionReplay records. Events stay in _events and will be\n // picked up by the next tick or batch-size check.\n if (this._flushInProgress) return;\n\n const nowMs = Date.now();\n const stored = getOrRotateSession({ key: this._storageKey, legacyKey: this._legacyStorageKey, nowMs });\n\n // Capture all buffered events upfront (before any await) so that\n // stop() / _stopCurrentRecording() clearing this._events cannot race\n // with the async send loop below and silently discard overflow batches.\n const allEvents = this._events;\n const allSizes = this._eventSizes;\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n\n this._flushInProgress = true;\n try {\n let offset = 0;\n while (offset < allEvents.length) {\n // Build a batch that fits under the server's payload limit.\n // When _flushInProgress blocked earlier flushes, events can accumulate\n // well past MAX_APPROX_BYTES_PER_BATCH; sending them all at once would\n // exceed the server's 1MB body limit (413).\n // A single event over the limit can't be sent (rrweb events aren't splittable); drop it and move on.\n const firstSize = allSizes[offset] ?? throwErr(\"_eventSizes out of sync with _events — this should never happen\");\n if (firstSize > MAX_FLUSH_PAYLOAD_BYTES) {\n captureWarning(\n \"SessionRecorder.flush\",\n new Error(`Dropping oversized session replay event (${firstSize} bytes > ${MAX_FLUSH_PAYLOAD_BYTES} byte limit); it cannot be sent without a 413.`),\n );\n offset += 1;\n continue;\n }\n\n let batchBytes = 0;\n let batchEnd = offset;\n for (let i = offset; i < allEvents.length; i++) {\n const nextSize = allSizes[i] ?? throwErr(\"_eventSizes out of sync with _events — this should never happen\");\n if (batchBytes + nextSize > MAX_FLUSH_PAYLOAD_BYTES && batchEnd > offset) break;\n batchBytes += nextSize;\n batchEnd = i + 1;\n }\n\n const batchEvents = allEvents.slice(offset, batchEnd);\n offset = batchEnd;\n\n const batchId = generateUuid();\n const payload = {\n browser_session_id: stored.session_id,\n session_replay_segment_id: this._sessionReplaySegmentId,\n batch_id: batchId,\n started_at_ms: stored.created_at_ms,\n sent_at_ms: nowMs,\n events: batchEvents,\n };\n\n const res = await this._deps.sendBatch(\n JSON.stringify(payload),\n { keepalive: options.keepalive },\n );\n\n if (res.status === \"error\") {\n if (isAnalyticsNotEnabledError(res.error)) {\n this._disable();\n return;\n }\n // Ad blockers commonly block analytics endpoints, causing network\n // errors. These are expected and should not pollute the console.\n if (isAdBlockerNetworkError(res.error)) {\n return;\n }\n captureWarning(\"SessionRecorder.flush\", res.error);\n return;\n }\n\n if (!res.data.ok) {\n captureWarning(\"SessionRecorder.flush\", new Error(`SessionRecorder flush failed: ${res.data.status} ${await res.data.text()}`));\n return;\n }\n }\n } finally {\n this._flushInProgress = false;\n }\n }\n\n private _disable() {\n this._disabled = true;\n this.clearBuffer();\n if (this._flushTimer !== null) {\n clearInterval(this._flushTimer);\n this._flushTimer = null;\n }\n this._stopCurrentRecording();\n }\n\n private async _startRecording() {\n if (this._recording || this._cancelled) return;\n\n if (!this._rrwebModule) {\n const rrwebImport = await Result.fromPromise(import(\"rrweb\"));\n if (rrwebImport.status === \"error\") {\n console.warn(\"SessionRecorder: rrweb import failed. Is rrweb installed?\", rrwebImport.error);\n return;\n }\n this._rrwebModule = rrwebImport.data;\n }\n\n // cancelled may change during the await above\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (this._cancelled) return;\n\n this._stopRecording = this._rrwebModule.record({\n emit: (event) => {\n const nowMs = Date.now();\n const stored = this._persistActivity(nowMs);\n\n // Detect session rotation: after 3+ minutes idle, getOrRotateSession\n // creates a new session ID. We need to inject a FullSnapshot so the\n // new server-side SessionReplay record is playable.\n if (this._lastBrowserSessionId === null) {\n this._lastBrowserSessionId = stored.session_id;\n } else if (stored.session_id !== this._lastBrowserSessionId && !this._takingSnapshot) {\n this._lastBrowserSessionId = stored.session_id;\n // Inject a FullSnapshot for the new session (calls emit synchronously)\n this._takingSnapshot = true;\n try {\n this._rrwebModule!.record.takeFullSnapshot();\n } finally {\n this._takingSnapshot = false;\n }\n }\n\n // Measure UTF-8 byte length to match the server's byte limit (.length counts UTF-16 units, undercounting multibyte content).\n const eventSize = textEncoder.encode(JSON.stringify(event)).byteLength;\n this._events.push(event);\n this._eventSizes.push(eventSize);\n this._approxBytes += eventSize;\n if (this._events.length >= MAX_EVENTS_PER_BATCH || this._approxBytes >= MAX_APPROX_BYTES_PER_BATCH) {\n runAsynchronously(() => this._flush({ keepalive: false }));\n }\n },\n maskAllInputs: this._replayOptions.maskAllInputs ?? true,\n ...(this._replayOptions.blockClass !== undefined ? { blockClass: this._replayOptions.blockClass } : {}),\n ...(this._replayOptions.blockSelector !== undefined ? { blockSelector: this._replayOptions.blockSelector } : {}),\n }) ?? null;\n\n this._recording = true;\n\n const onPageHide = () => {\n runAsynchronously(() => this._flush({ keepalive: true }));\n };\n window.addEventListener(\"pagehide\", onPageHide);\n document.addEventListener(\"visibilitychange\", onPageHide);\n this._detachListeners = () => {\n window.removeEventListener(\"pagehide\", onPageHide);\n document.removeEventListener(\"visibilitychange\", onPageHide);\n };\n }\n\n private _stopCurrentRecording() {\n if (this._detachListeners) {\n this._detachListeners();\n this._detachListeners = null;\n }\n if (this._stopRecording) {\n this._stopRecording();\n this._stopRecording = null;\n }\n this._events = [];\n this._eventSizes = [];\n this._approxBytes = 0;\n this._recording = false;\n }\n\n private _tick() {\n if (this._cancelled) return;\n if (this._events.length > 0) {\n runAsynchronously(() => this._flush({ keepalive: false }));\n }\n }\n}\n"],"mappings":"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"}
@@ -182,6 +182,7 @@ type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends s
182
182
  accessToken: string;
183
183
  refreshToken: string;
184
184
  }): Promise<void>;
185
+ awaitPendingAuthResolutions(): Promise<void>;
185
186
  };
186
187
  } & AsyncStoreProperty<"project", [], Project, false> & AsyncStoreProperty<"item", [{
187
188
  itemId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"client-app.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"mappings":"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"}
1
+ {"version":3,"file":"client-app.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client-app.js","names":["_HexclaveClientAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { CurrentUserCrud } from \"@hexclave/shared/dist/interface/crud/current-user\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { AsyncStoreProperty, AuthLike, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol, TokenStoreInit } from \"../../common\";\nimport type { RequestListener } from \"@hexclave/shared/dist/interface/client-interface\";\nimport { CustomerInvoicesList, CustomerInvoicesRequestOptions, CustomerProductsList, CustomerProductsRequestOptions, Item } from \"../../customers\";\nimport { Project } from \"../../projects\";\nimport { ProjectCurrentUser, SyncedPartialUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveClientAppImpl } from \"../implementations\";\nimport { AnalyticsOptions } from \"../implementations/session-replay\";\n\n/** @deprecated Use `HexclaveClientAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = {\n baseUrl?: string | { browser: string, server: string },\n extraRequestHeaders?: Record<string, string>,\n projectId?: ProjectId,\n publishableClientKey?: string,\n urls?: HandlerUrlOptions,\n oauthScopesOnSignIn?: Partial<OAuthScopesOnSignIn>,\n tokenStore?: TokenStoreInit<HasTokenStore>,\n redirectMethod?: RedirectMethod,\n inheritsFrom?: StackClientApp<any, any>,\n\n /**\n * Whether to show the Hexclave dev tool indicator in browser-like environments.\n *\n * - `true`: always show\n * - `false`: never show\n * - `\"auto\"` (default): show based on NODE_ENV or origin heuristics\n */\n devTool?: boolean | \"auto\",\n\n /**\n * By default, the Stack app will automatically prefetch some data from Stack's server when this app is first\n * constructed. This improves the performance of your app, but will create network requests that are unnecessary if\n * the app is never used or disposed of immediately. To disable this behavior, set this option to true.\n */\n noAutomaticPrefetch?: boolean,\n\n /**\n * Options for analytics and session recording. Replays are enabled by default;\n * set `{ replays: { enabled: false } }` to opt out.\n */\n analytics?: AnalyticsOptions,\n} & (\n { tokenStore: TokenStoreInit<HasTokenStore> } | { tokenStore?: undefined, inheritsFrom: StackClientApp<HasTokenStore, any> }\n) & (\n string extends ProjectId ? unknown : ({ projectId: ProjectId } | { inheritsFrom: StackClientApp<any, ProjectId> })\n);\n\n\n/** @deprecated Use `HexclaveClientAppJson` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined } & {\n uniqueIdentifier: string,\n // note: if you add more fields here, make sure to ensure the checkString in the constructor has/doesn't have them\n};\n\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n readonly projectId: ProjectId,\n\n /**\n * The version of the Hexclave SDK.\n */\n readonly version: string,\n\n /**\n * @deprecated Do not use `app.urls` for navigation. It is static and does not include runtime redirect-back,\n * cross-domain auth, or sign-out state. Use the matching `redirectToXyz()` method instead, for example\n * `redirectToSignIn()`, `redirectToSignUp()`, `redirectToSignOut()`, or `redirectToAccountSettings()`.\n */\n readonly urls: Readonly<ResolvedHandlerUrls>,\n\n signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise<void>,\n signInWithCredential(options: { email: string, password: string, noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"EmailPasswordMismatch\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signUpWithCredential(options: {\n email: string,\n password: string,\n noRedirect?: boolean,\n } & ({ noVerificationCallback: true } | { noVerificationCallback?: false, verificationCallbackUrl?: string })): Promise<Result<undefined, KnownErrors[\"UserWithEmailAlreadyExists\"] | KnownErrors[\"PasswordRequirementsNotMet\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n signInWithPasskey(): Promise<Result<undefined, KnownErrors[\"PasskeyAuthenticationFailed\"] | KnownErrors[\"InvalidTotpCode\"] | KnownErrors[\"PasskeyWebAuthnError\"]>>,\n callOAuthCallback(): Promise<boolean>,\n promptCliLogin(options: { appUrl: string, expiresInMillis?: number, anonRefreshToken?: string, promptLink?: (url: string, loginCode: string) => void }): Promise<Result<string, KnownErrors[\"CliAuthError\"] | KnownErrors[\"CliAuthExpiredError\"] | KnownErrors[\"CliAuthUsedError\"]>>,\n sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<undefined, KnownErrors[\"UserNotFound\"]>>,\n sendMagicLinkEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<{ nonce: string }, KnownErrors[\"RedirectUrlNotWhitelisted\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n resetPassword(options: { code: string, password: string }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyPasswordResetCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyTeamInvitationCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n acceptTeamInvitation(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n getTeamInvitationDetails(code: string): Promise<Result<{ teamDisplayName: string }, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n verifyEmail(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n signInWithMagicLink(code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signInWithMfa(otp: string, code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n\n redirectToOAuthCallback(): Promise<void>,\n\n getConvexClientAuth(options: HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }): (args: { forceRefreshToken: boolean }) => Promise<string | null>,\n getConvexHttpClientAuth(options: { tokenStore: TokenStoreInit }): Promise<string>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentUser<ProjectId> | null>,\n\n cancelSubscription(options: { productId: string, subscriptionId?: string } | { productId: string, subscriptionId?: string, teamId: string }): Promise<void>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialUser | TokenPartialUser | null>,\n\n [hexclaveAppInternalsSymbol]: {\n toClientJson(): StackClientAppJson<HasTokenStore, ProjectId>,\n setCurrentUser(userJsonPromise: Promise<CurrentUserCrud['Client']['Read'] | null>): void,\n getConstructorOptions(): StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined },\n sendSessionReplayBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n sendAnalyticsEventBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n addRequestListener(listener: RequestListener): () => void,\n sendRequest(path: string, requestOptions: RequestInit, requestType?: \"client\" | \"server\" | \"admin\"): Promise<Response>,\n getUrls(): Readonly<ResolvedHandlerUrls>,\n getRedirectMethod(): RedirectMethod,\n redirectToUrl(url: string | URL, options?: { replace?: boolean }): Promise<void>,\n redirectToHandler(handlerName: keyof HandlerUrls, options?: RedirectToOptions): Promise<void>,\n signInWithTokens(tokens: { accessToken: string, refreshToken: string }): Promise<void>,\n },\n }\n & AsyncStoreProperty<\"project\", [], Project, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n Item,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & AsyncStoreProperty<\n \"invoices\",\n [options: CustomerInvoicesRequestOptions],\n CustomerInvoicesList,\n true\n >\n & { [K in `redirectTo${Capitalize<keyof Omit<HandlerUrls, 'handler' | 'oauthCallback'>>}`]: (options?: RedirectToOptions) => Promise<void> }\n & AuthLike<HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }>\n);\n/** @deprecated Use `HexclaveClientAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackClientAppConstructorOptions<HasTokenStore, ProjectId>): StackClientApp<HasTokenStore, ProjectId>,\n new(options: StackClientAppConstructorOptions<boolean, string>): StackClientApp<boolean, string>,\n\n [hexclaveAppInternalsSymbol]: {\n fromClientJson<HasTokenStore extends boolean, ProjectId extends string>(\n json: StackClientAppJson<HasTokenStore, ProjectId>\n ): StackClientApp<HasTokenStore, ProjectId>,\n },\n};\nexport type HexclaveClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppJson<HasTokenStore, ProjectId>;\nexport type HexclaveClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackClientApp<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppConstructor = StackClientAppConstructor;\nexport const HexclaveClientApp: HexclaveClientAppConstructor = _HexclaveClientAppImpl;\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackClientApp: StackClientAppConstructor = HexclaveClientApp;\n"],"mappings":";;;;;AA6KA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
1
+ {"version":3,"file":"client-app.js","names":["_HexclaveClientAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { CurrentUserCrud } from \"@hexclave/shared/dist/interface/crud/current-user\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { AsyncStoreProperty, AuthLike, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol, TokenStoreInit } from \"../../common\";\nimport type { RequestListener } from \"@hexclave/shared/dist/interface/client-interface\";\nimport { CustomerInvoicesList, CustomerInvoicesRequestOptions, CustomerProductsList, CustomerProductsRequestOptions, Item } from \"../../customers\";\nimport { Project } from \"../../projects\";\nimport { ProjectCurrentUser, SyncedPartialUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveClientAppImpl } from \"../implementations\";\nimport { AnalyticsOptions } from \"../implementations/session-replay\";\n\n/** @deprecated Use `HexclaveClientAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = {\n baseUrl?: string | { browser: string, server: string },\n extraRequestHeaders?: Record<string, string>,\n projectId?: ProjectId,\n publishableClientKey?: string,\n urls?: HandlerUrlOptions,\n oauthScopesOnSignIn?: Partial<OAuthScopesOnSignIn>,\n tokenStore?: TokenStoreInit<HasTokenStore>,\n redirectMethod?: RedirectMethod,\n inheritsFrom?: StackClientApp<any, any>,\n\n /**\n * Whether to show the Hexclave dev tool indicator in browser-like environments.\n *\n * - `true`: always show\n * - `false`: never show\n * - `\"auto\"` (default): show based on NODE_ENV or origin heuristics\n */\n devTool?: boolean | \"auto\",\n\n /**\n * By default, the Stack app will automatically prefetch some data from Stack's server when this app is first\n * constructed. This improves the performance of your app, but will create network requests that are unnecessary if\n * the app is never used or disposed of immediately. To disable this behavior, set this option to true.\n */\n noAutomaticPrefetch?: boolean,\n\n /**\n * Options for analytics and session recording. Replays are enabled by default;\n * set `{ replays: { enabled: false } }` to opt out.\n */\n analytics?: AnalyticsOptions,\n} & (\n { tokenStore: TokenStoreInit<HasTokenStore> } | { tokenStore?: undefined, inheritsFrom: StackClientApp<HasTokenStore, any> }\n) & (\n string extends ProjectId ? unknown : ({ projectId: ProjectId } | { inheritsFrom: StackClientApp<any, ProjectId> })\n);\n\n\n/** @deprecated Use `HexclaveClientAppJson` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined } & {\n uniqueIdentifier: string,\n // note: if you add more fields here, make sure to ensure the checkString in the constructor has/doesn't have them\n};\n\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n readonly projectId: ProjectId,\n\n /**\n * The version of the Hexclave SDK.\n */\n readonly version: string,\n\n /**\n * @deprecated Do not use `app.urls` for navigation. It is static and does not include runtime redirect-back,\n * cross-domain auth, or sign-out state. Use the matching `redirectToXyz()` method instead, for example\n * `redirectToSignIn()`, `redirectToSignUp()`, `redirectToSignOut()`, or `redirectToAccountSettings()`.\n */\n readonly urls: Readonly<ResolvedHandlerUrls>,\n\n signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise<void>,\n signInWithCredential(options: { email: string, password: string, noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"EmailPasswordMismatch\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signUpWithCredential(options: {\n email: string,\n password: string,\n noRedirect?: boolean,\n } & ({ noVerificationCallback: true } | { noVerificationCallback?: false, verificationCallbackUrl?: string })): Promise<Result<undefined, KnownErrors[\"UserWithEmailAlreadyExists\"] | KnownErrors[\"PasswordRequirementsNotMet\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n signInWithPasskey(): Promise<Result<undefined, KnownErrors[\"PasskeyAuthenticationFailed\"] | KnownErrors[\"InvalidTotpCode\"] | KnownErrors[\"PasskeyWebAuthnError\"]>>,\n callOAuthCallback(): Promise<boolean>,\n promptCliLogin(options: { appUrl: string, expiresInMillis?: number, anonRefreshToken?: string, promptLink?: (url: string, loginCode: string) => void }): Promise<Result<string, KnownErrors[\"CliAuthError\"] | KnownErrors[\"CliAuthExpiredError\"] | KnownErrors[\"CliAuthUsedError\"]>>,\n sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<undefined, KnownErrors[\"UserNotFound\"]>>,\n sendMagicLinkEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<{ nonce: string }, KnownErrors[\"RedirectUrlNotWhitelisted\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n resetPassword(options: { code: string, password: string }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyPasswordResetCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyTeamInvitationCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n acceptTeamInvitation(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n getTeamInvitationDetails(code: string): Promise<Result<{ teamDisplayName: string }, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n verifyEmail(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n signInWithMagicLink(code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signInWithMfa(otp: string, code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n\n redirectToOAuthCallback(): Promise<void>,\n\n getConvexClientAuth(options: HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }): (args: { forceRefreshToken: boolean }) => Promise<string | null>,\n getConvexHttpClientAuth(options: { tokenStore: TokenStoreInit }): Promise<string>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentUser<ProjectId> | null>,\n\n cancelSubscription(options: { productId: string, subscriptionId?: string } | { productId: string, subscriptionId?: string, teamId: string }): Promise<void>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialUser | TokenPartialUser | null>,\n\n [hexclaveAppInternalsSymbol]: {\n toClientJson(): StackClientAppJson<HasTokenStore, ProjectId>,\n setCurrentUser(userJsonPromise: Promise<CurrentUserCrud['Client']['Read'] | null>): void,\n getConstructorOptions(): StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined },\n sendSessionReplayBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n sendAnalyticsEventBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n addRequestListener(listener: RequestListener): () => void,\n sendRequest(path: string, requestOptions: RequestInit, requestType?: \"client\" | \"server\" | \"admin\"): Promise<Response>,\n getUrls(): Readonly<ResolvedHandlerUrls>,\n getRedirectMethod(): RedirectMethod,\n redirectToUrl(url: string | URL, options?: { replace?: boolean }): Promise<void>,\n redirectToHandler(handlerName: keyof HandlerUrls, options?: RedirectToOptions): Promise<void>,\n signInWithTokens(tokens: { accessToken: string, refreshToken: string }): Promise<void>,\n awaitPendingAuthResolutions(): Promise<void>,\n },\n }\n & AsyncStoreProperty<\"project\", [], Project, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n Item,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & AsyncStoreProperty<\n \"invoices\",\n [options: CustomerInvoicesRequestOptions],\n CustomerInvoicesList,\n true\n >\n & { [K in `redirectTo${Capitalize<keyof Omit<HandlerUrls, 'handler' | 'oauthCallback'>>}`]: (options?: RedirectToOptions) => Promise<void> }\n & AuthLike<HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }>\n);\n/** @deprecated Use `HexclaveClientAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackClientAppConstructorOptions<HasTokenStore, ProjectId>): StackClientApp<HasTokenStore, ProjectId>,\n new(options: StackClientAppConstructorOptions<boolean, string>): StackClientApp<boolean, string>,\n\n [hexclaveAppInternalsSymbol]: {\n fromClientJson<HasTokenStore extends boolean, ProjectId extends string>(\n json: StackClientAppJson<HasTokenStore, ProjectId>\n ): StackClientApp<HasTokenStore, ProjectId>,\n },\n};\nexport type HexclaveClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppJson<HasTokenStore, ProjectId>;\nexport type HexclaveClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackClientApp<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppConstructor = StackClientAppConstructor;\nexport const HexclaveClientApp: HexclaveClientAppConstructor = _HexclaveClientAppImpl;\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackClientApp: StackClientAppConstructor = HexclaveClientApp;\n"],"mappings":";;;;;AA8KA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
@@ -35,6 +35,19 @@ type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId extends s
35
35
  }) & {
36
36
  quantity?: number;
37
37
  })): Promise<void>;
38
+ createCheckoutUrl(options: (({
39
+ userId: string;
40
+ } | {
41
+ teamId: string;
42
+ } | {
43
+ customCustomerId: string;
44
+ }) & ({
45
+ productId: string;
46
+ } | {
47
+ product: InlineProduct;
48
+ }) & {
49
+ returnUrl?: string;
50
+ })): Promise<string>;
38
51
  getUser(options: GetCurrentUserOptions<HasTokenStore> & {
39
52
  or: 'redirect';
40
53
  }): Promise<ProjectCurrentServerUser<ProjectId>>;
@@ -1 +1 @@
1
- {"version":3,"file":"server-app.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/server-app.ts"],"mappings":";;;;;;;;;;;;;KAkBY,gCAAA,4DAA4F,gCAAA,CAAiC,aAAA,EAAe,SAAA;EACtJ,eAAA;AAAA;;KAIU,cAAA;EAER,UAAA,CAAW,IAAA,EAAM,uBAAA,GAA0B,OAAA,CAAQ,UAAA;EAPiD;;;EAWpG,aAAA,IAAiB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAElD,UAAA,CAAW,OAAA,EAAS,uBAAA,GAA0B,OAAA,CAAQ,UAAA;EACtD,YAAA,CAAa,OAAA;IACR,MAAA;EAAA;IAAqB,MAAA;EAAA;IAAqB,gBAAA;EAAA;IAC1C,SAAA;EAAA;IAAwB,OAAA,EAAS,aAAA;EAAA;IAClC,QAAA;EAAA,KACA,OAAA;EAGJ,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAmB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC9G,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAgB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC3G,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAoB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC/G,OAAA,CAAQ,OAAA,GAAU,qBAAA,CAAsB,aAAA,IAAiB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC1F,OAAA,CAAQ,EAAA,WAAa,OAAA,CAAQ,UAAA;EAC7B,OAAA,CAAQ,OAAA;IAAW,MAAA;IAAgB,EAAA;EAAA,IAAqC,OAAA,CAAQ,UAAA;EAChF,OAAA,CAAQ,OAAA;IAAW,IAAA;IAAgB,GAAA,EAAK,eAAA;IAAsB,EAAA;EAAA,IAAqC,OAAA,CAAQ,UAAA;EAG3G,cAAA,CAAe,OAAA,EAAS,4BAAA,CAA6B,aAAA;IAAmB,IAAA;EAAA,IAAkB,OAAA,CAAQ,gBAAA;EAClG,cAAA,CAAe,OAAA,EAAS,4BAAA,CAA6B,aAAA;IAAmB,IAAA;EAAA,IAAmB,OAAA,CAAQ,gBAAA;EACnG,cAAA,CAAe,OAAA,EAAS,4BAAA,CAA6B,aAAA,IAAiB,OAAA,CAAQ,uBAAA,GAA0B,gBAAA;EACxG,OAAA,CAAQ,EAAA,WAAa,OAAA,CAAQ,UAAA;EAC7B,OAAA,CAAQ,OAAA;IAAW,MAAA;EAAA,IAAmB,OAAA,CAAQ,UAAA;EAG9C,SAAA,CAAU,OAAA,GAAU,sBAAA,GAAyB,OAAA,CAAQ,UAAA;IAAiB,UAAA;EAAA;EAPjB;;;;;;EAerD,yBAAA,CAA0B,MAAA,UAAgB,OAAA;IAAY,SAAA;EAAA,IAAwB,OAAA;IAAU,MAAA;IAAgB,YAAA;EAAA;EAGxG,mBAAA,CAAoB,OAAA;IAClB,MAAA;IACA,SAAA;IACA,gBAAA;IACA,KAAA;IACA,WAAA;IACA,sBAAA;EAAA,IACE,OAAA,CAAQ,MAAA,CAAO,mBAAA,EAAqB,YAAA,QAAoB,WAAA,CAAY,0CAAA;EAExE,SAAA,CAAU,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAEtC,qBAAA,IAAyB,OAAA,CAAQ,iBAAA;EAEjC,0BAAA,IAA8B,OAAA;AAAA,IAE9B,kBAAA,UAA4B,EAAA,WAAa,UAAA,kBACzC,IAAA,CAAK,kBAAA,cAAgC,UAAA,uCACrC,kBAAA,WAA6B,OAAA,GAAU,sBAAA,GAAyB,UAAA;EAAiB,UAAA;AAAA,WACjF,kBAAA,oBAAsC,EAAA,WAAa,cAAA,WACnD,kBAAA;EAEG,MAAA;EAAgB,MAAA;AAAA;EAAqB,MAAA;EAAgB,MAAA;AAAA;EAAqB,MAAA;EAAgB,gBAAA;AAAA,IAC7F,UAAA,WAGA,kBAAA,cAEC,OAAA,EAAS,8BAAA,GACV,oBAAA,UAGA,cAAA,CAAe,aAAA,EAAe,SAAA;;KAGtB,yBAAA;EAAA,2DAGe,cAAA,yDAEvB,OAAA,EAAS,gCAAA,CAAiC,aAAA,EAAe,SAAA,IAAa,cAAA,CAAe,aAAA,EAAe,SAAA;EAAA,KACjG,OAAA,EAAS,gCAAA,oBAAoD,cAAA;AAAA;AAAA,KAExD,mCAAA,4DAA+F,gCAAA,CAAiC,aAAA,EAAe,SAAA;AAAA,KAC/I,iBAAA,+EAAgG,cAAA,CAAe,aAAA,EAAe,SAAA;AAAA,KAC9H,4BAAA,GAA+B,yBAAA;AAAA,cAC9B,iBAAA,EAAmB,4BAAA;;cAEnB,cAAA,EAAgB,yBAAA"}
1
+ {"version":3,"file":"server-app.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/server-app.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server-app.js","names":["_HexclaveServerAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/server-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport type { GenericQueryCtx } from \"convex/server\";\nimport { AsyncStoreProperty, GetCurrentPartialUserOptions, GetCurrentUserOptions } from \"../../common\";\nimport { CustomerProductsList, CustomerProductsRequestOptions, InlineProduct, ServerItem } from \"../../customers\";\nimport { DataVaultStore } from \"../../data-vault\";\nimport { EmailDeliveryInfo, SendEmailOptions } from \"../../email\";\nimport { ServerListTeamsOptions, ServerListUsersOptions, ServerTeam, ServerTeamCreateOptions } from \"../../teams\";\nimport { ProjectCurrentServerUser, ServerOAuthProvider, ServerUser, ServerUserCreateOptions, SyncedPartialServerUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveServerAppImpl } from \"../implementations\";\nimport { StackClientApp, StackClientAppConstructorOptions } from \"./client-app\";\n\n\n/** @deprecated Use `HexclaveServerAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & {\n secretServerKey?: string,\n};\n\n/** @deprecated Use `HexclaveServerApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n createTeam(data: ServerTeamCreateOptions): Promise<ServerTeam>,\n /**\n * @deprecated use `getUser()` instead\n */\n getServerUser(): Promise<ProjectCurrentServerUser<ProjectId> | null>,\n\n createUser(options: ServerUserCreateOptions): Promise<ServerUser>,\n grantProduct(options: (\n ({ userId: string } | { teamId: string } | { customCustomerId: string }) &\n ({ productId: string } | { product: InlineProduct }) &\n { quantity?: number }\n )): Promise<void>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentServerUser<ProjectId> | null>,\n getUser(id: string): Promise<ServerUser | null>,\n getUser(options: { apiKey: string, or?: \"return-null\" | \"anonymous\" }): Promise<ServerUser | null>,\n getUser(options: { from: \"convex\", ctx: GenericQueryCtx<any>, or?: \"return-null\" | \"anonymous\" }): Promise<ServerUser | null>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialServerUser | TokenPartialUser | null>,\n getTeam(id: string): Promise<ServerTeam | null>,\n getTeam(options: { apiKey: string }): Promise<ServerTeam | null>,\n\n\n listUsers(options?: ServerListUsersOptions): Promise<ServerUser[] & { nextCursor: string | null }>,\n\n /**\n * Returns every direct (or recursive) team permission grant for every\n * member of the given team in one request. Use this instead of calling\n * `user.listPermissions(team)` per row when rendering a roster — that\n * pattern produces an N+1 over the team-member endpoint.\n */\n listTeamMemberPermissions(teamId: string, options?: { recursive?: boolean }): Promise<{ userId: string, permissionId: string }[]>,\n\n // TODO this should actually be on ServerUser\n createOAuthProvider(options: {\n userId: string,\n accountId: string,\n providerConfigId: string,\n email: string,\n allowSignIn: boolean,\n allowConnectedAccounts: boolean,\n }): Promise<Result<ServerOAuthProvider, InstanceType<typeof KnownErrors.OAuthProviderAccountIdAlreadyUsedForSignIn>>>,\n\n sendEmail(options: SendEmailOptions): Promise<void>,\n\n getEmailDeliveryStats(): Promise<EmailDeliveryInfo>,\n\n activateEmailCapacityBoost(): Promise<void>,\n }\n & AsyncStoreProperty<\"user\", [id: string], ServerUser | null, false>\n & Omit<AsyncStoreProperty<\"users\", [], ServerUser[], true>, \"listUsers\" | \"useUsers\">\n & AsyncStoreProperty<\"teams\", [options?: ServerListTeamsOptions], ServerTeam[] & { nextCursor: string | null }, true>\n & AsyncStoreProperty<\"dataVaultStore\", [id: string], DataVaultStore, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n ServerItem,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & StackClientApp<HasTokenStore, ProjectId>\n);\n/** @deprecated Use `HexclaveServerAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackServerAppConstructorOptions<HasTokenStore, ProjectId>): StackServerApp<HasTokenStore, ProjectId>,\n new (options: StackServerAppConstructorOptions<boolean, string>): StackServerApp<boolean, string>,\n};\nexport type HexclaveServerAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackServerAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveServerApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackServerApp<HasTokenStore, ProjectId>;\nexport type HexclaveServerAppConstructor = StackServerAppConstructor;\nexport const HexclaveServerApp: HexclaveServerAppConstructor = _HexclaveServerAppImpl;\n/** @deprecated Use `HexclaveServerApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackServerApp: StackServerAppConstructor = HexclaveServerApp;\n"],"mappings":";;;;;AA+GA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
1
+ {"version":3,"file":"server-app.js","names":["_HexclaveServerAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/server-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport type { GenericQueryCtx } from \"convex/server\";\nimport { AsyncStoreProperty, GetCurrentPartialUserOptions, GetCurrentUserOptions } from \"../../common\";\nimport { CustomerProductsList, CustomerProductsRequestOptions, InlineProduct, ServerItem } from \"../../customers\";\nimport { DataVaultStore } from \"../../data-vault\";\nimport { EmailDeliveryInfo, SendEmailOptions } from \"../../email\";\nimport { ServerListTeamsOptions, ServerListUsersOptions, ServerTeam, ServerTeamCreateOptions } from \"../../teams\";\nimport { ProjectCurrentServerUser, ServerOAuthProvider, ServerUser, ServerUserCreateOptions, SyncedPartialServerUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveServerAppImpl } from \"../implementations\";\nimport { StackClientApp, StackClientAppConstructorOptions } from \"./client-app\";\n\n\n/** @deprecated Use `HexclaveServerAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & {\n secretServerKey?: string,\n};\n\n/** @deprecated Use `HexclaveServerApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n createTeam(data: ServerTeamCreateOptions): Promise<ServerTeam>,\n /**\n * @deprecated use `getUser()` instead\n */\n getServerUser(): Promise<ProjectCurrentServerUser<ProjectId> | null>,\n\n createUser(options: ServerUserCreateOptions): Promise<ServerUser>,\n grantProduct(options: (\n ({ userId: string } | { teamId: string } | { customCustomerId: string }) &\n ({ productId: string } | { product: InlineProduct }) &\n { quantity?: number }\n )): Promise<void>,\n createCheckoutUrl(options: (\n ({ userId: string } | { teamId: string } | { customCustomerId: string }) &\n ({ productId: string } | { product: InlineProduct }) &\n { returnUrl?: string }\n )): Promise<string>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentServerUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentServerUser<ProjectId> | null>,\n getUser(id: string): Promise<ServerUser | null>,\n getUser(options: { apiKey: string, or?: \"return-null\" | \"anonymous\" }): Promise<ServerUser | null>,\n getUser(options: { from: \"convex\", ctx: GenericQueryCtx<any>, or?: \"return-null\" | \"anonymous\" }): Promise<ServerUser | null>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialServerUser | TokenPartialUser | null>,\n getTeam(id: string): Promise<ServerTeam | null>,\n getTeam(options: { apiKey: string }): Promise<ServerTeam | null>,\n\n\n listUsers(options?: ServerListUsersOptions): Promise<ServerUser[] & { nextCursor: string | null }>,\n\n /**\n * Returns every direct (or recursive) team permission grant for every\n * member of the given team in one request. Use this instead of calling\n * `user.listPermissions(team)` per row when rendering a roster — that\n * pattern produces an N+1 over the team-member endpoint.\n */\n listTeamMemberPermissions(teamId: string, options?: { recursive?: boolean }): Promise<{ userId: string, permissionId: string }[]>,\n\n // TODO this should actually be on ServerUser\n createOAuthProvider(options: {\n userId: string,\n accountId: string,\n providerConfigId: string,\n email: string,\n allowSignIn: boolean,\n allowConnectedAccounts: boolean,\n }): Promise<Result<ServerOAuthProvider, InstanceType<typeof KnownErrors.OAuthProviderAccountIdAlreadyUsedForSignIn>>>,\n\n sendEmail(options: SendEmailOptions): Promise<void>,\n\n getEmailDeliveryStats(): Promise<EmailDeliveryInfo>,\n\n activateEmailCapacityBoost(): Promise<void>,\n }\n & AsyncStoreProperty<\"user\", [id: string], ServerUser | null, false>\n & Omit<AsyncStoreProperty<\"users\", [], ServerUser[], true>, \"listUsers\" | \"useUsers\">\n & AsyncStoreProperty<\"teams\", [options?: ServerListTeamsOptions], ServerTeam[] & { nextCursor: string | null }, true>\n & AsyncStoreProperty<\"dataVaultStore\", [id: string], DataVaultStore, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n ServerItem,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & StackClientApp<HasTokenStore, ProjectId>\n);\n/** @deprecated Use `HexclaveServerAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackServerAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackServerAppConstructorOptions<HasTokenStore, ProjectId>): StackServerApp<HasTokenStore, ProjectId>,\n new (options: StackServerAppConstructorOptions<boolean, string>): StackServerApp<boolean, string>,\n};\nexport type HexclaveServerAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackServerAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveServerApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackServerApp<HasTokenStore, ProjectId>;\nexport type HexclaveServerAppConstructor = StackServerAppConstructor;\nexport const HexclaveServerApp: HexclaveServerAppConstructor = _HexclaveServerAppImpl;\n/** @deprecated Use `HexclaveServerApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackServerApp: StackServerAppConstructor = HexclaveServerApp;\n"],"mappings":";;;;;AAoHA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
@@ -110,6 +110,10 @@ type ServerListUsersOptionsBase = {
110
110
  * Free-text search. Matches user ID (exact UUID), display name, and contact channels (e.g. primary email).
111
111
  */
112
112
  query?: string;
113
+ /**
114
+ * Exclude users whose primary email domain matches one of these exact domains.
115
+ */
116
+ excludedEmailDomains?: string[];
113
117
  /**
114
118
  * Only return users who are members of the given team.
115
119
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/teams/index.ts"],"mappings":";;;;;;;;KAaY,iBAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,KAGU,8BAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,KAGU,yBAAA,GAA4B,iBAAA;EACtC,MAAA,CAAO,MAAA,EAAQ,8BAAA,GAAiC,OAAA;AAAA;AAAA,KAGtC,QAAA;EACV,EAAA;EACA,WAAA,EAAa,iBAAA;AAAA;;;;;;;KASH,kBAAA;EACV,EAAA;EACA,cAAA;EACA,SAAA,EAAW,IAAA;EACX,MAAA,IAAU,OAAA;AAAA;AAfZ;;;AAAA,KAqBY,cAAA,GAAiB,kBAAA;;;;;;AAV7B;;KAmBY,sBAAA;EACV,EAAA;EACA,MAAA;EACA,eAAA;EACA,cAAA;EACA,SAAA,EAAW,IAAA;EApBX;;;;AAMF;EAqBE,MAAA,IAAU,OAAA;AAAA;AAAA,KAGA,IAAA;EACV,EAAA;EACA,WAAA;EACA,eAAA;EACA,cAAA;EACA,sBAAA;EACA,UAAA,CAAW,OAAA;IAAW,KAAA;IAAe,WAAA;EAAA,IAAyB,OAAA;EAC9D,SAAA,IAAa,OAAA,CAAQ,QAAA;EACrB,eAAA,IAAmB,OAAA,CAAQ,kBAAA;EAC3B,MAAA,CAAO,MAAA,EAAQ,iBAAA,GAAoB,OAAA;EACnC,MAAA,IAAU,OAAA;EACV,YAAA,CAAa,OAAA,EAAS,qBAAA,WAAgC,OAAA,CAAQ,mBAAA;AAAA,IAC5D,kBAAA,gBAAkC,UAAA,YAAsB,QAAA;AAAA,KAEhD,iBAAA;EACV,WAAA;EACA,eAAA;EACA,cAAA,GAAiB,YAAA;AAAA;AAAA,iBAEH,uBAAA,CAAwB,OAAA,EAAS,iBAAA,GAAoB,SAAA;AAAA,KAQzD,iBAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,iBAEc,uBAAA,CAAwB,OAAA,EAAS,iBAAA,EAAmB,aAAA,WAAwB,SAAA;AAAA,KAShF,uBAAA,GAA0B,iBAAA;AAAA,KAE1B,cAAA,GAAiB,UAAA;EAC3B,WAAA,EAAa,uBAAA;AAAA;AAAA,KAGH,UAAA;EACV,SAAA,EAAW,IAAA;EACX,cAAA;EACA,SAAA,IAAa,OAAA,CAAQ,cAAA;EACrB,MAAA,CAAO,MAAA,EAAQ,uBAAA,GAA0B,OAAA;EACzC,MAAA,IAAU,OAAA;EACV,OAAA,CAAQ,MAAA,WAAiB,OAAA;EACzB,UAAA,CAAW,OAAA;IAAW,KAAA;IAAe,WAAA;EAAA,IAAyB,OAAA;EAC9D,UAAA,CAAW,MAAA,WAAiB,OAAA;AAAA,IAC1B,IAAA;AAAA,KAEC,0BAAA;EACH,MAAA;EACA,KAAA;EACA,OAAA;EACA,IAAA;EArDmB;;;EAyDnB,KAAA;EAxDO;;;EA4DP,MAAA;EA1DA;;;;EA+DA,iBAAA;EA9DE;;;;EAmEF,gBAAA;AAAA;AAAA,KAGU,sBAAA,GAAyB,0BAAA;EAEjC,aAAA;AAAA;EArEF;;;;;EA4EE,aAAA;EACA,gBAAA;AAAA;AAAA,KAIQ,sBAAA;EACV,OAAA;EACA,IAAA;EACA,MAAA;EACA,KAAA;EAjF4E;;AAQ9E;EA6EE,KAAA;AAAA;AAAA,KAGU,uBAAA,GAA0B,iBAAA;EACpC,aAAA;AAAA;AAAA,iBAEc,6BAAA,CAA8B,OAAA,EAAS,uBAAA,GAA0B,SAAA;AAAA,KAQrE,uBAAA,GAA0B,iBAAA;EACpC,sBAAA,GAAyB,YAAA;EACzB,cAAA,GAAiB,YAAA;AAAA;AAAA,iBAEH,6BAAA,CAA8B,OAAA,EAAS,uBAAA,GAA0B,SAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/teams/index.ts"],"mappings":";;;;;;;;KAaY,iBAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,KAGU,8BAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,KAGU,yBAAA,GAA4B,iBAAA;EACtC,MAAA,CAAO,MAAA,EAAQ,8BAAA,GAAiC,OAAA;AAAA;AAAA,KAGtC,QAAA;EACV,EAAA;EACA,WAAA,EAAa,iBAAA;AAAA;;;;;;;KASH,kBAAA;EACV,EAAA;EACA,cAAA;EACA,SAAA,EAAW,IAAA;EACX,MAAA,IAAU,OAAA;AAAA;AAfZ;;;AAAA,KAqBY,cAAA,GAAiB,kBAAA;;;;;;AAV7B;;KAmBY,sBAAA;EACV,EAAA;EACA,MAAA;EACA,eAAA;EACA,cAAA;EACA,SAAA,EAAW,IAAA;EApBX;;;;AAMF;EAqBE,MAAA,IAAU,OAAA;AAAA;AAAA,KAGA,IAAA;EACV,EAAA;EACA,WAAA;EACA,eAAA;EACA,cAAA;EACA,sBAAA;EACA,UAAA,CAAW,OAAA;IAAW,KAAA;IAAe,WAAA;EAAA,IAAyB,OAAA;EAC9D,SAAA,IAAa,OAAA,CAAQ,QAAA;EACrB,eAAA,IAAmB,OAAA,CAAQ,kBAAA;EAC3B,MAAA,CAAO,MAAA,EAAQ,iBAAA,GAAoB,OAAA;EACnC,MAAA,IAAU,OAAA;EACV,YAAA,CAAa,OAAA,EAAS,qBAAA,WAAgC,OAAA,CAAQ,mBAAA;AAAA,IAC5D,kBAAA,gBAAkC,UAAA,YAAsB,QAAA;AAAA,KAEhD,iBAAA;EACV,WAAA;EACA,eAAA;EACA,cAAA,GAAiB,YAAA;AAAA;AAAA,iBAEH,uBAAA,CAAwB,OAAA,EAAS,iBAAA,GAAoB,SAAA;AAAA,KAQzD,iBAAA;EACV,WAAA;EACA,eAAA;AAAA;AAAA,iBAEc,uBAAA,CAAwB,OAAA,EAAS,iBAAA,EAAmB,aAAA,WAAwB,SAAA;AAAA,KAShF,uBAAA,GAA0B,iBAAA;AAAA,KAE1B,cAAA,GAAiB,UAAA;EAC3B,WAAA,EAAa,uBAAA;AAAA;AAAA,KAGH,UAAA;EACV,SAAA,EAAW,IAAA;EACX,cAAA;EACA,SAAA,IAAa,OAAA,CAAQ,cAAA;EACrB,MAAA,CAAO,MAAA,EAAQ,uBAAA,GAA0B,OAAA;EACzC,MAAA,IAAU,OAAA;EACV,OAAA,CAAQ,MAAA,WAAiB,OAAA;EACzB,UAAA,CAAW,OAAA;IAAW,KAAA;IAAe,WAAA;EAAA,IAAyB,OAAA;EAC9D,UAAA,CAAW,MAAA,WAAiB,OAAA;AAAA,IAC1B,IAAA;AAAA,KAEC,0BAAA;EACH,MAAA;EACA,KAAA;EACA,OAAA;EACA,IAAA;EArDmB;;;EAyDnB,KAAA;EAxDO;;;EA4DP,oBAAA;EA1DA;;;EA8DA,MAAA;EA9D8D;;;;EAmE9D,iBAAA;EAlEkE;AAEpE;;;EAqEE,gBAAA;AAAA;AAAA,KAGU,sBAAA,GAAyB,0BAAA;EAEjC,aAAA;AAAA;EAvE2B;;AAE/B;;;EA4EI,aAAA;EACA,gBAAA;AAAA;AAAA,KAIQ,sBAAA;EACV,OAAA;EACA,IAAA;EACA,MAAA;EACA,KAAA;;;;EAIA,KAAA;AAAA;AAAA,KAGU,uBAAA,GAA0B,iBAAA;EACpC,aAAA;AAAA;AAAA,iBAEc,6BAAA,CAA8B,OAAA,EAAS,uBAAA,GAA0B,SAAA;AAAA,KAQrE,uBAAA,GAA0B,iBAAA;EACpC,sBAAA,GAAyB,YAAA;EACzB,cAAA,GAAiB,YAAA;AAAA;AAAA,iBAEH,6BAAA,CAA8B,OAAA,EAAS,uBAAA,GAA0B,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/lib/hexclave-app/teams/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { TeamsCrud } from \"@hexclave/shared/dist/interface/crud/teams\";\nimport { ReadonlyJson } from \"@hexclave/shared/dist/utils/json\";\n\nimport { ApiKeyCreationOptions, TeamApiKey, TeamApiKeyFirstView } from \"../api-keys\";\nimport { AsyncStoreProperty } from \"../common\";\nimport { Customer } from \"../customers\";\nimport { ServerUser } from \"../users\";\n\n\nexport type TeamMemberProfile = {\n displayName: string | null,\n profileImageUrl: string | null,\n}\n\nexport type TeamMemberProfileUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n};\n\nexport type EditableTeamMemberProfile = TeamMemberProfile & {\n update(update: TeamMemberProfileUpdateOptions): Promise<void>,\n}\n\nexport type TeamUser = {\n id: string,\n teamProfile: TeamMemberProfile,\n}\n\n/**\n * A team invitation as seen from the team's perspective (ie. the sender).\n *\n * Returned by `team.listInvitations()`. Contains the recipient email and allows\n * revoking the invitation.\n */\nexport type SentTeamInvitation = {\n id: string,\n recipientEmail: string | null,\n expiresAt: Date,\n revoke(): Promise<void>,\n}\n\n/**\n * @deprecated Use `SentTeamInvitation` instead.\n */\nexport type TeamInvitation = SentTeamInvitation;\n\n/**\n * A team invitation as seen from the invited user's perspective (ie. the receiver).\n *\n * Returned by `user.listTeamInvitations()`. Contains information about teams that have\n * sent invitations to any of the user's verified email addresses, and allows accepting\n * the invitation to join the team.\n */\nexport type ReceivedTeamInvitation = {\n id: string,\n teamId: string,\n teamDisplayName: string,\n recipientEmail: string,\n expiresAt: Date,\n\n /**\n * Accepts the invitation, adding the current user to the team.\n *\n * The user must have a verified email address matching the invitation's recipient email.\n */\n accept(): Promise<void>,\n}\n\nexport type Team = {\n id: string,\n displayName: string,\n profileImageUrl: string | null,\n clientMetadata: any,\n clientReadOnlyMetadata: any,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise<void>,\n listUsers(): Promise<TeamUser[]>,\n listInvitations(): Promise<SentTeamInvitation[]>,\n update(update: TeamUpdateOptions): Promise<void>,\n delete(): Promise<void>,\n createApiKey(options: ApiKeyCreationOptions<\"team\">): Promise<TeamApiKeyFirstView>,\n} & AsyncStoreProperty<\"apiKeys\", [], TeamApiKey[], true> & Customer;\n\nexport type TeamUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n clientMetadata?: ReadonlyJson,\n};\nexport function teamUpdateOptionsToCrud(options: TeamUpdateOptions): TeamsCrud[\"Client\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n };\n}\n\nexport type TeamCreateOptions = {\n displayName: string,\n profileImageUrl?: string,\n}\nexport function teamCreateOptionsToCrud(options: TeamCreateOptions, creatorUserId: string): TeamsCrud[\"Client\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: creatorUserId,\n };\n}\n\n\nexport type ServerTeamMemberProfile = TeamMemberProfile;\n\nexport type ServerTeamUser = ServerUser & {\n teamProfile: ServerTeamMemberProfile,\n}\n\nexport type ServerTeam = {\n createdAt: Date,\n serverMetadata: any,\n listUsers(): Promise<ServerTeamUser[]>,\n update(update: ServerTeamUpdateOptions): Promise<void>,\n delete(): Promise<void>,\n addUser(userId: string): Promise<void>,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise<void>,\n removeUser(userId: string): Promise<void>,\n} & Team;\n\ntype ServerListUsersOptionsBase = {\n cursor?: string,\n limit?: number,\n orderBy?: 'signedUpAt' | 'lastActiveAt',\n desc?: boolean,\n /**\n * Free-text search. Matches user ID (exact UUID), display name, and contact channels (e.g. primary email).\n */\n query?: string,\n /**\n * Only return users who are members of the given team.\n */\n teamId?: string,\n /**\n * Whether to include restricted users (users who haven't completed onboarding requirements).\n * Defaults to false.\n */\n includeRestricted?: boolean,\n /**\n * Whether to include anonymous users (and restricted users).\n * Defaults to false.\n */\n includeAnonymous?: boolean,\n};\n\nexport type ServerListUsersOptions = ServerListUsersOptionsBase & (\n {\n onlyAnonymous?: false,\n } | {\n /**\n * Whether to return only anonymous users.\n * Requires includeAnonymous=true.\n * Defaults to false.\n */\n onlyAnonymous: true,\n includeAnonymous: true,\n }\n);\n\nexport type ServerListTeamsOptions = {\n orderBy?: 'createdAt',\n desc?: boolean,\n cursor?: string,\n limit?: number,\n /**\n * Free-text search. Matches team ID (exact UUID) and display name.\n */\n query?: string,\n};\n\nexport type ServerTeamCreateOptions = TeamCreateOptions & {\n creatorUserId?: string,\n};\nexport function serverTeamCreateOptionsToCrud(options: ServerTeamCreateOptions): TeamsCrud[\"Server\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: options.creatorUserId,\n };\n}\n\nexport type ServerTeamUpdateOptions = TeamUpdateOptions & {\n clientReadOnlyMetadata?: ReadonlyJson,\n serverMetadata?: ReadonlyJson,\n};\nexport function serverTeamUpdateOptionsToCrud(options: ServerTeamUpdateOptions): TeamsCrud[\"Server\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n client_read_only_metadata: options.clientReadOnlyMetadata,\n server_metadata: options.serverMetadata,\n };\n}\n"],"mappings":";;;AA2FA,SAAgB,wBAAwB,SAA2D;AACjG,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EAC1B;;AAOH,SAAgB,wBAAwB,SAA4B,eAAsD;AACxH,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB;EAClB;;AA0EH,SAAgB,8BAA8B,SAAiE;AAC7G,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EAC1B;;AAOH,SAAgB,8BAA8B,SAAiE;AAC7G,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EACzB,2BAA2B,QAAQ;EACnC,iBAAiB,QAAQ;EAC1B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/lib/hexclave-app/teams/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { TeamsCrud } from \"@hexclave/shared/dist/interface/crud/teams\";\nimport { ReadonlyJson } from \"@hexclave/shared/dist/utils/json\";\n\nimport { ApiKeyCreationOptions, TeamApiKey, TeamApiKeyFirstView } from \"../api-keys\";\nimport { AsyncStoreProperty } from \"../common\";\nimport { Customer } from \"../customers\";\nimport { ServerUser } from \"../users\";\n\n\nexport type TeamMemberProfile = {\n displayName: string | null,\n profileImageUrl: string | null,\n}\n\nexport type TeamMemberProfileUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n};\n\nexport type EditableTeamMemberProfile = TeamMemberProfile & {\n update(update: TeamMemberProfileUpdateOptions): Promise<void>,\n}\n\nexport type TeamUser = {\n id: string,\n teamProfile: TeamMemberProfile,\n}\n\n/**\n * A team invitation as seen from the team's perspective (ie. the sender).\n *\n * Returned by `team.listInvitations()`. Contains the recipient email and allows\n * revoking the invitation.\n */\nexport type SentTeamInvitation = {\n id: string,\n recipientEmail: string | null,\n expiresAt: Date,\n revoke(): Promise<void>,\n}\n\n/**\n * @deprecated Use `SentTeamInvitation` instead.\n */\nexport type TeamInvitation = SentTeamInvitation;\n\n/**\n * A team invitation as seen from the invited user's perspective (ie. the receiver).\n *\n * Returned by `user.listTeamInvitations()`. Contains information about teams that have\n * sent invitations to any of the user's verified email addresses, and allows accepting\n * the invitation to join the team.\n */\nexport type ReceivedTeamInvitation = {\n id: string,\n teamId: string,\n teamDisplayName: string,\n recipientEmail: string,\n expiresAt: Date,\n\n /**\n * Accepts the invitation, adding the current user to the team.\n *\n * The user must have a verified email address matching the invitation's recipient email.\n */\n accept(): Promise<void>,\n}\n\nexport type Team = {\n id: string,\n displayName: string,\n profileImageUrl: string | null,\n clientMetadata: any,\n clientReadOnlyMetadata: any,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise<void>,\n listUsers(): Promise<TeamUser[]>,\n listInvitations(): Promise<SentTeamInvitation[]>,\n update(update: TeamUpdateOptions): Promise<void>,\n delete(): Promise<void>,\n createApiKey(options: ApiKeyCreationOptions<\"team\">): Promise<TeamApiKeyFirstView>,\n} & AsyncStoreProperty<\"apiKeys\", [], TeamApiKey[], true> & Customer;\n\nexport type TeamUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n clientMetadata?: ReadonlyJson,\n};\nexport function teamUpdateOptionsToCrud(options: TeamUpdateOptions): TeamsCrud[\"Client\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n };\n}\n\nexport type TeamCreateOptions = {\n displayName: string,\n profileImageUrl?: string,\n}\nexport function teamCreateOptionsToCrud(options: TeamCreateOptions, creatorUserId: string): TeamsCrud[\"Client\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: creatorUserId,\n };\n}\n\n\nexport type ServerTeamMemberProfile = TeamMemberProfile;\n\nexport type ServerTeamUser = ServerUser & {\n teamProfile: ServerTeamMemberProfile,\n}\n\nexport type ServerTeam = {\n createdAt: Date,\n serverMetadata: any,\n listUsers(): Promise<ServerTeamUser[]>,\n update(update: ServerTeamUpdateOptions): Promise<void>,\n delete(): Promise<void>,\n addUser(userId: string): Promise<void>,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise<void>,\n removeUser(userId: string): Promise<void>,\n} & Team;\n\ntype ServerListUsersOptionsBase = {\n cursor?: string,\n limit?: number,\n orderBy?: 'signedUpAt' | 'lastActiveAt',\n desc?: boolean,\n /**\n * Free-text search. Matches user ID (exact UUID), display name, and contact channels (e.g. primary email).\n */\n query?: string,\n /**\n * Exclude users whose primary email domain matches one of these exact domains.\n */\n excludedEmailDomains?: string[],\n /**\n * Only return users who are members of the given team.\n */\n teamId?: string,\n /**\n * Whether to include restricted users (users who haven't completed onboarding requirements).\n * Defaults to false.\n */\n includeRestricted?: boolean,\n /**\n * Whether to include anonymous users (and restricted users).\n * Defaults to false.\n */\n includeAnonymous?: boolean,\n};\n\nexport type ServerListUsersOptions = ServerListUsersOptionsBase & (\n {\n onlyAnonymous?: false,\n } | {\n /**\n * Whether to return only anonymous users.\n * Requires includeAnonymous=true.\n * Defaults to false.\n */\n onlyAnonymous: true,\n includeAnonymous: true,\n }\n);\n\nexport type ServerListTeamsOptions = {\n orderBy?: 'createdAt',\n desc?: boolean,\n cursor?: string,\n limit?: number,\n /**\n * Free-text search. Matches team ID (exact UUID) and display name.\n */\n query?: string,\n};\n\nexport type ServerTeamCreateOptions = TeamCreateOptions & {\n creatorUserId?: string,\n};\nexport function serverTeamCreateOptionsToCrud(options: ServerTeamCreateOptions): TeamsCrud[\"Server\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: options.creatorUserId,\n };\n}\n\nexport type ServerTeamUpdateOptions = TeamUpdateOptions & {\n clientReadOnlyMetadata?: ReadonlyJson,\n serverMetadata?: ReadonlyJson,\n};\nexport function serverTeamUpdateOptionsToCrud(options: ServerTeamUpdateOptions): TeamsCrud[\"Server\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n client_read_only_metadata: options.clientReadOnlyMetadata,\n server_metadata: options.serverMetadata,\n };\n}\n"],"mappings":";;;AA2FA,SAAgB,wBAAwB,SAA2D;AACjG,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EAC1B;;AAOH,SAAgB,wBAAwB,SAA4B,eAAsD;AACxH,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB;EAClB;;AA8EH,SAAgB,8BAA8B,SAAiE;AAC7G,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EAC1B;;AAOH,SAAgB,8BAA8B,SAAiE;AAC7G,QAAO;EACL,cAAc,QAAQ;EACtB,mBAAmB,QAAQ;EAC3B,iBAAiB,QAAQ;EACzB,2BAA2B,QAAQ;EACnC,iBAAiB,QAAQ;EAC1B"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)",
3
3
  "name": "@hexclave/js",
4
- "version": "1.0.29",
4
+ "version": "1.0.32",
5
5
  "repository": "https://github.com/hexclave/hexclave",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/index.js",
@@ -65,7 +65,7 @@
65
65
  "qrcode": "^1.5.4",
66
66
  "rrweb": "^1.1.3",
67
67
  "yup": "^1.7.1",
68
- "@hexclave/shared": "1.0.29"
68
+ "@hexclave/shared": "1.0.32"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@quetzallabs/i18n": "^0.1.19",
@@ -2400,16 +2400,11 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
2400
2400
  return clientVersion;
2401
2401
  }
2402
2402
 
2403
- private _botChallengeSiteKeysWarned = false;
2404
2403
  private _getBotChallengeSiteKeys(): { visibleSiteKey: string, invisibleSiteKey: string } | null {
2405
2404
  if (!isBrowserLike()) return null;
2406
2405
 
2407
2406
  const visibleSiteKey = envVars.HEXCLAVE_BOT_CHALLENGE_SITE_KEY;
2408
2407
  if (!visibleSiteKey) {
2409
- if (!this._botChallengeSiteKeysWarned) {
2410
- this._botChallengeSiteKeysWarned = true;
2411
- console.warn("[stack-auth] HEXCLAVE_BOT_CHALLENGE_SITE_KEY is not set — bot challenge fraud protection is disabled. Set the env variable to enable it.");
2412
- }
2413
2408
  return null;
2414
2409
  }
2415
2410
 
@@ -3667,6 +3662,9 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
3667
3662
  signInWithTokens: async (tokens: { accessToken: string, refreshToken: string }) => {
3668
3663
  await this._signInToAccountWithTokens(tokens);
3669
3664
  },
3665
+ awaitPendingAuthResolutions: async () => {
3666
+ await this._awaitPendingAuthResolutions();
3667
+ },
3670
3668
  };
3671
3669
  };
3672
3670
 
@@ -2,8 +2,7 @@
2
2
  //===========================================
3
3
  // THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template
4
4
  //===========================================
5
- import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
6
- import { KnownErrors, HexclaveServerInterface } from "@hexclave/shared";
5
+ import { HexclaveServerInterface, KnownErrors } from "@hexclave/shared";
7
6
  import { ContactChannelsCrud } from "@hexclave/shared/dist/interface/crud/contact-channels";
8
7
  import { ItemCrud } from "@hexclave/shared/dist/interface/crud/items";
9
8
  import { NotificationPreferenceCrud } from "@hexclave/shared/dist/interface/crud/notification-preferences";
@@ -23,6 +22,7 @@ import { ProviderType } from "@hexclave/shared/dist/utils/oauth";
23
22
  import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
24
23
  import { suspend } from "@hexclave/shared/dist/utils/react";
25
24
  import { Result } from "@hexclave/shared/dist/utils/results";
25
+ import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
26
26
  import * as yup from "yup";
27
27
  import { constructRedirectUrl } from "../../../../utils/url";
28
28
  import { ApiKey, ApiKeyCreationOptions, ApiKeyUpdateOptions, apiKeyCreationOptionsToCrud, apiKeyUpdateOptionsToCrud } from "../../api-keys";
@@ -62,14 +62,16 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
62
62
  includeAnonymous?: boolean,
63
63
  onlyAnonymous?: boolean,
64
64
  teamId?: string,
65
- ], UsersCrud['Server']['List']>(async ([cursor, limit, orderBy, desc, query, includeRestricted, includeAnonymous, onlyAnonymous, teamId]) => {
65
+ excludedEmailDomains?: string,
66
+ ], UsersCrud['Server']['List']>(async ([cursor, limit, orderBy, desc, query, includeRestricted, includeAnonymous, onlyAnonymous, teamId, excludedEmailDomains]) => {
66
67
  if (onlyAnonymous && !includeAnonymous) {
67
68
  throw new HexclaveAssertionError("onlyAnonymous=true requires includeAnonymous=true");
68
69
  }
70
+ const excludedEmailDomainList = excludedEmailDomains?.split(",");
69
71
  if (onlyAnonymous) {
70
- return await this._interface.listServerUsers({ cursor, limit, orderBy, desc, query, includeRestricted, includeAnonymous: true, onlyAnonymous: true, teamId });
72
+ return await this._interface.listServerUsers({ cursor, limit, orderBy, desc, query, excludedEmailDomains: excludedEmailDomainList, includeRestricted, includeAnonymous: true, onlyAnonymous: true, teamId });
71
73
  }
72
- return await this._interface.listServerUsers({ cursor, limit, orderBy, desc, query, includeRestricted, includeAnonymous, teamId });
74
+ return await this._interface.listServerUsers({ cursor, limit, orderBy, desc, query, excludedEmailDomains: excludedEmailDomainList, includeRestricted, includeAnonymous, teamId });
73
75
  });
74
76
  private readonly _serverUserCache = createCache<string[], UsersCrud['Server']['Read'] | null>(async ([userId]) => {
75
77
  const user = await this._interface.getServerUserById(userId);
@@ -1111,7 +1113,8 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
1111
1113
 
1112
1114
 
1113
1115
  async listUsers(options?: ServerListUsersOptions): Promise<ServerUser[] & { nextCursor: string | null }> {
1114
- const crud = Result.orThrow(await this._serverUsersCache.getOrWait([options?.cursor, options?.limit, options?.orderBy, options?.desc, options?.query, options?.includeRestricted, options?.includeAnonymous, options?.onlyAnonymous, options?.teamId], "write-only"));
1116
+ const excludedEmailDomains = options?.excludedEmailDomains && options.excludedEmailDomains.length > 0 ? options.excludedEmailDomains.join(",") : undefined;
1117
+ const crud = Result.orThrow(await this._serverUsersCache.getOrWait([options?.cursor, options?.limit, options?.orderBy, options?.desc, options?.query, options?.includeRestricted, options?.includeAnonymous, options?.onlyAnonymous, options?.teamId, excludedEmailDomains], "write-only"));
1115
1118
  const result: any = crud.items.map((j) => this._serverUserFromCrud(j));
1116
1119
  result.nextCursor = crud.pagination?.next_cursor ?? null;
1117
1120
  return result as any;
@@ -1165,23 +1168,24 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
1165
1168
  return this._customerProductsFromResponse(response);
1166
1169
  }
1167
1170
 
1171
+ private _resolveCustomer(
1172
+ options: { userId: string } | { teamId: string } | { customCustomerId: string }
1173
+ ): { customerType: "user" | "team" | "custom", customerId: string } {
1174
+ if ("userId" in options) {
1175
+ return { customerType: "user", customerId: options.userId };
1176
+ }
1177
+ if ("teamId" in options) {
1178
+ return { customerType: "team", customerId: options.teamId };
1179
+ }
1180
+ return { customerType: "custom", customerId: options.customCustomerId };
1181
+ }
1182
+
1168
1183
  async grantProduct(options: (
1169
1184
  ({ userId: string } | { teamId: string } | { customCustomerId: string }) &
1170
1185
  ({ productId: string } | { product: InlineProduct }) &
1171
1186
  { quantity?: number }
1172
1187
  )): Promise<void> {
1173
- let customerType: "user" | "team" | "custom";
1174
- let customerId: string;
1175
- if ("userId" in options) {
1176
- customerType = "user";
1177
- customerId = options.userId;
1178
- } else if ("teamId" in options) {
1179
- customerType = "team";
1180
- customerId = options.teamId;
1181
- } else {
1182
- customerType = "custom";
1183
- customerId = options.customCustomerId;
1184
- }
1188
+ const { customerType, customerId } = this._resolveCustomer(options);
1185
1189
 
1186
1190
  await this._interface.grantProduct({
1187
1191
  customerType,
@@ -1199,6 +1203,17 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
1199
1203
  await cache.refresh([customerId, null, null]);
1200
1204
  }
1201
1205
 
1206
+ async createCheckoutUrl(options: (
1207
+ ({ userId: string } | { teamId: string } | { customCustomerId: string }) &
1208
+ ({ productId: string } | { product: InlineProduct }) &
1209
+ { returnUrl?: string }
1210
+ )): Promise<string> {
1211
+ const { customerType, customerId } = this._resolveCustomer(options);
1212
+
1213
+ const productIdOrInline = "productId" in options ? options.productId : options.product;
1214
+ return await this._interface.createCheckoutUrl(customerType, customerId, productIdOrInline, null, options.returnUrl, "server");
1215
+ }
1216
+
1202
1217
  async createTeam(data: ServerTeamCreateOptions): Promise<ServerTeam> {
1203
1218
  const team = await this._interface.createServerTeam(serverTeamCreateOptionsToCrud(data));
1204
1219
  await this._serverTeamsCache.refreshWhere(() => true);
@@ -114,6 +114,9 @@ const MAX_APPROX_BYTES_PER_BATCH = 512_000;
114
114
  // envelope overhead (browser_session_id, timestamps, wrapper keys, etc.).
115
115
  const MAX_FLUSH_PAYLOAD_BYTES = 900_000;
116
116
 
117
+ // Reused across the emit hot path to avoid per-event allocation.
118
+ const textEncoder = new TextEncoder();
119
+
117
120
  export type StoredSession = {
118
121
  session_id: string,
119
122
  created_at_ms: number,
@@ -290,6 +293,17 @@ export class SessionRecorder {
290
293
  // When _flushInProgress blocked earlier flushes, events can accumulate
291
294
  // well past MAX_APPROX_BYTES_PER_BATCH; sending them all at once would
292
295
  // exceed the server's 1MB body limit (413).
296
+ // A single event over the limit can't be sent (rrweb events aren't splittable); drop it and move on.
297
+ const firstSize = allSizes[offset] ?? throwErr("_eventSizes out of sync with _events — this should never happen");
298
+ if (firstSize > MAX_FLUSH_PAYLOAD_BYTES) {
299
+ captureWarning(
300
+ "SessionRecorder.flush",
301
+ new Error(`Dropping oversized session replay event (${firstSize} bytes > ${MAX_FLUSH_PAYLOAD_BYTES} byte limit); it cannot be sent without a 413.`),
302
+ );
303
+ offset += 1;
304
+ continue;
305
+ }
306
+
293
307
  let batchBytes = 0;
294
308
  let batchEnd = offset;
295
309
  for (let i = offset; i < allEvents.length; i++) {
@@ -388,7 +402,8 @@ export class SessionRecorder {
388
402
  }
389
403
  }
390
404
 
391
- const eventSize = JSON.stringify(event).length;
405
+ // Measure UTF-8 byte length to match the server's byte limit (.length counts UTF-16 units, undercounting multibyte content).
406
+ const eventSize = textEncoder.encode(JSON.stringify(event)).byteLength;
392
407
  this._events.push(event);
393
408
  this._eventSizes.push(eventSize);
394
409
  this._approxBytes += eventSize;
@@ -128,6 +128,7 @@ export type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId ex
128
128
  redirectToUrl(url: string | URL, options?: { replace?: boolean }): Promise<void>,
129
129
  redirectToHandler(handlerName: keyof HandlerUrls, options?: RedirectToOptions): Promise<void>,
130
130
  signInWithTokens(tokens: { accessToken: string, refreshToken: string }): Promise<void>,
131
+ awaitPendingAuthResolutions(): Promise<void>,
131
132
  },
132
133
  }
133
134
  & AsyncStoreProperty<"project", [], Project, false>
@@ -35,6 +35,11 @@ export type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId ex
35
35
  ({ productId: string } | { product: InlineProduct }) &
36
36
  { quantity?: number }
37
37
  )): Promise<void>,
38
+ createCheckoutUrl(options: (
39
+ ({ userId: string } | { teamId: string } | { customCustomerId: string }) &
40
+ ({ productId: string } | { product: InlineProduct }) &
41
+ { returnUrl?: string }
42
+ )): Promise<string>,
38
43
 
39
44
 
40
45
  getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentServerUser<ProjectId>>,