tersejson 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +47 -4
  2. package/dist/{client-BQAZg7I8.d.mts → client-CFGvusCj.d.mts} +1 -1
  3. package/dist/{client-DOOGwp_p.d.ts → client-hUXNNGcN.d.ts} +1 -1
  4. package/dist/client.d.mts +2 -2
  5. package/dist/client.d.ts +2 -2
  6. package/dist/client.js.map +1 -1
  7. package/dist/client.mjs.map +1 -1
  8. package/dist/{express-LSVylWpN.d.ts → express-Da7WcJtt.d.ts} +1 -1
  9. package/dist/{express-BoL__Ao6.d.mts → express-O5w2NBTf.d.mts} +1 -1
  10. package/dist/express.d.mts +2 -2
  11. package/dist/express.d.ts +2 -2
  12. package/dist/graphql-C3PTnqnZ.d.mts +81 -0
  13. package/dist/graphql-DmtweJgh.d.ts +81 -0
  14. package/dist/graphql-client-2H4FjmRc.d.mts +123 -0
  15. package/dist/graphql-client-BXGtWqe9.d.ts +123 -0
  16. package/dist/graphql-client.d.mts +2 -0
  17. package/dist/graphql-client.d.ts +2 -0
  18. package/dist/graphql-client.js +215 -0
  19. package/dist/graphql-client.js.map +1 -0
  20. package/dist/graphql-client.mjs +207 -0
  21. package/dist/graphql-client.mjs.map +1 -0
  22. package/dist/graphql.d.mts +3 -0
  23. package/dist/graphql.d.ts +3 -0
  24. package/dist/graphql.js +304 -0
  25. package/dist/graphql.js.map +1 -0
  26. package/dist/graphql.mjs +296 -0
  27. package/dist/graphql.mjs.map +1 -0
  28. package/dist/index.d.mts +5 -3
  29. package/dist/index.d.ts +5 -3
  30. package/dist/index.js +400 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +398 -4
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/integrations.js.map +1 -1
  35. package/dist/integrations.mjs.map +1 -1
  36. package/dist/{types-CzaGQaV7.d.mts → types-BTonKlz8.d.mts} +56 -1
  37. package/dist/{types-CzaGQaV7.d.ts → types-BTonKlz8.d.ts} +56 -1
  38. package/package.json +44 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts","../src/graphql.ts"],"names":[],"mappings":"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","file":"graphql.js","sourcesContent":["/**\n * TerseJSON Core\n *\n * The core compression and expansion algorithms.\n */\n\nimport {\n TersePayload,\n isTersePayload,\n KeyPattern,\n KeyGenerator,\n NestedHandling,\n CompressOptions,\n} from './types';\n\n// ============================================================================\n// KEY PATTERN GENERATORS\n// ============================================================================\n\n/**\n * Alpha pattern: a, b, c, ... z, aa, ab, ...\n */\nfunction alphaGenerator(index: number): string {\n let key = '';\n let remaining = index;\n\n do {\n key = String.fromCharCode(97 + (remaining % 26)) + key;\n remaining = Math.floor(remaining / 26) - 1;\n } while (remaining >= 0);\n\n return key;\n}\n\n/**\n * Numeric pattern: 0, 1, 2, ... 9, 10, 11, ...\n */\nfunction numericGenerator(index: number): string {\n return String(index);\n}\n\n/**\n * Alphanumeric pattern: a1, a2, ... a9, b1, b2, ...\n */\nfunction alphanumericGenerator(index: number): string {\n const letterIndex = Math.floor(index / 9);\n const numIndex = (index % 9) + 1;\n return alphaGenerator(letterIndex) + numIndex;\n}\n\n/**\n * Short pattern: uses shortest possible keys\n * _, a, b, ..., z, aa, ab, ...\n */\nfunction shortGenerator(index: number): string {\n if (index === 0) return '_';\n return alphaGenerator(index - 1);\n}\n\n/**\n * Prefixed pattern: k0, k1, k2, ...\n */\nfunction prefixedGenerator(prefix: string, style: 'numeric' | 'alpha' = 'numeric'): KeyGenerator {\n return (index: number) => {\n if (style === 'alpha') {\n return prefix + alphaGenerator(index);\n }\n return prefix + index;\n };\n}\n\n/**\n * Creates a key generator from a pattern configuration\n */\nexport function createKeyGenerator(pattern: KeyPattern): { generator: KeyGenerator; name: string } {\n // If it's already a function, use it directly\n if (typeof pattern === 'function') {\n return { generator: pattern, name: 'custom' };\n }\n\n // If it's a preset string\n if (typeof pattern === 'string') {\n switch (pattern) {\n case 'alpha':\n return { generator: alphaGenerator, name: 'alpha' };\n case 'numeric':\n return { generator: numericGenerator, name: 'numeric' };\n case 'alphanumeric':\n return { generator: alphanumericGenerator, name: 'alphanumeric' };\n case 'short':\n return { generator: shortGenerator, name: 'short' };\n case 'prefixed':\n return { generator: prefixedGenerator('k'), name: 'prefixed:k' };\n default:\n return { generator: alphaGenerator, name: 'alpha' };\n }\n }\n\n // If it's a prefix config object\n if (typeof pattern === 'object' && 'prefix' in pattern) {\n return {\n generator: prefixedGenerator(pattern.prefix, pattern.style || 'numeric'),\n name: `prefixed:${pattern.prefix}`,\n };\n }\n\n return { generator: alphaGenerator, name: 'alpha' };\n}\n\n/**\n * Resolves nested handling to a numeric depth\n */\nfunction resolveNestedDepth(handling: NestedHandling | undefined, maxDepth: number): number {\n if (handling === undefined || handling === 'deep') {\n return maxDepth;\n }\n if (handling === 'shallow') {\n return 1;\n }\n if (handling === 'arrays') {\n return maxDepth; // Special handling in collect/compress functions\n }\n if (typeof handling === 'number') {\n return handling;\n }\n return maxDepth;\n}\n\n// Legacy generateShortKey removed - use createKeyGenerator instead\n\ninterface CollectKeysOptions {\n minKeyLength: number;\n maxDepth: number;\n nestedHandling: NestedHandling;\n excludeKeys?: string[];\n includeKeys?: string[];\n homogeneousOnly?: boolean;\n}\n\n/**\n * Collects all unique keys from an array of objects\n */\nfunction collectKeys(\n data: Record<string, unknown>[],\n options: CollectKeysOptions,\n currentDepth: number = 0\n): Set<string> {\n const keys = new Set<string>();\n const { minKeyLength, maxDepth, nestedHandling, excludeKeys, includeKeys } = options;\n\n if (currentDepth >= maxDepth) return keys;\n\n // For homogeneous mode, track key counts\n const keyCounts = new Map<string, number>();\n\n for (const item of data) {\n if (typeof item !== 'object' || item === null) continue;\n\n for (const key of Object.keys(item)) {\n // Skip excluded keys\n if (excludeKeys?.includes(key)) continue;\n\n // Include if in includeKeys, or if meets minKeyLength\n const shouldInclude = includeKeys?.includes(key) || key.length >= minKeyLength;\n\n if (shouldInclude) {\n keys.add(key);\n keyCounts.set(key, (keyCounts.get(key) || 0) + 1);\n }\n\n // Handle nested structures based on nestedHandling option\n const value = item[key];\n\n if (nestedHandling === 'shallow') {\n // Don't process nested structures\n continue;\n }\n\n if (Array.isArray(value) && value.length > 0 && isCompressibleArray(value)) {\n // Nested array of objects - always process\n const nestedKeys = collectKeys(\n value as Record<string, unknown>[],\n options,\n currentDepth + 1\n );\n nestedKeys.forEach(k => keys.add(k));\n } else if (\n nestedHandling !== 'arrays' &&\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n // Single nested object - skip if nestedHandling is 'arrays'\n const nestedKeys = collectKeys(\n [value as Record<string, unknown>],\n options,\n currentDepth + 1\n );\n nestedKeys.forEach(k => keys.add(k));\n }\n }\n }\n\n // If homogeneous mode, only keep keys that appear in ALL objects\n if (options.homogeneousOnly && data.length > 0) {\n for (const [key, count] of keyCounts) {\n if (count < data.length) {\n keys.delete(key);\n }\n }\n }\n\n return keys;\n}\n\n/**\n * Checks if an array is compressible (array of objects with consistent structure)\n */\nexport function isCompressibleArray(data: unknown): data is Record<string, unknown>[] {\n if (!Array.isArray(data) || data.length === 0) return false;\n\n // Check if all items are objects\n return data.every(\n item => typeof item === 'object' && item !== null && !Array.isArray(item)\n );\n}\n\n/**\n * Compresses an object using the key mapping\n */\nfunction compressObject(\n obj: Record<string, unknown>,\n keyToShort: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const compressed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const shortKey = keyToShort.get(key) ?? key;\n\n if (Array.isArray(value) && isCompressibleArray(value)) {\n // Recursively compress nested arrays\n compressed[shortKey] = value.map(item =>\n compressObject(\n item as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n )\n );\n } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n // Compress single nested objects too\n compressed[shortKey] = compressObject(\n value as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n } else {\n compressed[shortKey] = value;\n }\n }\n\n return compressed;\n}\n\n/**\n * Expands an object using the key mapping\n */\nfunction expandObject(\n obj: Record<string, unknown>,\n shortToKey: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const expanded: Record<string, unknown> = {};\n\n for (const [shortKey, value] of Object.entries(obj)) {\n const originalKey = shortToKey.get(shortKey) ?? shortKey;\n\n if (Array.isArray(value)) {\n expanded[originalKey] = value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return expandObject(\n item as Record<string, unknown>,\n shortToKey,\n maxDepth,\n currentDepth + 1\n );\n }\n return item;\n });\n } else if (typeof value === 'object' && value !== null) {\n expanded[originalKey] = expandObject(\n value as Record<string, unknown>,\n shortToKey,\n maxDepth,\n currentDepth + 1\n );\n } else {\n expanded[originalKey] = value;\n }\n }\n\n return expanded;\n}\n\n// Re-export CompressOptions from types for backwards compatibility\nexport type { CompressOptions } from './types';\n\n/**\n * Compresses an array of objects by replacing keys with short aliases\n */\nexport function compress<T extends Record<string, unknown>[]>(\n data: T,\n options: CompressOptions = {}\n): TersePayload<unknown[]> {\n const {\n minKeyLength = 3,\n maxDepth = 10,\n keyPattern = 'alpha',\n nestedHandling = 'deep',\n homogeneousOnly = false,\n excludeKeys,\n includeKeys,\n } = options;\n\n // Create key generator\n const { generator, name: patternName } = createKeyGenerator(keyPattern);\n\n // Resolve nested depth\n const effectiveDepth = resolveNestedDepth(nestedHandling, maxDepth);\n\n // Collect all unique keys\n const allKeys = collectKeys(data, {\n minKeyLength,\n maxDepth: effectiveDepth,\n nestedHandling,\n excludeKeys,\n includeKeys,\n homogeneousOnly,\n });\n\n // Sort keys by frequency of use (most used first) for optimal compression\n // For now, just sort alphabetically for deterministic output\n const sortedKeys = Array.from(allKeys).sort();\n\n // Create bidirectional mapping\n const keyToShort = new Map<string, string>();\n const keyMap: Record<string, string> = {};\n\n sortedKeys.forEach((key, index) => {\n const shortKey = generator(index);\n // Only use short key if it's actually shorter\n if (shortKey.length < key.length) {\n keyToShort.set(key, shortKey);\n keyMap[shortKey] = key;\n }\n });\n\n // Compress the data\n const compressed = data.map(item =>\n compressObject(item, keyToShort, effectiveDepth)\n );\n\n return {\n __terse__: true,\n v: 1,\n k: keyMap,\n d: compressed,\n p: patternName,\n };\n}\n\n/**\n * Expands a TersePayload back to its original form\n */\nexport function expand<T = unknown>(payload: TersePayload): T {\n const shortToKey = new Map(\n Object.entries(payload.k).map(([short, original]) => [short, original])\n );\n\n if (Array.isArray(payload.d)) {\n return payload.d.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return expandObject(item as Record<string, unknown>, shortToKey, 10);\n }\n return item;\n }) as T;\n }\n\n if (typeof payload.d === 'object' && payload.d !== null) {\n return expandObject(payload.d as Record<string, unknown>, shortToKey, 10) as T;\n }\n\n return payload.d as T;\n}\n\n/**\n * Creates a Proxy that transparently maps original keys to short keys\n * This is the magic that makes client-side access seamless\n */\nexport function createTerseProxy<T extends Record<string, unknown>>(\n compressed: Record<string, unknown>,\n keyMap: Record<string, string> // short -> original\n): T {\n // Create reverse map: original -> short\n const originalToShort = new Map(\n Object.entries(keyMap).map(([short, original]) => [original, short])\n );\n\n const handler: ProxyHandler<Record<string, unknown>> = {\n get(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop);\n }\n\n // Check if accessing by original key name\n const shortKey = originalToShort.get(prop);\n const actualKey = shortKey ?? prop;\n const value = target[actualKey];\n\n // Recursively proxy nested objects/arrays\n if (Array.isArray(value)) {\n return value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return createTerseProxy(item as Record<string, unknown>, keyMap);\n }\n return item;\n });\n }\n\n if (typeof value === 'object' && value !== null) {\n return createTerseProxy(value as Record<string, unknown>, keyMap);\n }\n\n return value;\n },\n\n has(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.has(target, prop);\n }\n const shortKey = originalToShort.get(prop);\n return (shortKey ?? prop) in target;\n },\n\n ownKeys(target) {\n // Return original key names\n return Object.keys(target).map(shortKey => keyMap[shortKey] ?? shortKey);\n },\n\n getOwnPropertyDescriptor(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.getOwnPropertyDescriptor(target, prop);\n }\n const shortKey = originalToShort.get(prop);\n const actualKey = shortKey ?? prop;\n const descriptor = Object.getOwnPropertyDescriptor(target, actualKey);\n if (descriptor) {\n return { ...descriptor, enumerable: true, configurable: true };\n }\n return undefined;\n },\n };\n\n return new Proxy(compressed, handler) as T;\n}\n\n/**\n * Wraps TersePayload data with Proxies for transparent access\n */\nexport function wrapWithProxy<T>(payload: TersePayload): T {\n if (Array.isArray(payload.d)) {\n return payload.d.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return createTerseProxy(item as Record<string, unknown>, payload.k);\n }\n return item;\n }) as T;\n }\n\n if (typeof payload.d === 'object' && payload.d !== null) {\n return createTerseProxy(payload.d as Record<string, unknown>, payload.k) as T;\n }\n\n return payload.d as T;\n}\n\n// Re-export for convenience\nexport { isTersePayload };\n","/**\n * TerseJSON GraphQL Middleware\n *\n * Integration for express-graphql that compresses arrays within GraphQL responses.\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport {\n GraphQLTerseOptions,\n GraphQLTerseMetadata,\n GraphQLTerseResponse,\n CompressOptions,\n} from './types';\nimport { isCompressibleArray, createKeyGenerator } from './core';\n\n/**\n * Default options for GraphQL compression\n */\nconst DEFAULT_OPTIONS: Required<Omit<GraphQLTerseOptions, 'shouldCompress' | 'excludePaths'>> & {\n shouldCompress?: GraphQLTerseOptions['shouldCompress'];\n excludePaths: string[];\n} = {\n minArrayLength: 2,\n debug: false,\n minKeyLength: 3,\n maxDepth: 10,\n keyPattern: 'alpha',\n nestedHandling: 'deep',\n homogeneousOnly: false,\n excludeKeys: [],\n includeKeys: [],\n excludePaths: [],\n};\n\n/**\n * Result from finding compressible arrays\n */\ninterface CompressibleArrayInfo {\n path: string;\n data: Record<string, unknown>[];\n}\n\n/**\n * Finds all compressible arrays within a data structure\n */\nexport function findCompressibleArrays(\n data: unknown,\n basePath: string = 'data',\n options: { minArrayLength: number; excludePaths: string[]; maxDepth: number },\n currentDepth: number = 0\n): CompressibleArrayInfo[] {\n const results: CompressibleArrayInfo[] = [];\n\n if (currentDepth >= options.maxDepth) return results;\n\n if (Array.isArray(data)) {\n // Check if this array is compressible\n if (\n isCompressibleArray(data) &&\n data.length >= options.minArrayLength &&\n !options.excludePaths.includes(basePath)\n ) {\n results.push({ path: basePath, data: data as Record<string, unknown>[] });\n }\n\n // Also check for nested arrays within array items\n data.forEach((item, index) => {\n if (typeof item === 'object' && item !== null) {\n const nestedResults = findCompressibleArrays(\n item,\n `${basePath}[${index}]`,\n options,\n currentDepth + 1\n );\n results.push(...nestedResults);\n }\n });\n } else if (typeof data === 'object' && data !== null) {\n // Walk object properties\n for (const [key, value] of Object.entries(data)) {\n const path = `${basePath}.${key}`;\n const nestedResults = findCompressibleArrays(value, path, options, currentDepth + 1);\n results.push(...nestedResults);\n }\n }\n\n return results;\n}\n\n/**\n * Collects all unique keys from multiple arrays\n */\nfunction collectKeysFromArrays(\n arrays: CompressibleArrayInfo[],\n options: CompressOptions\n): Set<string> {\n const allKeys = new Set<string>();\n const { minKeyLength = 3, excludeKeys = [], includeKeys = [] } = options;\n\n function collectFromObject(obj: Record<string, unknown>, depth: number = 0): void {\n if (depth >= (options.maxDepth ?? 10)) return;\n\n for (const key of Object.keys(obj)) {\n // Skip excluded keys\n if (excludeKeys.includes(key)) continue;\n\n // Include if in includeKeys, or if meets minKeyLength\n const shouldInclude = includeKeys.includes(key) || key.length >= minKeyLength;\n if (shouldInclude) {\n allKeys.add(key);\n }\n\n // Recurse into nested structures\n const value = obj[key];\n if (Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n collectFromObject(item as Record<string, unknown>, depth + 1);\n }\n }\n } else if (typeof value === 'object' && value !== null) {\n collectFromObject(value as Record<string, unknown>, depth + 1);\n }\n }\n }\n\n for (const { data } of arrays) {\n for (const item of data) {\n collectFromObject(item);\n }\n }\n\n return allKeys;\n}\n\n/**\n * Compresses an object using the key mapping\n */\nfunction compressObjectWithMap(\n obj: Record<string, unknown>,\n keyToShort: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const compressed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const shortKey = keyToShort.get(key) ?? key;\n\n if (Array.isArray(value)) {\n compressed[shortKey] = value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return compressObjectWithMap(\n item as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n }\n return item;\n });\n } else if (typeof value === 'object' && value !== null) {\n compressed[shortKey] = compressObjectWithMap(\n value as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n } else {\n compressed[shortKey] = value;\n }\n }\n\n return compressed;\n}\n\n/**\n * Sets a value at a path in an object (mutates the object)\n */\nfunction setAtPath(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split(/\\.|\\[(\\d+)\\]/).filter(Boolean);\n let current: unknown = obj;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const isIndex = /^\\d+$/.test(part);\n if (isIndex) {\n current = (current as unknown[])[parseInt(part, 10)];\n } else {\n current = (current as Record<string, unknown>)[part];\n }\n }\n\n const lastPart = parts[parts.length - 1];\n const isLastIndex = /^\\d+$/.test(lastPart);\n if (isLastIndex) {\n (current as unknown[])[parseInt(lastPart, 10)] = value;\n } else {\n (current as Record<string, unknown>)[lastPart] = value;\n }\n}\n\n/**\n * Compresses a GraphQL response in-place\n */\nexport function compressGraphQLResponse<T extends { data?: unknown }>(\n response: T,\n options: GraphQLTerseOptions = {}\n): GraphQLTerseResponse<T['data']> | T {\n const config = { ...DEFAULT_OPTIONS, ...options };\n\n // If no data field, return as-is\n if (!response.data) {\n return response;\n }\n\n // Find all compressible arrays\n const arrays = findCompressibleArrays(response.data, 'data', {\n minArrayLength: config.minArrayLength,\n excludePaths: config.excludePaths,\n maxDepth: config.maxDepth,\n });\n\n // Apply custom shouldCompress filter\n const filteredArrays = config.shouldCompress\n ? arrays.filter(({ path, data }) => config.shouldCompress!(data, path))\n : arrays;\n\n // If no arrays to compress, return as-is\n if (filteredArrays.length === 0) {\n return response;\n }\n\n // Collect all unique keys from all arrays\n const allKeys = collectKeysFromArrays(filteredArrays, config);\n\n // Sort keys for deterministic output\n const sortedKeys = Array.from(allKeys).sort();\n\n // Create key generator\n const { generator } = createKeyGenerator(config.keyPattern);\n\n // Build key mapping\n const keyToShort = new Map<string, string>();\n const keyMap: Record<string, string> = {};\n\n sortedKeys.forEach((key, index) => {\n const shortKey = generator(index);\n // Only use short key if it's actually shorter\n if (shortKey.length < key.length) {\n keyToShort.set(key, shortKey);\n keyMap[shortKey] = key;\n }\n });\n\n // If no keys were actually shortened, return as-is\n if (Object.keys(keyMap).length === 0) {\n return response;\n }\n\n // Clone the data to avoid mutating the original\n const clonedData = JSON.parse(JSON.stringify(response.data));\n\n // Sort paths from deepest to shallowest to avoid breaking nested access\n // when parent arrays have their keys renamed\n const sortedArrays = [...filteredArrays].sort((a, b) => {\n const depthA = (a.path.match(/\\./g) || []).length + (a.path.match(/\\[/g) || []).length;\n const depthB = (b.path.match(/\\./g) || []).length + (b.path.match(/\\[/g) || []).length;\n return depthB - depthA; // Deepest first\n });\n\n // Compress each array and update in the cloned data\n const paths: string[] = [];\n for (const { path, data } of sortedArrays) {\n const compressedArray = data.map(item =>\n compressObjectWithMap(item, keyToShort, config.maxDepth)\n );\n setAtPath({ data: clonedData } as Record<string, unknown>, path, compressedArray);\n paths.push(path);\n }\n\n // Build the terse metadata\n const terseMeta: GraphQLTerseMetadata = {\n v: 1,\n k: keyMap,\n paths,\n };\n\n // Build the response\n const terseResponse: GraphQLTerseResponse<T['data']> = {\n data: clonedData as T['data'],\n __terse__: terseMeta,\n };\n\n // Preserve errors and extensions if present\n if ('errors' in response && response.errors) {\n terseResponse.errors = response.errors as GraphQLTerseResponse['errors'];\n }\n if ('extensions' in response && response.extensions) {\n terseResponse.extensions = response.extensions as GraphQLTerseResponse['extensions'];\n }\n\n if (config.debug) {\n const originalSize = JSON.stringify(response).length;\n const compressedSize = JSON.stringify(terseResponse).length;\n const savings = ((1 - compressedSize / originalSize) * 100).toFixed(1);\n console.log(\n `[tersejson/graphql] Compressed ${originalSize} -> ${compressedSize} bytes (${savings}% savings)`\n );\n console.log(`[tersejson/graphql] Compressed paths: ${paths.join(', ')}`);\n }\n\n return terseResponse;\n}\n\n/**\n * Creates a format function for express-graphql\n *\n * @example\n * ```typescript\n * import { graphqlHTTP } from 'express-graphql';\n * import { createTerseFormatFn } from 'tersejson/graphql';\n *\n * app.use('/graphql', graphqlHTTP({\n * schema: mySchema,\n * formatResult: createTerseFormatFn({ debug: true }),\n * }));\n * ```\n */\nexport function createTerseFormatFn(options: GraphQLTerseOptions = {}) {\n return function formatResult(\n result: { data?: unknown; errors?: unknown[]; extensions?: Record<string, unknown> },\n _context?: unknown,\n _info?: unknown\n ) {\n return compressGraphQLResponse(result, options);\n };\n}\n\n/**\n * Express middleware wrapper for express-graphql\n *\n * @example\n * ```typescript\n * import { graphqlHTTP } from 'express-graphql';\n * import { terseGraphQL } from 'tersejson/graphql';\n *\n * app.use('/graphql', terseGraphQL(\n * graphqlHTTP({\n * schema: mySchema,\n * graphiql: true,\n * }),\n * { debug: true }\n * ));\n * ```\n */\nexport function terseGraphQL(\n graphqlMiddleware: RequestHandler,\n options: GraphQLTerseOptions = {}\n): RequestHandler {\n const config = { ...DEFAULT_OPTIONS, ...options };\n\n return function terseGraphQLMiddleware(\n req: Request,\n res: Response,\n next: NextFunction\n ): void {\n // Check if client supports terse responses\n const acceptsTerse =\n req.headers['accept-terse'] === 'true' || req.headers['x-accept-terse'] === 'true';\n\n if (!acceptsTerse) {\n // Client doesn't support terse, pass through to original middleware\n graphqlMiddleware(req, res, next);\n return;\n }\n\n // Store original json method\n const originalJson = res.json.bind(res);\n\n // Override res.json to intercept the response\n res.json = function terseGraphQLJson(data: unknown): Response {\n // Check if this looks like a GraphQL response\n if (typeof data === 'object' && data !== null && 'data' in data) {\n try {\n const compressed = compressGraphQLResponse(\n data as { data?: unknown; errors?: unknown[]; extensions?: Record<string, unknown> },\n config\n );\n\n // If compression happened, set the header\n if ('__terse__' in compressed) {\n res.setHeader('x-terse-json', 'graphql');\n }\n\n return originalJson(compressed);\n } catch (error) {\n if (config.debug) {\n console.error('[tersejson/graphql] Compression failed:', error);\n }\n return originalJson(data);\n }\n }\n\n return originalJson(data);\n };\n\n // Call the original GraphQL middleware\n graphqlMiddleware(req, res, next);\n };\n}\n\n// Default export\nexport default terseGraphQL;\n"]}
