import {
  __export,
  __reExport
} from "./chunk-F5QR3K72.js";

// ../shared/src/valita.ts
var valita_exports = {};
__export(valita_exports, {
  assert: () => assert,
  is: () => is,
  parse: () => parse,
  readonly: () => readonly,
  readonlyArray: () => readonlyArray,
  readonlyObject: () => readonlyObject,
  readonlyRecord: () => readonlyRecord,
  test: () => test
});
__reExport(valita_exports, valita_star);
import * as v from "@badrap/valita";
import * as valita_star from "@badrap/valita";
function toDisplay(value) {
  switch (typeof value) {
    case "string":
    case "number":
    case "boolean":
      return JSON.stringify(value);
    case "undefined":
      return "undefined";
    case "bigint":
      return value.toString() + "n";
    default:
      if (value === null) {
        return "null";
      }
      if (Array.isArray(value)) {
        return "array";
      }
      return typeof value;
  }
}
function toDisplayAtPath(v2, path2) {
  if (!path2?.length) {
    return toDisplay(v2);
  }
  let cur = v2;
  for (const p of path2) {
    cur = cur[p];
  }
  return toDisplay(cur);
}
function displayList(word, expected, toDisplay2 = (x) => String(x)) {
  if (expected.length === 1) {
    return toDisplay2(expected[0]);
  }
  const suffix = `${toDisplay2(
    expected[expected.length - 2]
  )} ${word} ${toDisplay2(expected[expected.length - 1])}`;
  if (expected.length === 2) {
    return suffix;
  }
  return `${expected.slice(0, -2).map(toDisplay2).join(", ")}, ${suffix}`;
}
function getMessage(err2, v2) {
  const firstIssue = err2.issues[0];
  const { path: path2 } = firstIssue;
  const atPath = path2?.length ? ` at ${path2.join(".")}` : "";
  switch (firstIssue.code) {
    case "invalid_type":
      return `Expected ${displayList(
        "or",
        firstIssue.expected
      )}${atPath}. Got ${toDisplayAtPath(v2, path2)}`;
    case "missing_value": {
      const atPath2 = path2 && path2.length > 1 ? ` at ${path2.slice(0, -1).join(".")}` : "";
      if (firstIssue.path?.length) {
        return `Missing property ${firstIssue.path.at(-1)}${atPath2}`;
      }
      return `TODO Unknown missing property${atPath2}`;
    }
    case "invalid_literal":
      return `Expected literal value ${displayList(
        "or",
        firstIssue.expected,
        toDisplay
      )}${atPath} Got ${toDisplayAtPath(v2, path2)}`;
    case "invalid_length": {
      return `Expected array with length ${firstIssue.minLength === firstIssue.maxLength ? firstIssue.minLength : `between ${firstIssue.minLength} and ${firstIssue.maxLength}`}${atPath}. Got array with length ${v2.length}`;
    }
    case "unrecognized_keys":
      if (firstIssue.keys.length === 1) {
        return `Unexpected property ${firstIssue.keys[0]}${atPath}`;
      }
      return `Unexpected properties ${displayList(
        "and",
        firstIssue.keys
      )}${atPath}`;
    case "invalid_union":
      return `Invalid union value${atPath}`;
    case "custom_error": {
      const { error } = firstIssue;
      const message = !error ? "unknown" : typeof error === "string" ? error : error.message ?? "unknown";
      return `${message}${atPath}. Got ${toDisplayAtPath(v2, path2)}`;
    }
  }
}
function parse(value, schema, mode) {
  const res = test(value, schema, mode);
  if (!res.ok) {
    throw new TypeError(res.error);
  }
  return res.value;
}
function is(value, schema, mode) {
  return test(value, schema, mode).ok;
}
function assert(value, schema, mode) {
  parse(value, schema, mode);
}
function test(value, schema, mode) {
  const res = schema.try(value, mode ? { mode } : void 0);
  if (!res.ok) {
    return { ok: false, error: getMessage(res, value) };
  }
  return res;
}
function readonly(t) {
  return t;
}
function readonlyObject(t) {
  return readonly(v.object(t));
}
function readonlyArray(t) {
  return readonly(v.array(t));
}
function readonlyRecord(t) {
  return readonly(v.record(t));
}

