@bounded-sh/core 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -20,10 +20,13 @@ let clientConfig = {
20
20
  humanAuthApiUrl: 'https://auth.bounded.sh',
21
21
  functionsUrl: 'https://functions.bounded.sh',
22
22
  appId: '',
23
- // 'email' = Bounded Better Auth human login (inline OTP) — the out-of-box default
24
- // for most apps. For wallet login use authMethod:'phantom' (Solana / Phantom, the
25
- // recommended wallet option), or signInAnonymously() for zero-friction 'guest'
26
- // accounts all coexist. ('wallet' is an unimplemented stub; don't use.)
23
+ // 'email' = Bounded Auth human login (inline email OTP) — the out-of-box default
24
+ // for normal apps. Hosted OAuth/social uses loginWithRedirect/loginWithPopup.
25
+ // Text OTP is off by default and uses hosted/headless text helpers only when
26
+ // Bounded explicitly enables it for the issuer. For
27
+ // crypto/onchain wallet login use authMethod:'phantom' (Solana / Phantom), or
28
+ // signInAnonymously() for zero-friction 'guest' accounts. ('wallet' is an
29
+ // unimplemented stub; don't use.)
27
30
  authMethod: 'email',
28
31
  chain: '',
29
32
  rpcUrl: '',
@@ -4223,7 +4226,7 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
4223
4226
  }
4224
4227
  }
4225
4228
 