@@ -0,0 +1,296 @@
1
+ // src/core.ts
2
+ function alphaGenerator(index) {
3
+ let key = "";
4
+ let remaining = index;
5
+ do {
6
+ key = String.fromCharCode(97 + remaining % 26) + key;
7
+ remaining = Math.floor(remaining / 26) - 1;
8
+ } while (remaining >= 0);
9
+ return key;
10
+ }
11
+ function numericGenerator(index) {
12
+ return String(index);
13
+ }
14
+ function alphanumericGenerator(index) {
15
+ const letterIndex = Math.floor(index / 9);
16
+ const numIndex = index % 9 + 1;
17
+ return alphaGenerator(letterIndex) + numIndex;
18
+ }
19
+ function shortGenerator(index) {
20
+ if (index === 0) return "_";
21
+ return alphaGenerator(index - 1);
22
+ }
23
+ function prefixedGenerator(prefix, style = "numeric") {
24
+ return (index) => {
25
+ if (style === "alpha") {
26
+ return prefix + alphaGenerator(index);
27
+ }
28
+ return prefix + index;
29
+ };
30
+ }
31
+ function createKeyGenerator(pattern) {
32
+ if (typeof pattern === "function") {
33
+ return { generator: pattern, name: "custom" };
34
+ }
35
+ if (typeof pattern === "string") {
36
+ switch (pattern) {
37
+ case "alpha":
38
+ return { generator: alphaGenerator, name: "alpha" };
39
+ case "numeric":
40
+ return { generator: numericGenerator, name: "numeric" };
41
+ case "alphanumeric":
42
+ return { generator: alphanumericGenerator, name: "alphanumeric" };
43
+ case "short":
44
+ return { generator: shortGenerator, name: "short" };
45
+ case "prefixed":
46
+ return { generator: prefixedGenerator("k"), name: "prefixed:k" };
47
+ default:
48
+ return { generator: alphaGenerator, name: "alpha" };
49
+ }
50
+ }
51
+ if (typeof pattern === "object" && "prefix" in pattern) {
52
+ return {
53
+ generator: prefixedGenerator(pattern.prefix, pattern.style || "numeric"),
54
+ name: `prefixed:${pattern.prefix}`
55
+ };
56
+ }
57
+ return { generator: alphaGenerator, name: "alpha" };
58
+ }
59
+ function isCompressibleArray(data) {
60
+ if (!Array.isArray(data) || data.length === 0) return false;
61
+ return data.every(
62
+ (item) => typeof item === "object" && item !== null && !Array.isArray(item)
63
+ );
64
+ }
65
+
66
+ // src/graphql.ts
67
+ var DEFAULT_OPTIONS = {
68
+ minArrayLength: 2,
69
+ debug: false,
70
+ minKeyLength: 3,
71
+ maxDepth: 10,
72
+ keyPattern: "alpha",
73
+ nestedHandling: "deep",
74
+ homogeneousOnly: false,
75
+ excludeKeys: [],
76
+ includeKeys: [],
77
+ excludePaths: []
78
+ };
79
+ function findCompressibleArrays(data, basePath = "data", options, currentDepth = 0) {
80
+ const results = [];
81
+ if (currentDepth >= options.maxDepth) return results;
82
+ if (Array.isArray(data)) {
83
+ if (isCompressibleArray(data) && data.length >= options.minArrayLength && !options.excludePaths.includes(basePath)) {
84
+ results.push({ path: basePath, data });
85
+ }
86
+ data.forEach((item, index) => {
87
+ if (typeof item === "object" && item !== null) {
88
+ const nestedResults = findCompressibleArrays(
89
+ item,
90
+ `${basePath}[${index}]`,
91
+ options,
92
+ currentDepth + 1
93
+ );
94
+ results.push(...nestedResults);
95
+ }
96
+ });
97
+ } else if (typeof data === "object" && data !== null) {
98
+ for (const [key, value] of Object.entries(data)) {
99
+ const path = `${basePath}.${key}`;
100
+ const nestedResults = findCompressibleArrays(value, path, options, currentDepth + 1);
101
+ results.push(...nestedResults);
102
+ }
103
+ }
104
+ return results;
105
+ }
106
+ function collectKeysFromArrays(arrays, options) {
107
+ const allKeys = /* @__PURE__ */ new Set();
108
+ const { minKeyLength = 3, excludeKeys = [], includeKeys = [] } = options;
109
+ function collectFromObject(obj, depth = 0) {
110
+ if (depth >= (options.maxDepth ?? 10)) return;
111
+ for (const key of Object.keys(obj)) {
112
+ if (excludeKeys.includes(key)) continue;
113
+ const shouldInclude = includeKeys.includes(key) || key.length >= minKeyLength;
114
+ if (shouldInclude) {
115
+ allKeys.add(key);
116
+ }
117
+ const value = obj[key];
118
+ if (Array.isArray(value)) {
119
+ for (const item of value) {
120
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
121
+ collectFromObject(item, depth + 1);
122
+ }
123
+ }
124
+ } else if (typeof value === "object" && value !== null) {
125
+ collectFromObject(value, depth + 1);
126
+ }
127
+ }
128
+ }
129
+ for (const { data } of arrays) {
130
+ for (const item of data) {
131
+ collectFromObject(item);
132
+ }
133
+ }
134
+ return allKeys;
135
+ }
136
+ function compressObjectWithMap(obj, keyToShort, maxDepth, currentDepth = 0) {
137
+ if (currentDepth >= maxDepth) return obj;
138
+ const compressed = {};
139
+ for (const [key, value] of Object.entries(obj)) {
140
+ const shortKey = keyToShort.get(key) ?? key;
141
+ if (Array.isArray(value)) {
142
+ compressed[shortKey] = value.map((item) => {
143
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
144
+ return compressObjectWithMap(
145
+ item,
146
+ keyToShort,
147
+ maxDepth,
148
+ currentDepth + 1
149
+ );
150
+ }
151
+ return item;
152
+ });
153
+ } else if (typeof value === "object" && value !== null) {
154
+ compressed[shortKey] = compressObjectWithMap(
155
+ value,
156
+ keyToShort,
157
+ maxDepth,
158
+ currentDepth + 1
159
+ );
160
+ } else {
161
+ compressed[shortKey] = value;
162
+ }
163
+ }
164
+ return compressed;
165
+ }
166
+ function setAtPath(obj, path, value) {
167
+ const parts = path.split(/\.|\[(\d+)\]/).filter(Boolean);
168
+ let current = obj;
169
+ for (let i = 0; i < parts.length - 1; i++) {
170
+ const part = parts[i];
171
+ const isIndex = /^\d+$/.test(part);
172
+ if (isIndex) {
173
+ current = current[parseInt(part, 10)];
174
+ } else {
175
+ current = current[part];
176
+ }
177
+ }
178
+ const lastPart = parts[parts.length - 1];
179
+ const isLastIndex = /^\d+$/.test(lastPart);
180
+ if (isLastIndex) {
181
+ current[parseInt(lastPart, 10)] = value;
182
+ } else {
183
+ current[lastPart] = value;
184
+ }
185
+ }
186
+ function compressGraphQLResponse(response, options = {}) {
187
+ const config = { ...DEFAULT_OPTIONS, ...options };
188
+ if (!response.data) {
189
+ return response;
190
+ }
191
+ const arrays = findCompressibleArrays(response.data, "data", {
192
+ minArrayLength: config.minArrayLength,
193
+ excludePaths: config.excludePaths,
194
+ maxDepth: config.maxDepth
195
+ });
196
+ const filteredArrays = config.shouldCompress ? arrays.filter(({ path, data }) => config.shouldCompress(data, path)) : arrays;
197
+ if (filteredArrays.length === 0) {
198
+ return response;
199
+ }
200
+ const allKeys = collectKeysFromArrays(filteredArrays, config);
201
+ const sortedKeys = Array.from(allKeys).sort();
202
+ const { generator } = createKeyGenerator(config.keyPattern);
203
+ const keyToShort = /* @__PURE__ */ new Map();
204
+ const keyMap = {};
205
+ sortedKeys.forEach((key, index) => {
206
+ const shortKey = generator(index);
207
+ if (shortKey.length < key.length) {
208
+ keyToShort.set(key, shortKey);
209
+ keyMap[shortKey] = key;
210
+ }
211
+ });
212
+ if (Object.keys(keyMap).length === 0) {
213
+ return response;
214
+ }
215
+ const clonedData = JSON.parse(JSON.stringify(response.data));
216
+ const sortedArrays = [...filteredArrays].sort((a, b) => {
217
+ const depthA = (a.path.match(/\./g) || []).length + (a.path.match(/\[/g) || []).length;
218
+ const depthB = (b.path.match(/\./g) || []).length + (b.path.match(/\[/g) || []).length;
219
+ return depthB - depthA;
220
+ });
221
+ const paths = [];
222
+ for (const { path, data } of sortedArrays) {
223
+ const compressedArray = data.map(
224
+ (item) => compressObjectWithMap(item, keyToShort, config.maxDepth)
225
+ );
226
+ setAtPath({ data: clonedData }, path, compressedArray);
227
+ paths.push(path);
228
+ }
229
+ const terseMeta = {
230
+ v: 1,
231
+ k: keyMap,
232
+ paths
233
+ };
234
+ const terseResponse = {
235
+ data: clonedData,
236
+ __terse__: terseMeta
237
+ };
238
+ if ("errors" in response && response.errors) {
239
+ terseResponse.errors = response.errors;
240
+ }
241
+ if ("extensions" in response && response.extensions) {
242
+ terseResponse.extensions = response.extensions;
243
+ }
244
+ if (config.debug) {
245
+ const originalSize = JSON.stringify(response).length;
246
+ const compressedSize = JSON.stringify(terseResponse).length;
247
+ const savings = ((1 - compressedSize / originalSize) * 100).toFixed(1);
248
+ console.log(
249
+ `[tersejson/graphql] Compressed ${originalSize} -> ${compressedSize} bytes (${savings}% savings)`
250
+ );
251
+ console.log(`[tersejson/graphql] Compressed paths: ${paths.join(", ")}`);
252
+ }
253
+ return terseResponse;
254
+ }
255
+ function createTerseFormatFn(options = {}) {
256
+ return function formatResult(result, _context, _info) {
257
+ return compressGraphQLResponse(result, options);
258
+ };
259
+ }
260
+ function terseGraphQL(graphqlMiddleware, options = {}) {
261
+ const config = { ...DEFAULT_OPTIONS, ...options };
262
+ return function terseGraphQLMiddleware(req, res, next) {
263
+ const acceptsTerse = req.headers["accept-terse"] === "true" || req.headers["x-accept-terse"] === "true";
264
+ if (!acceptsTerse) {
265
+ graphqlMiddleware(req, res, next);
266
+ return;
267
+ }
268
+ const originalJson = res.json.bind(res);
269
+ res.json = function terseGraphQLJson(data) {
270
+ if (typeof data === "object" && data !== null && "data" in data) {
271
+ try {
272
+ const compressed = compressGraphQLResponse(
273
+ data,
274
+ config
275
+ );
276
+ if ("__terse__" in compressed) {
277
+ res.setHeader("x-terse-json", "graphql");
278
+ }
279
+ return originalJson(compressed);
280
+ } catch (error) {
281
+ if (config.debug) {
282
+ console.error("[tersejson/graphql] Compression failed:", error);
283
+ }
284
+ return originalJson(data);
285
+ }
286
+ }
287
+ return originalJson(data);
288
+ };
289
+ graphqlMiddleware(req, res, next);
290
+ };
291
+ }
292
+ var graphql_default = terseGraphQL;
293
+
294
+ export { compressGraphQLResponse, createTerseFormatFn, graphql_default as default, findCompressibleArrays, terseGraphQL };
295
+ //# sourceMappingURL=graphql.mjs.map
296
+ //# sourceMappingURL=graphql.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts","../src/graphql.ts"],"names":[],"mappings":"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","file":"graphql.mjs","sourcesContent":["/**\n * TerseJSON Core\n *\n * The core compression and expansion algorithms.\n */\n\nimport {\n TersePayload,\n isTersePayload,\n KeyPattern,\n KeyGenerator,\n NestedHandling,\n CompressOptions,\n} from './types';\n\n// ============================================================================\n// KEY PATTERN GENERATORS\n// ============================================================================\n\n/**\n * Alpha pattern: a, b, c, ... z, aa, ab, ...\n */\nfunction alphaGenerator(index: number): string {\n let key = '';\n let remaining = index;\n\n do {\n key = String.fromCharCode(97 + (remaining % 26)) + key;\n remaining = Math.floor(remaining / 26) - 1;\n } while (remaining >= 0);\n\n return key;\n}\n\n/**\n * Numeric pattern: 0, 1, 2, ... 9, 10, 11, ...\n */\nfunction numericGenerator(index: number): string {\n return String(index);\n}\n\n/**\n * Alphanumeric pattern: a1, a2, ... a9, b1, b2, ...\n */\nfunction alphanumericGenerator(index: number): string {\n const letterIndex = Math.floor(index / 9);\n const numIndex = (index % 9) + 1;\n return alphaGenerator(letterIndex) + numIndex;\n}\n\n/**\n * Short pattern: uses shortest possible keys\n * _, a, b, ..., z, aa, ab, ...\n */\nfunction shortGenerator(index: number): string {\n if (index === 0) return '_';\n return alphaGenerator(index - 1);\n}\n\n/**\n * Prefixed pattern: k0, k1, k2, ...\n */\nfunction prefixedGenerator(prefix: string, style: 'numeric' | 'alpha' = 'numeric'): KeyGenerator {\n return (index: number) => {\n if (style === 'alpha') {\n return prefix + alphaGenerator(index);\n }\n return prefix + index;\n };\n}\n\n/**\n * Creates a key generator from a pattern configuration\n */\nexport function createKeyGenerator(pattern: KeyPattern): { generator: KeyGenerator; name: string } {\n // If it's already a function, use it directly\n if (typeof pattern === 'function') {\n return { generator: pattern, name: 'custom' };\n }\n\n // If it's a preset string\n if (typeof pattern === 'string') {\n switch (pattern) {\n case 'alpha':\n return { generator: alphaGenerator, name: 'alpha' };\n case 'numeric':\n return { generator: numericGenerator, name: 'numeric' };\n case 'alphanumeric':\n return { generator: alphanumericGenerator, name: 'alphanumeric' };\n case 'short':\n return { generator: shortGenerator, name: 'short' };\n case 'prefixed':\n return { generator: prefixedGenerator('k'), name: 'prefixed:k' };\n default:\n return { generator: alphaGenerator, name: 'alpha' };\n }\n }\n\n // If it's a prefix config object\n if (typeof pattern === 'object' && 'prefix' in pattern) {\n return {\n generator: prefixedGenerator(pattern.prefix, pattern.style || 'numeric'),\n name: `prefixed:${pattern.prefix}`,\n };\n }\n\n return { generator: alphaGenerator, name: 'alpha' };\n}\n\n/**\n * Resolves nested handling to a numeric depth\n */\nfunction resolveNestedDepth(handling: NestedHandling | undefined, maxDepth: number): number {\n if (handling === undefined || handling === 'deep') {\n return maxDepth;\n }\n if (handling === 'shallow') {\n return 1;\n }\n if (handling === 'arrays') {\n return maxDepth; // Special handling in collect/compress functions\n }\n if (typeof handling === 'number') {\n return handling;\n }\n return maxDepth;\n}\n\n// Legacy generateShortKey removed - use createKeyGenerator instead\n\ninterface CollectKeysOptions {\n minKeyLength: number;\n maxDepth: number;\n nestedHandling: NestedHandling;\n excludeKeys?: string[];\n includeKeys?: string[];\n homogeneousOnly?: boolean;\n}\n\n/**\n * Collects all unique keys from an array of objects\n */\nfunction collectKeys(\n data: Record<string, unknown>[],\n options: CollectKeysOptions,\n currentDepth: number = 0\n): Set<string> {\n const keys = new Set<string>();\n const { minKeyLength, maxDepth, nestedHandling, excludeKeys, includeKeys } = options;\n\n if (currentDepth >= maxDepth) return keys;\n\n // For homogeneous mode, track key counts\n const keyCounts = new Map<string, number>();\n\n for (const item of data) {\n if (typeof item !== 'object' || item === null) continue;\n\n for (const key of Object.keys(item)) {\n // Skip excluded keys\n if (excludeKeys?.includes(key)) continue;\n\n // Include if in includeKeys, or if meets minKeyLength\n const shouldInclude = includeKeys?.includes(key) || key.length >= minKeyLength;\n\n if (shouldInclude) {\n keys.add(key);\n keyCounts.set(key, (keyCounts.get(key) || 0) + 1);\n }\n\n // Handle nested structures based on nestedHandling option\n const value = item[key];\n\n if (nestedHandling === 'shallow') {\n // Don't process nested structures\n continue;\n }\n\n if (Array.isArray(value) && value.length > 0 && isCompressibleArray(value)) {\n // Nested array of objects - always process\n const nestedKeys = collectKeys(\n value as Record<string, unknown>[],\n options,\n currentDepth + 1\n );\n nestedKeys.forEach(k => keys.add(k));\n } else if (\n nestedHandling !== 'arrays' &&\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n // Single nested object - skip if nestedHandling is 'arrays'\n const nestedKeys = collectKeys(\n [value as Record<string, unknown>],\n options,\n currentDepth + 1\n );\n nestedKeys.forEach(k => keys.add(k));\n }\n }\n }\n\n // If homogeneous mode, only keep keys that appear in ALL objects\n if (options.homogeneousOnly && data.length > 0) {\n for (const [key, count] of keyCounts) {\n if (count < data.length) {\n keys.delete(key);\n }\n }\n }\n\n return keys;\n}\n\n/**\n * Checks if an array is compressible (array of objects with consistent structure)\n */\nexport function isCompressibleArray(data: unknown): data is Record<string, unknown>[] {\n if (!Array.isArray(data) || data.length === 0) return false;\n\n // Check if all items are objects\n return data.every(\n item => typeof item === 'object' && item !== null && !Array.isArray(item)\n );\n}\n\n/**\n * Compresses an object using the key mapping\n */\nfunction compressObject(\n obj: Record<string, unknown>,\n keyToShort: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const compressed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const shortKey = keyToShort.get(key) ?? key;\n\n if (Array.isArray(value) && isCompressibleArray(value)) {\n // Recursively compress nested arrays\n compressed[shortKey] = value.map(item =>\n compressObject(\n item as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n )\n );\n } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n // Compress single nested objects too\n compressed[shortKey] = compressObject(\n value as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n } else {\n compressed[shortKey] = value;\n }\n }\n\n return compressed;\n}\n\n/**\n * Expands an object using the key mapping\n */\nfunction expandObject(\n obj: Record<string, unknown>,\n shortToKey: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const expanded: Record<string, unknown> = {};\n\n for (const [shortKey, value] of Object.entries(obj)) {\n const originalKey = shortToKey.get(shortKey) ?? shortKey;\n\n if (Array.isArray(value)) {\n expanded[originalKey] = value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return expandObject(\n item as Record<string, unknown>,\n shortToKey,\n maxDepth,\n currentDepth + 1\n );\n }\n return item;\n });\n } else if (typeof value === 'object' && value !== null) {\n expanded[originalKey] = expandObject(\n value as Record<string, unknown>,\n shortToKey,\n maxDepth,\n currentDepth + 1\n );\n } else {\n expanded[originalKey] = value;\n }\n }\n\n return expanded;\n}\n\n// Re-export CompressOptions from types for backwards compatibility\nexport type { CompressOptions } from './types';\n\n/**\n * Compresses an array of objects by replacing keys with short aliases\n */\nexport function compress<T extends Record<string, unknown>[]>(\n data: T,\n options: CompressOptions = {}\n): TersePayload<unknown[]> {\n const {\n minKeyLength = 3,\n maxDepth = 10,\n keyPattern = 'alpha',\n nestedHandling = 'deep',\n homogeneousOnly = false,\n excludeKeys,\n includeKeys,\n } = options;\n\n // Create key generator\n const { generator, name: patternName } = createKeyGenerator(keyPattern);\n\n // Resolve nested depth\n const effectiveDepth = resolveNestedDepth(nestedHandling, maxDepth);\n\n // Collect all unique keys\n const allKeys = collectKeys(data, {\n minKeyLength,\n maxDepth: effectiveDepth,\n nestedHandling,\n excludeKeys,\n includeKeys,\n homogeneousOnly,\n });\n\n // Sort keys by frequency of use (most used first) for optimal compression\n // For now, just sort alphabetically for deterministic output\n const sortedKeys = Array.from(allKeys).sort();\n\n // Create bidirectional mapping\n const keyToShort = new Map<string, string>();\n const keyMap: Record<string, string> = {};\n\n sortedKeys.forEach((key, index) => {\n const shortKey = generator(index);\n // Only use short key if it's actually shorter\n if (shortKey.length < key.length) {\n keyToShort.set(key, shortKey);\n keyMap[shortKey] = key;\n }\n });\n\n // Compress the data\n const compressed = data.map(item =>\n compressObject(item, keyToShort, effectiveDepth)\n );\n\n return {\n __terse__: true,\n v: 1,\n k: keyMap,\n d: compressed,\n p: patternName,\n };\n}\n\n/**\n * Expands a TersePayload back to its original form\n */\nexport function expand<T = unknown>(payload: TersePayload): T {\n const shortToKey = new Map(\n Object.entries(payload.k).map(([short, original]) => [short, original])\n );\n\n if (Array.isArray(payload.d)) {\n return payload.d.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return expandObject(item as Record<string, unknown>, shortToKey, 10);\n }\n return item;\n }) as T;\n }\n\n if (typeof payload.d === 'object' && payload.d !== null) {\n return expandObject(payload.d as Record<string, unknown>, shortToKey, 10) as T;\n }\n\n return payload.d as T;\n}\n\n/**\n * Creates a Proxy that transparently maps original keys to short keys\n * This is the magic that makes client-side access seamless\n */\nexport function createTerseProxy<T extends Record<string, unknown>>(\n compressed: Record<string, unknown>,\n keyMap: Record<string, string> // short -> original\n): T {\n // Create reverse map: original -> short\n const originalToShort = new Map(\n Object.entries(keyMap).map(([short, original]) => [original, short])\n );\n\n const handler: ProxyHandler<Record<string, unknown>> = {\n get(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop);\n }\n\n // Check if accessing by original key name\n const shortKey = originalToShort.get(prop);\n const actualKey = shortKey ?? prop;\n const value = target[actualKey];\n\n // Recursively proxy nested objects/arrays\n if (Array.isArray(value)) {\n return value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return createTerseProxy(item as Record<string, unknown>, keyMap);\n }\n return item;\n });\n }\n\n if (typeof value === 'object' && value !== null) {\n return createTerseProxy(value as Record<string, unknown>, keyMap);\n }\n\n return value;\n },\n\n has(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.has(target, prop);\n }\n const shortKey = originalToShort.get(prop);\n return (shortKey ?? prop) in target;\n },\n\n ownKeys(target) {\n // Return original key names\n return Object.keys(target).map(shortKey => keyMap[shortKey] ?? shortKey);\n },\n\n getOwnPropertyDescriptor(target, prop: string | symbol) {\n if (typeof prop === 'symbol') {\n return Reflect.getOwnPropertyDescriptor(target, prop);\n }\n const shortKey = originalToShort.get(prop);\n const actualKey = shortKey ?? prop;\n const descriptor = Object.getOwnPropertyDescriptor(target, actualKey);\n if (descriptor) {\n return { ...descriptor, enumerable: true, configurable: true };\n }\n return undefined;\n },\n };\n\n return new Proxy(compressed, handler) as T;\n}\n\n/**\n * Wraps TersePayload data with Proxies for transparent access\n */\nexport function wrapWithProxy<T>(payload: TersePayload): T {\n if (Array.isArray(payload.d)) {\n return payload.d.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return createTerseProxy(item as Record<string, unknown>, payload.k);\n }\n return item;\n }) as T;\n }\n\n if (typeof payload.d === 'object' && payload.d !== null) {\n return createTerseProxy(payload.d as Record<string, unknown>, payload.k) as T;\n }\n\n return payload.d as T;\n}\n\n// Re-export for convenience\nexport { isTersePayload };\n","/**\n * TerseJSON GraphQL Middleware\n *\n * Integration for express-graphql that compresses arrays within GraphQL responses.\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport {\n GraphQLTerseOptions,\n GraphQLTerseMetadata,\n GraphQLTerseResponse,\n CompressOptions,\n} from './types';\nimport { isCompressibleArray, createKeyGenerator } from './core';\n\n/**\n * Default options for GraphQL compression\n */\nconst DEFAULT_OPTIONS: Required<Omit<GraphQLTerseOptions, 'shouldCompress' | 'excludePaths'>> & {\n shouldCompress?: GraphQLTerseOptions['shouldCompress'];\n excludePaths: string[];\n} = {\n minArrayLength: 2,\n debug: false,\n minKeyLength: 3,\n maxDepth: 10,\n keyPattern: 'alpha',\n nestedHandling: 'deep',\n homogeneousOnly: false,\n excludeKeys: [],\n includeKeys: [],\n excludePaths: [],\n};\n\n/**\n * Result from finding compressible arrays\n */\ninterface CompressibleArrayInfo {\n path: string;\n data: Record<string, unknown>[];\n}\n\n/**\n * Finds all compressible arrays within a data structure\n */\nexport function findCompressibleArrays(\n data: unknown,\n basePath: string = 'data',\n options: { minArrayLength: number; excludePaths: string[]; maxDepth: number },\n currentDepth: number = 0\n): CompressibleArrayInfo[] {\n const results: CompressibleArrayInfo[] = [];\n\n if (currentDepth >= options.maxDepth) return results;\n\n if (Array.isArray(data)) {\n // Check if this array is compressible\n if (\n isCompressibleArray(data) &&\n data.length >= options.minArrayLength &&\n !options.excludePaths.includes(basePath)\n ) {\n results.push({ path: basePath, data: data as Record<string, unknown>[] });\n }\n\n // Also check for nested arrays within array items\n data.forEach((item, index) => {\n if (typeof item === 'object' && item !== null) {\n const nestedResults = findCompressibleArrays(\n item,\n `${basePath}[${index}]`,\n options,\n currentDepth + 1\n );\n results.push(...nestedResults);\n }\n });\n } else if (typeof data === 'object' && data !== null) {\n // Walk object properties\n for (const [key, value] of Object.entries(data)) {\n const path = `${basePath}.${key}`;\n const nestedResults = findCompressibleArrays(value, path, options, currentDepth + 1);\n results.push(...nestedResults);\n }\n }\n\n return results;\n}\n\n/**\n * Collects all unique keys from multiple arrays\n */\nfunction collectKeysFromArrays(\n arrays: CompressibleArrayInfo[],\n options: CompressOptions\n): Set<string> {\n const allKeys = new Set<string>();\n const { minKeyLength = 3, excludeKeys = [], includeKeys = [] } = options;\n\n function collectFromObject(obj: Record<string, unknown>, depth: number = 0): void {\n if (depth >= (options.maxDepth ?? 10)) return;\n\n for (const key of Object.keys(obj)) {\n // Skip excluded keys\n if (excludeKeys.includes(key)) continue;\n\n // Include if in includeKeys, or if meets minKeyLength\n const shouldInclude = includeKeys.includes(key) || key.length >= minKeyLength;\n if (shouldInclude) {\n allKeys.add(key);\n }\n\n // Recurse into nested structures\n const value = obj[key];\n if (Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n collectFromObject(item as Record<string, unknown>, depth + 1);\n }\n }\n } else if (typeof value === 'object' && value !== null) {\n collectFromObject(value as Record<string, unknown>, depth + 1);\n }\n }\n }\n\n for (const { data } of arrays) {\n for (const item of data) {\n collectFromObject(item);\n }\n }\n\n return allKeys;\n}\n\n/**\n * Compresses an object using the key mapping\n */\nfunction compressObjectWithMap(\n obj: Record<string, unknown>,\n keyToShort: Map<string, string>,\n maxDepth: number,\n currentDepth: number = 0\n): Record<string, unknown> {\n if (currentDepth >= maxDepth) return obj;\n\n const compressed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const shortKey = keyToShort.get(key) ?? key;\n\n if (Array.isArray(value)) {\n compressed[shortKey] = value.map(item => {\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n return compressObjectWithMap(\n item as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n }\n return item;\n });\n } else if (typeof value === 'object' && value !== null) {\n compressed[shortKey] = compressObjectWithMap(\n value as Record<string, unknown>,\n keyToShort,\n maxDepth,\n currentDepth + 1\n );\n } else {\n compressed[shortKey] = value;\n }\n }\n\n return compressed;\n}\n\n/**\n * Sets a value at a path in an object (mutates the object)\n */\nfunction setAtPath(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split(/\\.|\\[(\\d+)\\]/).filter(Boolean);\n let current: unknown = obj;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const isIndex = /^\\d+$/.test(part);\n if (isIndex) {\n current = (current as unknown[])[parseInt(part, 10)];\n } else {\n current = (current as Record<string, unknown>)[part];\n }\n }\n\n const lastPart = parts[parts.length - 1];\n const isLastIndex = /^\\d+$/.test(lastPart);\n if (isLastIndex) {\n (current as unknown[])[parseInt(lastPart, 10)] = value;\n } else {\n (current as Record<string, unknown>)[lastPart] = value;\n }\n}\n\n/**\n * Compresses a GraphQL response in-place\n */\nexport function compressGraphQLResponse<T extends { data?: unknown }>(\n response: T,\n options: GraphQLTerseOptions = {}\n): GraphQLTerseResponse<T['data']> | T {\n const config = { ...DEFAULT_OPTIONS, ...options };\n\n // If no data field, return as-is\n if (!response.data) {\n return response;\n }\n\n // Find all compressible arrays\n const arrays = findCompressibleArrays(response.data, 'data', {\n minArrayLength: config.minArrayLength,\n excludePaths: config.excludePaths,\n maxDepth: config.maxDepth,\n });\n\n // Apply custom shouldCompress filter\n const filteredArrays = config.shouldCompress\n ? arrays.filter(({ path, data }) => config.shouldCompress!(data, path))\n : arrays;\n\n // If no arrays to compress, return as-is\n if (filteredArrays.length === 0) {\n return response;\n }\n\n // Collect all unique keys from all arrays\n const allKeys = collectKeysFromArrays(filteredArrays, config);\n\n // Sort keys for deterministic output\n const sortedKeys = Array.from(allKeys).sort();\n\n // Create key generator\n const { generator } = createKeyGenerator(config.keyPattern);\n\n // Build key mapping\n const keyToShort = new Map<string, string>();\n const keyMap: Record<string, string> = {};\n\n sortedKeys.forEach((key, index) => {\n const shortKey = generator(index);\n // Only use short key if it's actually shorter\n if (shortKey.length < key.length) {\n keyToShort.set(key, shortKey);\n keyMap[shortKey] = key;\n }\n });\n\n // If no keys were actually shortened, return as-is\n if (Object.keys(keyMap).length === 0) {\n return response;\n }\n\n // Clone the data to avoid mutating the original\n const clonedData = JSON.parse(JSON.stringify(response.data));\n\n // Sort paths from deepest to shallowest to avoid breaking nested access\n // when parent arrays have their keys renamed\n const sortedArrays = [...filteredArrays].sort((a, b) => {\n const depthA = (a.path.match(/\\./g) || []).length + (a.path.match(/\\[/g) || []).length;\n const depthB = (b.path.match(/\\./g) || []).length + (b.path.match(/\\[/g) || []).length;\n return depthB - depthA; // Deepest first\n });\n\n // Compress each array and update in the cloned data\n const paths: string[] = [];\n for (const { path, data } of sortedArrays) {\n const compressedArray = data.map(item =>\n compressObjectWithMap(item, keyToShort, config.maxDepth)\n );\n setAtPath({ data: clonedData } as Record<string, unknown>, path, compressedArray);\n paths.push(path);\n }\n\n // Build the terse metadata\n const terseMeta: GraphQLTerseMetadata = {\n v: 1,\n k: keyMap,\n paths,\n };\n\n // Build the response\n const terseResponse: GraphQLTerseResponse<T['data']> = {\n data: clonedData as T['data'],\n __terse__: terseMeta,\n };\n\n // Preserve errors and extensions if present\n if ('errors' in response && response.errors) {\n terseResponse.errors = response.errors as GraphQLTerseResponse['errors'];\n }\n if ('extensions' in response && response.extensions) {\n terseResponse.extensions = response.extensions as GraphQLTerseResponse['extensions'];\n }\n\n if (config.debug) {\n const originalSize = JSON.stringify(response).length;\n const compressedSize = JSON.stringify(terseResponse).length;\n const savings = ((1 - compressedSize / originalSize) * 100).toFixed(1);\n console.log(\n `[tersejson/graphql] Compressed ${originalSize} -> ${compressedSize} bytes (${savings}% savings)`\n );\n console.log(`[tersejson/graphql] Compressed paths: ${paths.join(', ')}`);\n }\n\n return terseResponse;\n}\n\n/**\n * Creates a format function for express-graphql\n *\n * @example\n * ```typescript\n * import { graphqlHTTP } from 'express-graphql';\n * import { createTerseFormatFn } from 'tersejson/graphql';\n *\n * app.use('/graphql', graphqlHTTP({\n * schema: mySchema,\n * formatResult: createTerseFormatFn({ debug: true }),\n * }));\n * ```\n */\nexport function createTerseFormatFn(options: GraphQLTerseOptions = {}) {\n return function formatResult(\n result: { data?: unknown; errors?: unknown[]; extensions?: Record<string, unknown> },\n _context?: unknown,\n _info?: unknown\n ) {\n return compressGraphQLResponse(result, options);\n };\n}\n\n/**\n * Express middleware wrapper for express-graphql\n *\n * @example\n * ```typescript\n * import { graphqlHTTP } from 'express-graphql';\n * import { terseGraphQL } from 'tersejson/graphql';\n *\n * app.use('/graphql', terseGraphQL(\n * graphqlHTTP({\n * schema: mySchema,\n * graphiql: true,\n * }),\n * { debug: true }\n * ));\n * ```\n */\nexport function terseGraphQL(\n graphqlMiddleware: RequestHandler,\n options: GraphQLTerseOptions = {}\n): RequestHandler {\n const config = { ...DEFAULT_OPTIONS, ...options };\n\n return function terseGraphQLMiddleware(\n req: Request,\n res: Response,\n next: NextFunction\n ): void {\n // Check if client supports terse responses\n const acceptsTerse =\n req.headers['accept-terse'] === 'true' || req.headers['x-accept-terse'] === 'true';\n\n if (!acceptsTerse) {\n // Client doesn't support terse, pass through to original middleware\n graphqlMiddleware(req, res, next);\n return;\n }\n\n // Store original json method\n const originalJson = res.json.bind(res);\n\n // Override res.json to intercept the response\n res.json = function terseGraphQLJson(data: unknown): Response {\n // Check if this looks like a GraphQL response\n if (typeof data === 'object' && data !== null && 'data' in data) {\n try {\n const compressed = compressGraphQLResponse(\n data as { data?: unknown; errors?: unknown[]; extensions?: Record<string, unknown> },\n config\n );\n\n // If compression happened, set the header\n if ('__terse__' in compressed) {\n res.setHeader('x-terse-json', 'graphql');\n }\n\n return originalJson(compressed);\n } catch (error) {\n if (config.debug) {\n console.error('[tersejson/graphql] Compression failed:', error);\n }\n return originalJson(data);\n }\n }\n\n return originalJson(data);\n };\n\n // Call the original GraphQL middleware\n graphqlMiddleware(req, res, next);\n };\n}\n\n// Default export\nexport default terseGraphQL;\n"]}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
- export { d as client, c as compress, b as createKeyGenerator, a as createTerseProxy, e as expand, i as isCompressibleArray, w as wrapWithProxy } from './client-BQAZg7I8.mjs';
2
- export { C as CompressOptions, d as KeyGenerator, K as KeyPattern, c as KeyPatternPreset, N as NestedHandling, b as TerseClientOptions, a as TerseMiddlewareOptions, T as TersePayload, e as Tersed, i as isTersePayload } from './types-CzaGQaV7.mjs';
3
- export { e as express } from './express-BoL__Ao6.mjs';
1
+ export { d as client, c as compress, b as createKeyGenerator, a as createTerseProxy, e as expand, i as isCompressibleArray, w as wrapWithProxy } from './client-CFGvusCj.mjs';
2
+ export { C as CompressOptions, G as GraphQLTerseMetadata, g as GraphQLTerseOptions, f as GraphQLTerseResponse, d as KeyGenerator, K as KeyPattern, c as KeyPatternPreset, N as NestedHandling, b as TerseClientOptions, a as TerseMiddlewareOptions, T as TersePayload, e as Tersed, h as isGraphQLTersePayload, i as isTersePayload } from './types-BTonKlz8.mjs';
3
+ export { e as express } from './express-O5w2NBTf.mjs';
4
4
  export { i as integrations } from './integrations-7WeFO1Lk.mjs';
5
+ export { g as graphql } from './graphql-C3PTnqnZ.mjs';
6
+ export { g as graphqlClient } from './graphql-client-2H4FjmRc.mjs';
5
7
  export { AnalyticsConfig, AnalyticsStats, CompressionEvent, TerseAnalytics, default as analytics, getAnalytics, initAnalytics, recordEvent } from './analytics.mjs';
6
8
  import 'express';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- export { d as client, c as compress, b as createKeyGenerator, a as createTerseProxy, e as expand, i as isCompressibleArray, w as wrapWithProxy } from './client-DOOGwp_p.js';
2
- export { C as CompressOptions, d as KeyGenerator, K as KeyPattern, c as KeyPatternPreset, N as NestedHandling, b as TerseClientOptions, a as TerseMiddlewareOptions, T as TersePayload, e as Tersed, i as isTersePayload } from './types-CzaGQaV7.js';
3
- export { e as express } from './express-LSVylWpN.js';
1
+ export { d as client, c as compress, b as createKeyGenerator, a as createTerseProxy, e as expand, i as isCompressibleArray, w as wrapWithProxy } from './client-hUXNNGcN.js';
2
+ export { C as CompressOptions, G as GraphQLTerseMetadata, g as GraphQLTerseOptions, f as GraphQLTerseResponse, d as KeyGenerator, K as KeyPattern, c as KeyPatternPreset, N as NestedHandling, b as TerseClientOptions, a as TerseMiddlewareOptions, T as TersePayload, e as Tersed, h as isGraphQLTersePayload, i as isTersePayload } from './types-BTonKlz8.js';
3
+ export { e as express } from './express-Da7WcJtt.js';
4
4
  export { i as integrations } from './integrations-7WeFO1Lk.js';
5
+ export { g as graphql } from './graphql-DmtweJgh.js';
6
+ export { g as graphqlClient } from './graphql-client-BXGtWqe9.js';
5
7
  export { AnalyticsConfig, AnalyticsStats, CompressionEvent, TerseAnalytics, default as analytics, getAnalytics, initAnalytics, recordEvent } from './analytics.js';
6
8
  import 'express';