// ../shared/src/asserts.ts
function assert2(b, msg = "Assertion failed") {
  if (!b) {
    throw new Error(msg);
  }
}

// ../reflect-protocol/src/version.ts
var versionSchema = valita_exports.number();
var nullableVersionSchema = valita_exports.union(versionSchema, valita_exports.null());

// ../reflect-protocol/src/connected.ts
var connectedBodySchema = valita_exports.object({
  wsid: valita_exports.string(),
  timestamp: valita_exports.number().optional()
});
var connectedMessageSchema = valita_exports.tuple([
  valita_exports.literal("connected"),
  connectedBodySchema
]);

// ../reflect-protocol/src/error.ts
var errorKindSchema = valita_exports.union(
  valita_exports.literal("AuthInvalidated"),
  valita_exports.literal("ClientNotFound"),
  valita_exports.literal("InvalidConnectionRequest"),
  valita_exports.literal("InvalidConnectionRequestBaseCookie"),
  valita_exports.literal("InvalidConnectionRequestLastMutationID"),
  valita_exports.literal("InvalidMessage"),
  valita_exports.literal("InvalidPush"),
  valita_exports.literal("RoomClosed"),
  valita_exports.literal("RoomNotFound"),
  valita_exports.literal("Unauthorized"),
  valita_exports.literal("VersionNotSupported")
);
var errorMessageSchema = valita_exports.tuple([
  valita_exports.literal("error"),
  errorKindSchema,
  valita_exports.string()
]);

// ../shared/src/json-schema.ts
import * as valita from "@badrap/valita";

// ../shared/src/config.ts
var isProd = false;

// ../shared/src/has-own.ts
var objectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty;
var hasOwn = Object.hasOwn || ((object11, key) => objectPrototypeHasOwnProperty.call(object11, key));

// ../shared/src/json.ts
function isJSONValue(v2, path2) {
  switch (typeof v2) {
    case "boolean":
    case "number":
    case "string":
      return true;
    case "object":
      if (v2 === null) {
        return true;
      }
      if (Array.isArray(v2)) {
        return isJSONArray(v2, path2);
      }
      return objectIsJSONObject(v2, path2);
  }
  return false;
}
function objectIsJSONObject(v2, path2) {
  for (const k in v2) {
    if (hasOwn(v2, k)) {
      path2.push(k);
      const value = v2[k];
      if (value !== void 0 && !isJSONValue(value, path2)) {
        return false;
      }
      path2.pop();
    }
  }
  return true;
}
function isJSONArray(v2, path2) {
  for (let i = 0; i < v2.length; i++) {
    path2.push(i);
    if (!isJSONValue(v2[i], path2)) {
      return false;
    }
    path2.pop();
  }
  return true;
}

// ../shared/src/json-schema.ts
var path = [];
var jsonSchema = valita_exports.unknown().chain((v2) => {
  if (isProd) {
    return valita.ok(v2);
  }
  const rv = isJSONValue(v2, path) ? valita.ok(v2) : valita.err({
    message: `Not a JSON value`,
    path: path.slice()
  });
  path.length = 0;
  return rv;
});

// ../reflect-protocol/src/patch.ts
var putOpSchema = valita_exports.object({
  op: valita_exports.literal("put"),
  key: valita_exports.string(),
  value: jsonSchema
});
var delOpSchema = valita_exports.object({
  op: valita_exports.literal("del"),
  key: valita_exports.string()
});
var clearOpSchema = valita_exports.object({
  op: valita_exports.literal("clear")
});
var patchOpSchema = valita_exports.union(putOpSchema, delOpSchema, clearOpSchema);
var patchSchema = valita_exports.array(patchOpSchema);

