{"version":3,"file":"validate-config.cjs","sources":["../../../src/collection/validate-config.ts"],"sourcesContent":["import {\n  CollectionRequiresConfigError,\n  CollectionRequiresSyncConfigError,\n} from '../errors'\nimport {\n  CollectionRequiresGetKeyError,\n  InvalidCallbackOptionError,\n  InvalidGetKeyError,\n  InvalidOptionTypeError,\n  InvalidSyncConfigError,\n  InvalidSyncFunctionError,\n} from './config-errors'\n\n/**\n * Known top-level config properties for createCollection.\n * Extra properties are allowed; these names are only used for typo suggestions.\n */\nconst KNOWN_CONFIG_KEYS = new Set([\n  `id`,\n  `schema`,\n  `getKey`,\n  `sync`,\n  `gcTime`,\n  `startSync`,\n  `autoIndex`,\n  `defaultIndexType`,\n  `compare`,\n  `syncMode`,\n  `defaultStringCollation`,\n  `onInsert`,\n  `onUpdate`,\n  `onDelete`,\n  `utils`,\n  `singleResult`,\n  // Metadata returned by persistedCollectionOptions.\n  `persistence`,\n])\n\n// Limit suggestions to casing mistakes and adjacent swaps in longer names.\n// Broader edit-distance matching can mistake adapter fields for core options.\nfunction findLikelyTypo(\n  key: string,\n  config: Record<string, unknown>,\n): string | undefined {\n  for (const knownKey of KNOWN_CONFIG_KEYS) {\n    if (knownKey in config) continue\n    if (key.toLowerCase() === knownKey.toLowerCase()) return knownKey\n    if (key.length < 5 || key.length !== knownKey.length) continue\n\n    for (let i = 0; i < key.length - 1; i++) {\n      const swapped = key.slice(0, i) + key[i + 1] + key[i] + key.slice(i + 2)\n      if (swapped === knownKey) return knownKey\n    }\n  }\n  return undefined\n}\n\nfunction describeType(value: unknown): string {\n  if (value === null) return `null`\n  if (value === undefined) return `undefined`\n  if (Array.isArray(value)) return `an array`\n  return typeof value\n}\n\n/**\n * Validates the collection config at runtime, providing clear error messages\n * for common misconfiguration mistakes that would otherwise surface as\n * unreadable TypeScript errors.\n *\n * This runs before the config is passed to CollectionImpl, catching issues\n * early with actionable error messages.\n */\nexport function validateCollectionConfig(config: unknown): void {\n  // Check config exists and is an object\n  if (!config || typeof config !== `object` || Array.isArray(config)) {\n    throw new CollectionRequiresConfigError()\n  }\n\n  const configObj = config as Record<string, unknown>\n\n  // Adapter metadata is valid. Warn only when an extra key is likely a typo.\n  for (const key of Object.keys(configObj)) {\n    if (!KNOWN_CONFIG_KEYS.has(key) && !key.startsWith(`_`)) {\n      const suggestion = findLikelyTypo(key, configObj)\n      if (suggestion) {\n        console.warn(\n          `Possible misspelling in collection config: \"${key}\". Did you mean \"${suggestion}\"?`,\n        )\n      }\n    }\n  }\n\n  // Validate getKey\n  if (!(`getKey` in configObj) || configObj.getKey === undefined) {\n    throw new CollectionRequiresGetKeyError()\n  }\n  if (typeof configObj.getKey !== `function`) {\n    throw new InvalidGetKeyError(describeType(configObj.getKey))\n  }\n\n  // Validate sync\n  if (!configObj.sync) {\n    throw new CollectionRequiresSyncConfigError()\n  }\n  if (typeof configObj.sync !== `object` || Array.isArray(configObj.sync)) {\n    throw new InvalidSyncConfigError(describeType(configObj.sync))\n  }\n  const syncObj = configObj.sync as Record<string, unknown>\n  if (typeof syncObj.sync !== `function`) {\n    throw new InvalidSyncFunctionError(describeType(syncObj.sync))\n  }\n\n  // Validate callback options\n  const callbackOptions = [\n    `onInsert`,\n    `onUpdate`,\n    `onDelete`,\n    `compare`,\n  ] as const\n  for (const optionName of callbackOptions) {\n    if (\n      optionName in configObj &&\n      configObj[optionName] !== undefined &&\n      typeof configObj[optionName] !== `function`\n    ) {\n      throw new InvalidCallbackOptionError(\n        optionName,\n        describeType(configObj[optionName]),\n      )\n    }\n  }\n\n  // Validate id\n  if (`id` in configObj && configObj.id !== undefined) {\n    if (typeof configObj.id !== `string`) {\n      throw new InvalidOptionTypeError(\n        `id`,\n        `a string`,\n        describeType(configObj.id),\n      )\n    }\n  }\n\n  // Validate gcTime\n  if (`gcTime` in configObj && configObj.gcTime !== undefined) {\n    if (typeof configObj.gcTime !== `number`) {\n      throw new InvalidOptionTypeError(\n        `gcTime`,\n        `a number`,\n        describeType(configObj.gcTime),\n      )\n    }\n  }\n\n  // Validate startSync\n  if (`startSync` in configObj && configObj.startSync !== undefined) {\n    if (typeof configObj.startSync !== `boolean`) {\n      throw new InvalidOptionTypeError(\n        `startSync`,\n        `a boolean`,\n        describeType(configObj.startSync),\n      )\n    }\n  }\n\n  // Validate autoIndex\n  if (`autoIndex` in configObj && configObj.autoIndex !== undefined) {\n    if (configObj.autoIndex !== `off` && configObj.autoIndex !== `eager`) {\n      throw new InvalidOptionTypeError(\n        `autoIndex`,\n        `\"off\" or \"eager\"`,\n        String(configObj.autoIndex),\n      )\n    }\n  }\n\n  // Validate syncMode\n  if (`syncMode` in configObj && configObj.syncMode !== undefined) {\n    if (configObj.syncMode !== `eager` && configObj.syncMode !== `on-demand`) {\n      throw new InvalidOptionTypeError(\n        `syncMode`,\n        `\"eager\" or \"on-demand\"`,\n        String(configObj.syncMode),\n      )\n    }\n  }\n\n  // Validate utils\n  if (`utils` in configObj && configObj.utils !== undefined) {\n    if (\n      typeof configObj.utils !== `object` ||\n      configObj.utils === null ||\n      Array.isArray(configObj.utils)\n    ) {\n      throw new InvalidOptionTypeError(\n        `utils`,\n        `an object`,\n        describeType(configObj.utils),\n      )\n    }\n  }\n}\n"],"names":["CollectionRequiresConfigError","CollectionRequiresGetKeyError","InvalidGetKeyError","CollectionRequiresSyncConfigError","InvalidSyncConfigError","InvalidSyncFunctionError","InvalidCallbackOptionError","InvalidOptionTypeError"],"mappings":"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"}