diff --git a/lib/data.ts b/lib/data.ts new file mode 100644 index 0000000..a028406 --- /dev/null +++ b/lib/data.ts @@ -0,0 +1,49 @@ +import { Client } from "typesense"; + +const client = new Client({ + nodes: [ + { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + host: process.env.TYPESENSE_HOST!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + port: Number(process.env.TYPESENSE_PORT!), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + protocol: process.env.TYPESENSE_PROTOCOL!, + }, + ], + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + apiKey: process.env.TYPESENSE_API_KEY!, + connectionTimeoutSeconds: 2, +}); + +const collection = client.collections("thomas-bernhard"); + +function getDistinct(field: string): Promise> { + return ( + collection + .documents() + // this does not work as expected when grouping by an array field (or a nested field which has + // an object[] anywhere in its path) because grouping then happens by the array of values, not + // by individual values. for example: await getDistinct("contains.work.title") + .search({ + q: "", + query_by: field, + group_by: field, + per_page: 250, // 250 is the hard maximum for typesense + group_limit: 1, // we're not interested in the actual documents, but gotta retrieve at least 1.. + }) + .then((r) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return r + .grouped_hits!.map((l) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return l.group_key[0]!; + }) + .sort(); + }) + ); +} + +export function getLanguages(): Promise> { + return getDistinct("language"); +} diff --git a/package.json b/package.json index d2ee257..b8b3c6c 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "server-only": "^0.0.1", "sharp": "^0.33.4", "shiki": "^1.10.3", + "typesense": "^1.8.2", "valibot": "^0.36.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6410bfb..9c483f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: shiki: specifier: ^1.10.3 version: 1.10.3 + typesense: + specifier: ^1.8.2 + version: 1.8.2(@babel/runtime@7.25.0) valibot: specifier: ^0.36.0 version: 0.36.0 @@ -362,6 +365,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.25.0': + resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.24.7': resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} @@ -1537,6 +1544,9 @@ packages: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1556,6 +1566,9 @@ packages: peerDependencies: playwright: '>1.0.0' + axios@1.7.3: + resolution: {integrity: sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==} + axobject-query@3.1.1: resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} @@ -1700,6 +1713,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1822,6 +1839,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2191,6 +2212,15 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -2198,6 +2228,10 @@ packages: resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} engines: {node: '>=14'} + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -2714,6 +2748,10 @@ packages: resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} engines: {node: '>=18'} + loglevel@1.9.1: + resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==} + engines: {node: '>= 0.6.0'} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -3272,6 +3310,9 @@ packages: property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -3338,6 +3379,9 @@ packages: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp-ast-analysis@0.7.1: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -3821,6 +3865,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + typesense@1.8.2: + resolution: {integrity: sha512-aBpePjA99Qvo+OP2pJwMpvga4Jrm1Y2oV5NsrWXBxlqUDNEUCPZBIksPv2Hq0jxQxHhLLyJVbjXjByXsvpCDVA==} + engines: {node: '>=18'} + peerDependencies: + '@babel/runtime': ^7.23.2 + unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -4240,6 +4290,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/runtime@7.25.0': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/template@7.24.7': dependencies: '@babel/code-frame': 7.24.7 @@ -5903,6 +5957,8 @@ snapshots: astring@1.8.6: {} + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -5924,6 +5980,14 @@ snapshots: picocolors: 1.0.1 playwright: 1.45.2 + axios@1.7.3: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@3.1.1: dependencies: deep-equal: 2.2.3 @@ -6060,6 +6124,10 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@12.1.0: {} @@ -6179,6 +6247,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + dequal@2.0.3: {} detect-libc@2.0.3: {} @@ -6726,6 +6796,8 @@ snapshots: flatted@3.3.1: {} + follow-redirects@1.15.6: {} + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -6735,6 +6807,12 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + format@0.2.2: {} fs.realpath@1.0.0: {} @@ -7272,6 +7350,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + loglevel@1.9.1: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -8093,6 +8173,8 @@ snapshots: property-information@6.5.0: {} + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -8243,6 +8325,8 @@ snapshots: globalthis: 1.0.4 which-builtin-type: 1.1.3 + regenerator-runtime@0.14.1: {} + regexp-ast-analysis@0.7.1: dependencies: '@eslint-community/regexpp': 4.11.0 @@ -8884,6 +8968,14 @@ snapshots: typescript@5.5.3: {} + typesense@1.8.2(@babel/runtime@7.25.0): + dependencies: + '@babel/runtime': 7.25.0 + axios: 1.7.3 + loglevel: 1.9.1 + transitivePeerDependencies: + - debug + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.7