// ../reflect-protocol/src/poke.ts
var pokeSchema = valita_exports.object({
  // We always specify a Version as our cookie, but Replicache starts clients
  // with initial cookie `null`, before the first request. So we have to be
  // able to send a base cookie with value `null` to match that state.
  baseCookie: nullableVersionSchema,
  cookie: versionSchema,
  lastMutationIDChanges: valita_exports.record(valita_exports.number()),
  // Patch keys are clientIDs.  Currently only the keys are used to indicate
  // presense/absence of clientID, values are ignored but may be used
  // in the future.
  presence: patchSchema.optional(),
  patch: patchSchema,
  timestamp: valita_exports.number().optional(),
  // Following debug fields are set when client's connect request has
  // debugPerf=true
  debugOriginTimestamp: valita_exports.number().optional(),
  debugServerReceivedTimestamp: valita_exports.number().optional(),
  debugServerSentTimestamp: valita_exports.number().optional()
});
var pokeBodySchema = valita_exports.object({
  pokes: valita_exports.array(pokeSchema),
  requestID: valita_exports.string(),
  // Set when client's connect request has debugPerf=true
  debugServerBufferMs: valita_exports.number().optional()
});
var pokeMessageSchema = valita_exports.tuple([valita_exports.literal("poke"), pokeBodySchema]);

// ../reflect-protocol/src/pong.ts
var pongBodySchema = valita_exports.object({});
var pongMessageSchema = valita_exports.tuple([valita_exports.literal("pong"), pongBodySchema]);

// ../reflect-protocol/src/pull.ts
var pullRequestBodySchema = valita_exports.object({
  clientGroupID: valita_exports.string(),
  cookie: nullableVersionSchema,
  requestID: valita_exports.string()
});
var pullResponseBodySchema = valita_exports.object({
  cookie: versionSchema,
  // Matches pullRequestBodySchema requestID that initiated this response
  requestID: valita_exports.string(),
  lastMutationIDChanges: valita_exports.record(valita_exports.number())
  // Pull is currently only used for mutation recovery which does not use
  // the patch so we save work by not computing the patch.
});
var pullRequestMessageSchema = valita_exports.tuple([
  valita_exports.literal("pull"),
  pullRequestBodySchema
]);
var pullResponseMessageSchema = valita_exports.tuple([
  valita_exports.literal("pull"),
  pullResponseBodySchema
]);

// ../reflect-protocol/src/down.ts
var downstreamSchema = valita_exports.union(
  connectedMessageSchema,
  pokeMessageSchema,
  pullResponseMessageSchema,
  errorMessageSchema,
  pongMessageSchema
);

// ../reflect-protocol/src/api/auth.ts
var connectionsResponseSchema = valita_exports.array(
  valita_exports.object({
    userID: valita_exports.string(),
    clientID: valita_exports.string()
  })
);

// ../reflect-protocol/src/api/room.ts
var createRoomRequestSchema = valita_exports.object({
  jurisdiction: valita_exports.literal("eu").optional()
});

// ../reflect-protocol/src/ping.ts
var pingBodySchema = valita_exports.object({});
var pingMessageSchema = valita_exports.tuple([valita_exports.literal("ping"), pingBodySchema]);

// ../reflect-protocol/src/push.ts
var mutationSchema = valita_exports.object({
  id: valita_exports.number(),
  clientID: valita_exports.string(),
  name: valita_exports.string(),
  args: jsonSchema,
  timestamp: valita_exports.number()
});
var pushBodySchema = valita_exports.object({
  clientGroupID: valita_exports.string(),
  mutations: valita_exports.array(mutationSchema),
  pushVersion: valita_exports.number(),
  schemaVersion: valita_exports.string(),
  timestamp: valita_exports.number(),
  requestID: valita_exports.string()
});
var pushMessageSchema = valita_exports.tuple([valita_exports.literal("push"), pushBodySchema]);