4226
- var __rest = (undefined && undefined.__rest) || function (s, e) {
4229
+ var __rest$1 = (undefined && undefined.__rest) || function (s, e) {
4227
4230
  var t = {};
4228
4231
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4229
4232
  t[p] = s[p];
@@ -4698,7 +4701,7 @@ async function search(path, query, opts = {}) {
4698
4701
  normalizedPath = normalizedPath.slice(0, -1);
4699
4702
  }
4700
4703
  if (!normalizedPath || normalizedPath.length === 0) {
4701
- return new Error("Invalid path provided.");
4704
+ throw new Error("Invalid path provided.");
4702
4705
  }
4703
4706
  if (typeof query !== "string" || query.trim().length === 0) {
4704
4707
  throw new Error("search query must be a non-empty string");
@@ -4725,7 +4728,7 @@ async function get(path, opts = {}) {
4725
4728
  normalizedPath = normalizedPath.slice(0, -1);
4726
4729
  }
4727
4730
  if (!normalizedPath || normalizedPath.length === 0) {
4728
- return new Error("Invalid path provided.");
4731
+ throw new Error("Invalid path provided.");
4729
4732
  }
4730
4733
  // Create cache key combining path, prompt, filter, sort, includeSubPaths,
4731
4734
  // shape, limit, cursor — and (H1) the caller's appId + principal fingerprint,
@@ -4853,6 +4856,23 @@ function cleanupExpiredCache() {
4853
4856
  });
4854
4857
  lastCacheCleanup = now;
4855
4858
  }
4859
+ function classifyGetManyBatchError(error) {
4860
+ var _a, _b, _c;
4861
+ const err = error;
4862
+ const status = (_b = (_a = err === null || err === void 0 ? void 0 : err.status) !== null && _a !== void 0 ? _a : err === null || err === void 0 ? void 0 : err.statusCode) !== null && _b !== void 0 ? _b : (_c = err === null || err === void 0 ? void 0 : err.response) === null || _c === void 0 ? void 0 : _c.status;
4863
+ const message = error instanceof Error
4864
+ ? error.message
4865
+ : typeof (err === null || err === void 0 ? void 0 : err.message) === 'string'
4866
+ ? err.message
4867
+ : 'Unknown error';
4868
+ if (status === 401 || status === 403) {
4869
+ return { code: 'UNAUTHORIZED', message };
4870
+ }
4871
+ if (status === 400) {
4872
+ return { code: 'INVALID_PATH', message };
4873
+ }
4874
+ return { code: 'REQUEST_FAILED', message };
4875
+ }
4856
4876
  async function getMany(paths, opts = {}) {
4857
4877
  var _a, _b, _c, _d, _e;
4858
4878
  if (paths.length === 0) {
@@ -4897,6 +4917,11 @@ async function getMany(paths, opts = {}) {
4897
4917
  if (uncachedPaths.length > 0) {
4898
4918
  try {
4899
4919
  const response = await makeApiRequest('POST', 'items/batch', { paths: uncachedPaths }, opts._overrides);
4920
+ if (response.status === 404 && response.data == null) {
4921
+ const endpointError = new Error('Batch read endpoint returned 404');
4922
+ endpointError.status = 404;
4923
+ throw endpointError;
4924
+ }
4900
4925
  // makeApiRequest returns `{ data: <httpBody> }`, and the worker's items/batch
4901
4926
  // httpBody is `{ data: { results: [...] }, status }` — so the results are
4902
4927
  // double-nested at response.data.data.results. (Reading response.data.results
@@ -4939,11 +4964,12 @@ async function getMany(paths, opts = {}) {
4939
4964
  }
4940
4965
  }
4941
4966
  catch (error) {
4967
+ const batchError = classifyGetManyBatchError(error);
4942
4968
  for (const originalIndex of uncachedIndices) {
4943
4969
  results[originalIndex] = {
4944
4970
  path: normalizedPaths[originalIndex],
4945
4971
  data: null,
4946
- error: { code: 'NOT_FOUND', message: error instanceof Error ? error.message : 'Unknown error' }
4972
+ error: batchError,
4947
4973
  };
4948
4974
  }
4949
4975
  }
@@ -5105,26 +5131,23 @@ async function setMany(many, options) {
5105
5131
  return Object.assign(Object.assign({}, documents.map(d => d.document)), { transactionId: transactionResult.signature, signedTransaction: transactionResult.signedTransaction });
5106
5132
  }
5107
5133
  // Handle Solana on-chain transaction flow
5108
- let lastTxSignature = undefined;
5109
- let signedTransaction = undefined;
5110
- for (let i = 0; i < transactions.length; i++) {
5111
- const curTx = transactions[i];
5112
- let transactionResult;
5113
- if (curTx.serializedTransaction) {
5114
- transactionResult = await handlePreBuiltTransaction(curTx, authProvider, options);
5115
- }
5116
- else {
5117
- transactionResult = await handleSolanaTransaction(curTx, authProvider, options);
5118
- }
5119
- lastTxSignature = transactionResult.transactionSignature;
5120
- signedTransaction = transactionResult.signedTransaction;
5134
+ if (!Array.isArray(transactions) || transactions.length !== 1) {
5135
+ throw new Error(`Expected exactly one on-chain transaction, received ${Array.isArray(transactions) ? transactions.length : 0}`);
5136
+ }
5137
+ const curTx = transactions[0];
5138
+ let transactionResult;
5139
+ if (curTx.serializedTransaction) {
5140
+ transactionResult = await handlePreBuiltTransaction(curTx, authProvider, options);
5141
+ }
5142
+ else {
5143
+ transactionResult = await handleSolanaTransaction(curTx, authProvider, options);
5121
5144
  }
5122
5145
  // Sync items after all transactions are confirmed
5123
5146
  // Wait for 1.5 seconds to ensure all transactions are confirmed
5124
5147
  await new Promise(resolve => setTimeout(resolve, 1500));
5125
5148
  await syncItems(many.map(m => m.path), options);
5126
5149
  // TODO: Should we wait here or do the optimistic subscription updates like below?
5127
- return Object.assign(Object.assign({}, documents.map(d => d.document)), { transactionId: lastTxSignature, signedTransaction: signedTransaction });
5150
+ return Object.assign(Object.assign({}, documents.map(d => d.document)), { transactionId: transactionResult.transactionSignature, signedTransaction: transactionResult.signedTransaction });
5128
5151
  }
5129
5152
  else if (setResponse.status === 200) {
5130
5153
  // This means that the document was set successfully.
@@ -5137,7 +5160,7 @@ async function setMany(many, options) {
5137
5160
  else if (setResponse.data &&
5138
5161
  typeof setResponse.data === 'object' &&
5139
5162
  setResponse.data.success === true) {
5140
- const _k = setResponse.data, { success: _success } = _k, rest = __rest(_k, ["success"]);
5163
+ const _k = setResponse.data, { success: _success } = _k, rest = __rest$1(_k, ["success"]);
5141
5164
  return Object.assign(Object.assign(Object.assign({}, documents.map(d => d.document)), rest), { transactionId: null });
5142
5165
  }
5143
5166
  else {
@@ -5373,7 +5396,7 @@ async function getFiles(path, options) {
5373
5396
  try {
5374
5397
  const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
5375
5398
  if (!normalizedPath || normalizedPath.length === 0) {
5376
- return new Error("Invalid path provided.");
5399
+ throw new Error("Invalid path provided.");
5377
5400
  }
5378
5401
  const apiPath = `storage?path=${normalizedPath}`;
5379
5402
  const response = await makeApiRequest('GET', apiPath, null, options === null || options === void 0 ? void 0 : options._overrides);
@@ -5793,6 +5816,12 @@ function roomKeyFromRoutePath(routePath) {
5793
5816
  return null;
5794
5817
  return `${segs[0]}/${segs[1]}`;
5795
5818
  }
5819
+ function replaySubscriptions(connection) {
5820
+ for (const sub of connection.subscriptions.values()) {
5821
+ sub.lastData = undefined;
5822
+ sendSubscribe(connection, sub);
5823
+ }
5824
+ }
5796
5825
  async function getOrCreateConnection(appId, isServer, routePath, authTokenProvider, principalKey) {
5797
5826
  attachBrowserReconnectHooksOnce();
5798
5827
  // A per-room subscription gets its OWN connection routed to the room DO; all
@@ -5818,10 +5847,12 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5818
5847
  pendingRequests: new Map(),
5819
5848
  isConnecting: false,
5820
5849
  isConnected: false,
5850
+ isAuthenticating: false,
5821
5851
  appId,
5822
5852
  key: connKey,
5823
5853
  routePath: roomKey ? routePath : undefined,
5824
5854
  authTokenProvider,
5855
+ pendingAuthToken: null,
5825
5856
  tokenRefreshTimer: null,
5826
5857
  consecutiveAuthFailures: 0,
5827
5858
  };
@@ -5846,16 +5877,17 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5846
5877
  // Per-room connection: carry the room path so the worker routes this WS
5847
5878
  // to the room DO (appId#room#roomId) where the live view fan-out lives.
5848
5879
  if (connection.routePath) {
5849
- wsUrl.searchParams.append('path', connection.routePath);
5880
+ wsUrl.searchParams.append('routePath', connection.routePath);
5850
5881
  }
5851
- // Add auth token if available. A wallet-scoped connection resolves its
5852
- // token from the wallet's own session (self-refreshing); all others use
5853
- // the ambient env/web session.
5882
+ // Resolve auth token if available. A wallet-scoped connection resolves
5883
+ // its token from the wallet's own session (self-refreshing); all others
5884
+ // use the ambient env/web session. The token is sent as the first WS
5885
+ // frame after open, never as a URL query parameter.
5854
5886
  const authToken = connection.authTokenProvider
5855
5887
  ? await connection.authTokenProvider().catch(() => null)
5856
5888
  : await getFreshAuthToken(isServer);
5889
+ connection.pendingAuthToken = authToken || null;
5857
5890
  if (authToken) {
5858
- wsUrl.searchParams.append('authorization', authToken);
5859
5891
  // Successful token acquisition — reset failure counter
5860
5892
  connection.consecutiveAuthFailures = 0;
5861
5893
  }
@@ -5881,6 +5913,7 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5881
5913
  connection.ws = ws;
5882
5914
  // Handle connection open
5883
5915
  ws.addEventListener('open', () => {
5916
+ var _a, _b;
5884
5917
  connection.isConnecting = false;
5885
5918
  connection.isConnected = true;
5886
5919
  // NOTE: Do NOT reset consecutiveAuthFailures here. It is reset when a
@@ -5895,10 +5928,26 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5895
5928
  // urlProvider skips straight to unauthenticated connection.
5896
5929
  // Schedule periodic token freshness checks
5897
5930
  scheduleTokenRefresh(connection, isServer);
5898
- // Re-subscribe to all existing subscriptions after reconnect
5899
- for (const sub of connection.subscriptions.values()) {
5900
- sub.lastData = undefined;
5901
- sendSubscribe(connection, sub);
5931
+ if (connection.pendingAuthToken) {
5932
+ connection.isAuthenticating = true;
5933
+ try {
5934
+ (_a = connection.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({ type: 'auth', token: connection.pendingAuthToken }));
5935
+ }
5936
+ catch (error) {
5937
+ connection.isAuthenticating = false;
5938
+ connection.isConnected = false;
5939
+ console.error('[WS v2] Error sending auth message:', error);
5940
+ try {
5941
+ (_b = connection.ws) === null || _b === void 0 ? void 0 : _b.close(1008, 'Authentication send failed');
5942
+ }
5943
+ catch (_c) {
5944
+ // Already closed.
5945
+ }
5946
+ }
5947
+ }
5948
+ else {
5949
+ connection.isAuthenticating = false;
5950
+ replaySubscriptions(connection);
5902
5951
  }
5903
5952
  });
5904
5953
  // Handle incoming messages
@@ -5922,6 +5971,7 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5922
5971
  // Handle close
5923
5972
  ws.addEventListener('close', () => {
5924
5973
  connection.isConnected = false;
5974
+ connection.isAuthenticating = false;
5925
5975
  if (connection.tokenRefreshTimer) {
5926
5976
  clearInterval(connection.tokenRefreshTimer);
5927
5977
  connection.tokenRefreshTimer = null;
@@ -5938,6 +5988,11 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
5938
5988
  function handleServerMessage(connection, message) {
5939
5989
  var _a, _b;
5940
5990
  switch (message.type) {
5991
+ case 'authenticated': {
5992
+ connection.isAuthenticating = false;
5993
+ replaySubscriptions(connection);
5994
+ break;
5995
+ }
5941
5996
  case 'subscribed': {
5942
5997
  const subscription = connection.subscriptions.get(message.subscriptionId);
5943
5998
  if (subscription) {
@@ -6238,7 +6293,7 @@ async function subscribeV2(path, subscriptionOptions, roomRoutePath) {
6238
6293
  };
6239
6294
  connection.subscriptions.set(subscriptionId, subscription);
6240
6295
  // Send subscribe message if connected
6241
- if (connection.isConnected) {
6296
+ if (connection.isConnected && !connection.isAuthenticating) {
6242
6297
  // Create a promise to wait for subscription confirmation
6243
6298
  const subscriptionPromise = new Promise((resolve, reject) => {
6244
6299
  connection.pendingSubscriptions.set(subscriptionId, { resolve, reject });
@@ -6276,7 +6331,7 @@ async function removeCallbackFromSubscription(connection, subscriptionId, callba
6276
6331
  }
6277
6332
  // No more callbacks, unsubscribe from server
6278
6333
  connection.subscriptions.delete(subscriptionId);
6279
- if (connection.isConnected) {
6334
+ if (connection.isConnected && !connection.isAuthenticating) {
6280
6335
  // Create a promise to wait for unsubscription confirmation
6281
6336
  const unsubscribePromise = new Promise((resolve, reject) => {
6282
6337
  connection.pendingUnsubscriptions.set(subscriptionId, { resolve, reject });
@@ -6452,12 +6507,59 @@ function generateRequestId() {
6452
6507
  */
6453
6508
  function hasActiveConnection() {
6454
6509
  for (const connection of connections.values()) {
6455
- if (connection.ws && connection.isConnected) {
6510
+ if (connection.ws && connection.isConnected && !connection.isAuthenticating) {
6456
6511
  return true;
6457
6512
  }
6458
6513
  }
6459
6514
  return false;
6460
6515
  }
6516
+ async function waitForConnectionAuthenticated(connection) {
6517
+ if (!connection.isAuthenticating || !connection.ws)
6518
+ return;
6519
+ const ws = connection.ws;
6520
+ await new Promise((resolve, reject) => {
6521
+ let timeout;
6522
+ let cleanup = () => { };
6523
+ const onMessage = (event) => {
6524
+ try {
6525
+ const message = JSON.parse(event.data);
6526
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'authenticated') {
6527
+ cleanup();
6528
+ resolve();
6529
+ }
6530
+ }
6531
+ catch (_a) {
6532
+ // Other frames are handled by the main listener.
6533
+ }
6534
+ };
6535
+ const onClose = () => {
6536
+ cleanup();
6537
+ reject(new Error('WebSocket disconnected during authentication'));
6538
+ };
6539
+ const onError = () => {
6540
+ cleanup();
6541
+ reject(new Error('WebSocket authentication failed'));
6542
+ };
6543
+ cleanup = () => {
6544
+ clearTimeout(timeout);
6545
+ ws.removeEventListener('message', onMessage);
6546
+ ws.removeEventListener('close', onClose);
6547
+ ws.removeEventListener('error', onError);
6548
+ };
6549
+ timeout = setTimeout(() => {
6550
+ cleanup();
6551
+ reject(new Error('WebSocket authentication timeout'));
6552
+ }, 10000);
6553
+ if (!connection.isAuthenticating) {
6554
+ cleanup();
6555
+ resolve();
6556
+ return;
6557
+ }
6558
+ ws.addEventListener('message', onMessage);
6559
+ ws.addEventListener('close', onClose);
6560
+ ws.addEventListener('error', onError);
6561
+ });
6562
+ }
6461
6563
  async function sendRequest(msgBuilder) {
6462
6564
  const config = await getConfig();
6463
6565
  const appId = config.appId;
@@ -6483,6 +6585,7 @@ async function sendRequest(msgBuilder) {
6483
6585
  if (!connection.ws || !connection.isConnected) {
6484
6586
  throw new Error('WebSocket connection not available');
6485
6587
  }
6588
+ await waitForConnectionAuthenticated(connection);
6486
6589
  const requestId = generateRequestId();
6487
6590
  const message = msgBuilder(requestId);
6488
6591
  return new Promise((resolve, reject) => {
@@ -6519,7 +6622,7 @@ function wsIntent(appId, roomRoutePath, intent) {
6519
6622
  const roomKey = roomKeyFromRoutePath(roomRoutePath);
6520
6623
  const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
6521
6624
  const connection = connections.get(connKey);
6522
- if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN) {
6625
+ if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
6523
6626
  return false;
6524
6627
  }
6525
6628
  try {
@@ -6542,7 +6645,7 @@ function wsIntentReliable(appId, roomRoutePath, intent) {
6542
6645
  const roomKey = roomKeyFromRoutePath(roomRoutePath);
6543
6646
  const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
6544
6647
  const connection = connections.get(connKey);
6545
- if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN) {
6648
+ if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
6546
6649
  return undefined;
6547
6650
  }
6548
6651
  const requestId = generateRequestId();
@@ -6869,6 +6972,7 @@ class RealtimeStore {
6869
6972
  this.idbDirtyKeys = new Set();
6870
6973
  this.closed = false;
6871
6974
  this.authToken = null;
6975
+ this.authenticating = false;
6872
6976
  this.isServer = false;
6873
6977
  this.tokenRefreshTimer = null;
6874
6978
  // -----------------------------------------------------------------------
@@ -6916,7 +7020,7 @@ class RealtimeStore {
6916
7020
  this.initPromise = this.init();
6917
7021
  await this.initPromise;
6918
7022
  }
6919
- if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN)
7023
+ if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN && !this.authenticating)
6920
7024
  return;
6921
7025
  if (this.connectPromise)
6922
7026
  return this.connectPromise;
@@ -6931,21 +7035,52 @@ class RealtimeStore {
6931
7035
  }
6932
7036
  const params = new URLSearchParams();
6933
7037
  params.set('apiKey', this.appId);
6934
- if (this.authToken)
6935
- params.set('authorization', this.authToken);
6936
- // Note: token in URL is required until DO server supports subprotocol auth.
6937
- // WSS encrypts the full URL including query params on the wire.
6938
7038
  const url = `${this.wsUrl}?${params.toString()}`;
6939
7039
  const ws = new WebSocket(url);
6940
7040
  this.ws = ws;
6941
- const onOpen = () => {
7041
+ let authTimer = null;
7042
+ const finishConnected = () => {
7043
+ if (authTimer) {
7044
+ clearTimeout(authTimer);
7045
+ authTimer = null;
7046
+ }
7047
+ this.authenticating = false;
6942
7048
  ws.removeEventListener('error', onError);
6943
7049
  this.reconnectDelay = 1000;
6944
7050
  this.connectPromise = null;
6945
7051
  this.resubscribeAll();
6946
7052
  resolve();
6947
7053
  };
7054
+ const onOpen = () => {
7055
+ if (!this.authToken) {
7056
+ finishConnected();
7057
+ return;
7058
+ }
7059
+ this.authenticating = true;
7060
+ authTimer = setTimeout(() => {
7061
+ this.authenticating = false;
7062
+ this.connectPromise = null;
7063
+ try {
7064
+ ws.close(1008, 'Authentication timeout');
7065
+ }
7066
+ catch ( /* ignore */_a) { /* ignore */ }
7067
+ reject(new Error('WebSocket authentication timeout'));
7068
+ }, 10000);
7069
+ try {
7070
+ ws.send(JSON.stringify({ type: 'auth', token: this.authToken }));
7071
+ }
7072
+ catch (e) {
7073
+ if (authTimer)
7074
+ clearTimeout(authTimer);
7075
+ this.authenticating = false;
7076
+ this.connectPromise = null;
7077
+ reject(e);
7078
+ }
7079
+ };
6948
7080
  const onError = (e) => {
7081
+ if (authTimer)
7082
+ clearTimeout(authTimer);
7083
+ this.authenticating = false;
6949
7084
  ws.removeEventListener('open', onOpen);
6950
7085
  this.connectPromise = null;
6951
7086
  reject(new Error('WebSocket connection failed'));
@@ -6953,9 +7088,22 @@ class RealtimeStore {
6953
7088
  ws.addEventListener('open', onOpen, { once: true });
6954
7089
  ws.addEventListener('error', onError, { once: true });
6955
7090
  ws.addEventListener('message', (event) => {
7091
+ if (this.authenticating) {
7092
+ try {
7093
+ const msg = JSON.parse(typeof event.data === 'string' ? event.data : new TextDecoder().decode(event.data));
7094
+ if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'authenticated') {
7095
+ finishConnected();
7096
+ return;
7097
+ }
7098
+ }
7099
+ catch ( /* fall through to normal handling */_a) { /* fall through to normal handling */ }
7100
+ }
6956
7101
  this.handleMessage(event.data);
6957
7102
  });
6958
7103
  ws.addEventListener('close', () => {
7104
+ if (authTimer)
7105
+ clearTimeout(authTimer);
7106
+ this.authenticating = false;
6959
7107
  this.ws = null;
6960
7108
  this.connectPromise = null;
6961
7109
  this.rejectAllPending('WebSocket closed');
@@ -7008,6 +7156,8 @@ class RealtimeStore {
7008
7156
  break;
7009
7157
  case 'pong':
7010
7158
  break;
7159
+ case 'authenticated':
7160
+ break;
7011
7161
  // v1 compat: handle legacy message types during transition
7012
7162
  case 'subscribed':
7013
7163
  this.handleSnapshot(Object.assign(Object.assign({}, msg), { type: 'snapshot', docs: msg.data }));
@@ -7609,6 +7759,17 @@ function resetRealtimeStore() {
7609
7759
  // rule, and dispatches to the function — returning its JSON, or throwing on
7610
7760
  // 403 / error.
7611
7761
  // ---------------------------------------------------------------------------
7762
+ var __rest = (undefined && undefined.__rest) || function (s, e) {
7763
+ var t = {};
7764
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
7765
+ t[p] = s[p];
7766
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7767
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7768
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
7769
+ t[p[i]] = s[p[i]];
7770
+ }
7771
+ return t;
7772
+ };
7612
7773
  /** Prod functions dispatcher; overridable via init({ functionsUrl }) or network preset. */
7613
7774
  const DEFAULT_FUNCTIONS_URL = 'https://functions.bounded.sh';
7614
7775
  class FunctionInvokeError extends Error {
@@ -7619,6 +7780,12 @@ class FunctionInvokeError extends Error {
7619
7780
  this.name = 'FunctionInvokeError';
7620
7781
  }
7621
7782
  }
7783
+ function stripAuthHeaders(headers) {
7784
+ if (!headers)
7785
+ return undefined;
7786
+ const { Authorization, authorization } = headers, rest = __rest(headers, ["Authorization", "authorization"]);
7787
+ return Object.keys(rest).length > 0 ? rest : undefined;
7788
+ }
7622
7789
  /**
7623
7790
  * Invoke a deployed Bounded Function by name. Returns the function's JSON.
7624
7791
  *
@@ -7641,7 +7808,7 @@ async function invoke(name, args = {}, opts = {}) {
7641
7808
  const authHeader = ((_a = opts._overrides) === null || _a === void 0 ? void 0 : _a._getAuthHeaders)
7642
7809
  ? await opts._overrides._getAuthHeaders()
7643
7810
  : await createAuthHeader(config.isServer);
7644
- const headers = Object.assign(Object.assign({ 'Content-Type': 'application/json', 'X-App-Id': config.appId, 'X-Public-App-Id': config.appId }, (authHeader !== null && authHeader !== void 0 ? authHeader : {})), ((_b = opts.headers) !== null && _b !== void 0 ? _b : {}));
7811
+ const headers = Object.assign(Object.assign({ 'Content-Type': 'application/json', 'X-App-Id': config.appId, 'X-Public-App-Id': config.appId }, ((_b = stripAuthHeaders(opts.headers)) !== null && _b !== void 0 ? _b : {})), (authHeader !== null && authHeader !== void 0 ? authHeader : {}));
7645
7812
  const controller = new AbortController();
7646
7813
  const timeoutMs = (_c = opts.timeoutMs) !== null && _c !== void 0 ? _c : 60000;
7647
7814
  const timer = setTimeout(() => controller.abort(), timeoutMs);