// ../reflect-protocol/src/up.ts
var upstreamSchema = valita_exports.union(
  pingMessageSchema,
  pushMessageSchema,
  pullRequestMessageSchema
);

// ../datadog/out/datadog-log-sink.js
import { Lock } from "@rocicorp/lock";
var DD_BASE_URL = new URL("https://http-intake.logs.datadoghq.com/api/v2/logs");
var MAX_LOG_ENTRIES_PER_FLUSH = 1e3;
var FORCE_FLUSH_THRESHOLD = 250;
var MAX_ENTRY_BYTES = 5 * 1024 * 1024;
var MAX_MESSAGE_RETRIES = 2;
var MAX_ENTRY_CHARS = MAX_ENTRY_BYTES / 4;
var DatadogLogSink = class {
  #messages = [];
  #apiKey;
  #source;
  #service;
  #host;
  #version;
  #interval;
  #baseURL;
  #timerID = 0;
  #flushLock = new Lock();
  constructor(options) {
    const { apiKey, source, service, host, version, interval = 5e3, baseURL: baseUrl = DD_BASE_URL } = options;
    this.#apiKey = apiKey;
    this.#source = source;
    this.#service = service;
    this.#host = host;
    this.#version = version;
    this.#interval = interval;
    this.#baseURL = baseUrl.toString();
  }
  log(level, context, ...args) {
    this.#messages.push(makeMessage(args, context, level));
    if (level === "error" || this.#messages.length === FORCE_FLUSH_THRESHOLD) {
      void this.flush();
    } else {
      this.#startTimer();
    }
  }
  #startTimer() {
    if (this.#timerID) {
      return;
    }
    this.#timerID = setTimeout(() => {
      this.#timerID = 0;
      void this.flush();
    }, this.#interval);
  }
  flush() {
    return this.#flushLock.withLock(async () => {
      const { length } = this.#messages;
      if (length === 0) {
        return;
      }
      do {
        const flushTime = Date.now();
        const stringified = [];
        let totalBytes = 0;
        for (const m of this.#messages) {
          m.flushDelayMs = flushTime - m.date;
          let str = JSON.stringify(m);
          if (str.length > MAX_ENTRY_CHARS) {
            m.message = `[Dropped message of length ${str.length}]`;
            str = JSON.stringify(m);
          }
          if (str.length + totalBytes + stringified.length > MAX_ENTRY_CHARS) {
            break;
          }
          totalBytes += str.length;
          stringified.push(str);
          if (stringified.length === MAX_LOG_ENTRIES_PER_FLUSH) {
            break;
          }
        }
        const body = stringified.join("\n");
        const url = new URL(this.#baseURL);
        if (this.#apiKey !== void 0) {
          url.searchParams.set("dd-api-key", this.#apiKey);
        }
        if (this.#source) {
          url.searchParams.set("ddsource", this.#source);
          url.searchParams.set("dd-evp-origin", this.#source);
        }
        if (this.#service) {
          url.searchParams.set("service", this.#service);
        }
        if (this.#host) {
          url.searchParams.set("host", this.#host);
        }
        if (this.#version) {
          url.searchParams.set("ddtags", `version:${this.#version}`);
        }
        let ok2 = false;
        try {
          const response = await fetch(url.toString(), {
            method: "POST",
            body,
            keepalive: true
          });
          ok2 = response.ok;
          if (!ok2) {
            console.error("response", response.status, response.statusText, await response.text);
          }
        } catch (e) {
          console.error("Log flush to datadog failed", e);
        }
        if (ok2) {
          this.#messages.splice(0, stringified.length);
        } else {
          let numWithTooManyRetries = 0;
          for (let i = 0; i < stringified.length; i++) {
            const m = this.#messages[i];
            m.flushRetryCount = (m.flushRetryCount ?? 0) + 1;
            if (m.flushRetryCount > MAX_MESSAGE_RETRIES) {
              numWithTooManyRetries++;
            }
          }
          if (numWithTooManyRetries > 0) {
            console.error(`Dropping ${numWithTooManyRetries} datadog log messages which failed to send ${MAX_MESSAGE_RETRIES + 1} times.`);
            this.#messages.splice(0, numWithTooManyRetries);
          }
        }
      } while (this.#messages.length >= FORCE_FLUSH_THRESHOLD);
      if (this.#messages.length) {
        this.#startTimer();
      }
    });
  }
};
function flattenMessage(message) {
  if (Array.isArray(message) && message.length === 1) {
    return flattenMessage(message[0]);
  }
  return message;
}
function convertError(e) {
  return {
    name: e.name,
    message: e.message,
    stack: e.stack
  };
}
function convertErrors(message) {
  if (message instanceof Error) {
    return convertError(message);
  }
  if (message instanceof Array) {
    const convertedMessage = [];
    for (const item of message) {
      if (item instanceof Error) {
        convertedMessage.push(convertError(item));
      } else {
        convertedMessage.push(item);
      }
    }
    return convertedMessage;
  }
  return message;
}
var LOG_SINK_FLUSH_RETRY_COUNT = "flushRetryCount";
var LOG_SINK_FLUSH_DELAY_ATTRIBUTE = "flushDelayMs";
var RESERVED_KEY_PREFIX = "@DATADOG_RESERVED_";
var RESERVED_KEYS = [
  "host",
  "source",
  "status",
  "service",
  "version",
  "trace_id",
  "message",
  "msg",
  "date",
  // The following are attributes reserved by the DataDogLogSink
  // itself (as opposed to DataDog), to report on its own behavior.
  LOG_SINK_FLUSH_DELAY_ATTRIBUTE,
  LOG_SINK_FLUSH_RETRY_COUNT
];
function makeMessage(message, context, logLevel) {
  let safeContext = void 0;
  if (context !== void 0) {
    for (const reservedKey of RESERVED_KEYS) {
      if (Object.hasOwn(context, reservedKey)) {
        if (safeContext === void 0) {
          safeContext = { ...context };
        }
        safeContext[RESERVED_KEY_PREFIX + reservedKey] = safeContext[reservedKey];
        delete safeContext[reservedKey];
      }
    }
  }
  const msg = {
    ...safeContext ?? context,
    date: Date.now(),
    message: convertErrors(flattenMessage(message)),
    status: logLevel
  };
  if (logLevel === "error") {
    msg.error = { origin: "logger" };
  }
  return msg;
}

// ../reflect-shared/src/config.ts
var defaultConfig = {
  closeBeacon: true
};
Object.freeze(defaultConfig);
var config = { ...defaultConfig };
function getConfig(name) {
  return config[name];
}

// ../reflect-shared/src/paths.ts
var CLOSE_BEACON_PATH = "/api/sync/v1/close";

// ../shared/src/buffer-sizer.ts
var BufferSizer = class {
  #bufferSizeMs;
  #initialBufferSizeMs;
  #minBufferSizeMs;
  #maxBufferSizeMs;
  #adjustBufferSizeIntervalMs;
  #bufferNeededMsHistory = [];
  #missableCountSinceLastBufferAdjust = 0;
  #missedCountSinceLastBufferAdjust = 0;
  #timeOfLastBufferAdjust = -1;
  #ignoreNextMissable = false;
  constructor(options) {
    assert2(options.minBufferSizeMs <= options.maxBufferSizeMs);
    assert2(options.initialBufferSizeMs >= options.minBufferSizeMs);
    assert2(options.initialBufferSizeMs <= options.maxBufferSizeMs);
    assert2(options.adjustBufferSizeIntervalMs > 0);
    this.#initialBufferSizeMs = options.initialBufferSizeMs;
    this.#minBufferSizeMs = options.minBufferSizeMs;
    this.#maxBufferSizeMs = options.maxBufferSizeMs;
    this.#adjustBufferSizeIntervalMs = options.adjustBufferSizeIntervalMs;
    this.#bufferSizeMs = this.#initialBufferSizeMs;
  }
  get bufferSizeMs() {
    return this.#bufferSizeMs;
  }
  recordMissable(now, missed, bufferNeededMs, lc) {
    if (this.#ignoreNextMissable) {
      this.#ignoreNextMissable = false;
      return;
    }
    lc = lc.withContext("BufferSizer");
    this.#bufferNeededMsHistory.push(bufferNeededMs);
    this.#missableCountSinceLastBufferAdjust++;
    if (missed) {
      this.#missedCountSinceLastBufferAdjust++;
    }
    if (this.#timeOfLastBufferAdjust === -1) {
      this.#timeOfLastBufferAdjust = now;
      return;
    }
    if (now - this.#timeOfLastBufferAdjust < this.#adjustBufferSizeIntervalMs) {
      return;
    }
    if (this.#missableCountSinceLastBufferAdjust < 200) {
      return;
    }
    this.#bufferNeededMsHistory.sort((a, b) => a - b);
    const targetBufferNeededMs = this.#bufferNeededMsHistory[Math.floor(this.#bufferNeededMsHistory.length * 99.5 / 100)];
    const bufferSizeMs = this.#bufferSizeMs;
    lc.info?.(
      "bufferSizeMs",
      bufferSizeMs,
      "targetBufferNeededMs",
      targetBufferNeededMs,
      "this._maxBufferNeededMs.length",
      this.#bufferNeededMsHistory.length,
      "percentile index",
      Math.floor(this.#bufferNeededMsHistory.length * 99.5 / 100),
      this.#bufferNeededMsHistory
    );
    let newBufferSizeMs = bufferSizeMs;
    const missPercent = this.#missedCountSinceLastBufferAdjust / this.#missableCountSinceLastBufferAdjust;
    if (missPercent > 0.01) {
      newBufferSizeMs = Math.min(
        this.#maxBufferSizeMs,
        Math.max(bufferSizeMs, targetBufferNeededMs)
      );
      lc.info?.(
        "High miss percent",
        missPercent,
        "over last",
        now - this.#timeOfLastBufferAdjust,
        "ms."
      );
    } else if (missPercent < 5e-3) {
      newBufferSizeMs = Math.max(
        this.#minBufferSizeMs,
        Math.min(bufferSizeMs, targetBufferNeededMs)
      );
      lc.info?.(
        "Low miss percent",
        missPercent,
        "over last",
        now - this.#timeOfLastBufferAdjust,
        "ms."
      );
    }
    if (bufferSizeMs !== newBufferSizeMs) {
      lc.info?.(
        "Adjusting buffer",
        newBufferSizeMs > bufferSizeMs ? "up" : "down",
        "from",
        bufferSizeMs,
        "to",
        newBufferSizeMs
      );
    }
    this.#bufferNeededMsHistory = [];
    this.#missableCountSinceLastBufferAdjust = 0;
    this.#missedCountSinceLastBufferAdjust = 0;
    this.#timeOfLastBufferAdjust = now;
    this.#bufferSizeMs = newBufferSizeMs;
    this.#ignoreNextMissable = true;
  }
  reset() {
    this.#bufferSizeMs = this.#initialBufferSizeMs;
    this.#bufferNeededMsHistory = [];
    this.#missableCountSinceLastBufferAdjust = 0;
    this.#missedCountSinceLastBufferAdjust = 0;
    this.#timeOfLastBufferAdjust = -1;
    this.#ignoreNextMissable = false;
  }
};

export {
  parse,
  valita_exports,
  connectionsResponseSchema,
  createRoomRequestSchema,
  assert2 as assert,
  jsonSchema,
  versionSchema,
  nullableVersionSchema,
  downstreamSchema,
  upstreamSchema,
  getConfig,
  CLOSE_BEACON_PATH,
  DatadogLogSink,
  BufferSizer
};
//# sourceMappingURL=chunk-4ZRNZFBK.js.map
