1
0
Fork 0
mirror of https://github.com/mat-1/matdoesdev.git synced 2025-08-02 14:46:04 +00:00
This commit is contained in:
mat 2024-01-01 00:36:35 -06:00
parent f6b9db6160
commit 6b08b2bbed
15 changed files with 769 additions and 26 deletions

Binary file not shown.

View file

@ -1,25 +1,25 @@
(https_redirect) {
@do_https_redirect {
not header_regexp veryoldbrowser User-Agent Navigator|MSIE|Mosaic
protocol http
}
redir @do_https_redirect https://{host}{uri}
@do_https_redirect {
not header_regexp veryoldbrowser User-Agent Navigator|MSIE|Mosaic|Kindle
protocol http
}
redir @do_https_redirect https://{host}{uri}
}
(gif_redirect) {
@do_not_gif_redirect {
not header_regexp oldweb_today Origin http://localhost:10001
@do_not_gif_redirect {
not header_regexp oldweb_today Origin http://localhost:10001
not header_regexp oldweb_today Origin oldweb.today
not header_regexp veryveryoldbrowser User-Agent Navigator|MSIE|NCSA_Mosaic
}
vars not_gif_redirect false
vars @do_not_gif_redirect not_gif_redirect true
@do_gif_redirect {
expression `{vars.not_gif_redirect} == false`
path_regexp ^/retro/.*\.png$
}
not header_regexp veryveryoldbrowser User-Agent Navigator|MSIE|NCSA_Mosaic
}
vars not_gif_redirect false
vars @do_not_gif_redirect not_gif_redirect true
@do_gif_redirect {
expression `{vars.not_gif_redirect} == false`
path_regexp ^/retro/.*\.png$
}
uri @do_gif_redirect path_regexp \.png$ .gif
uri @do_gif_redirect path_regexp \.png$ .gif
}
matdoes.dev:80 matdoes.dev:443 http://matctazmu565vivubva3p3bulaneangiff47xmnezzjx2nuinwjoxjyd.onion {
@ -33,21 +33,21 @@ matdoes.dev:80 matdoes.dev:443 http://matctazmu565vivubva3p3bulaneangiff47xmnezz
# block chrome but not chromium-based browsers
@chrome {
header_regexp chrome User-Agent Chrome\/[0-9./]+\s(Mobile\s)?Safari\/[0-9./]+$
not header User-Agent *Googlebot/*
not path /dot_git/*
not header_regexp not_chrome User-Agent Googlebot/|eightyeightthirtyone
not path /dot_git/*
}
respond @chrome "This site is best viewed with Firefox (or literally any browser that isn't Chrome).
respond @chrome "This site is best viewed with Firefox (or any browser that isn't Chrome).
If you're unable to use Firefox, you can also access this website via SSH, Gemini, Gopher, Finger, Telnet, and some others." 403
root * /www
# easter egg that makes old browsers show the retro page
@retro_redirect {
path /
header_regexp oldbrowser User-Agent PaleMoon|Trident|MSIE|Netscape|Navigator
}
header_regexp oldbrowser User-Agent PaleMoon|Trident|MSIE|Netscape|Navigator
}
redir @retro_redirect /retro 302
root * /www
file_server {
precompressed br gzip
}
@ -93,6 +93,18 @@ If you're unable to use Firefox, you can also access this website via SSH, Gemin
# .git easter egg
uri /.git/* replace .git dot_git 1
route /buttons/88x31.* {
uri strip_prefix /buttons
file_server {
root /opt/x227f
}
}
handle_path /buttons/i/* {
try_files {path} {path}.png {path}.gif {path}.jpg {path}.webp {path}.avif {path}.bmp
root * /opt/x227f/buttons
file_server
}
handle_errors {
@should_be_404 {
expression {http.error.status_code} == 404
@ -112,13 +124,12 @@ If you're unable to use Firefox, you can also access this website via SSH, Gemin
file_server @is_451 {
status 451
}
rewrite @should_be_404 /404.html
file_server @is_not_451
}
}
(matrix_media_proxy) {
handle /_matrix/media/*/download/matdoes.dev/discord_* {
header Access-Control-Allow-Origin *
@ -181,7 +192,10 @@ f.matdoes.dev {
reverse_proxy 127.0.0.1:4000
}
git.matdoes.dev {
reverse_proxy 127.0.0.1:3000
reverse_proxy 127.0.0.1:3000
}
s.matdoes.dev {
reverse_proxy 127.0.0.1:28019
}
mail.matdoes.dev {
@ -208,3 +222,7 @@ hetzner.matdoes.dev {
}
respond "uwu" 402
}
xmpp.matdoes.dev {
respond ""
}

View file

@ -38,6 +38,7 @@
"@sveltejs/adapter-static": "^2.0.3",
"@sveltejs/kit": "1.27.7",
"@types/js-yaml": "^4.0.9",
"cbor-x": "^1.5.6",
"cookie": "^0.6.0",
"html-minifier": "^4.0.0",
"patch-package": "^8.0.0",

View file

@ -0,0 +1,2 @@
export const ssr = false
export const prerender = false

View file

@ -0,0 +1,62 @@
<script lang="ts">
import { page } from '$app/stores'
import { writable } from 'svelte/store'
import './app.css'
import { buttonIndexFromHash, pageIndexFromName } from './88x31'
$: selectedPage = $page.url.pathname.split('/').pop()
let selectedButtonHash = writable<string | null>(null)
let selectedPageName = writable<string | null>(null)
page.subscribe(async (page) => {
await new Promise((r) => requestAnimationFrame(r))
const hash = page.url.hash.slice(1)
// if the hash has a . then it's a page name
if (hash === '') {
selectedButtonHash.set(null)
selectedPageName.set(null)
} else if (hash.includes('.')) {
selectedButtonHash.set(null)
selectedPageName.set(hash)
} else {
selectedButtonHash.set(hash)
selectedPageName.set(null)
}
})
</script>
<header>
<nav>
<a href="/buttons" class:selected={selectedPage === 'buttons'}>List</a>
<a
href="/buttons/degrees{$selectedPageName ? `#${$selectedPageName}` : ''}"
class:selected={selectedPage === 'degrees'}>Degrees of separation</a
>
<!-- <a href="/buttons/stats" class:selected={selectedPage === 'stats'}>Stats</a> -->
</nav>
<nav class="source">
<a href="https://github.com/mat-1/x227f">Source</a>
</nav>
</header>
<main>
<slot />
</main>
<style>
nav {
display: flex;
gap: 0.5em;
}
header {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.selected {
font-weight: bold;
}
</style>

View file

@ -0,0 +1,238 @@
<script lang="ts">
import { onDestroy, onMount } from 'svelte'
import { buttonIndexFromHash, buttonUrlFromIndex, data, pageIndexFromName } from './88x31'
import { writable } from 'svelte/store'
import { page } from '$app/stores'
import ButtonLink from './ButtonLink.svelte'
import ExternalLinkIcon from './ExternalLinkIcon.svelte'
import ExternalLink from './ExternalLink.svelte'
let searchQuery = writable('')
let sort = writable('relevance')
let visibleButtons = new Set<string>()
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
visibleButtons.add(entry.target.id)
} else {
visibleButtons.delete(entry.target.id)
}
})
visibleButtons = visibleButtons
})
let buttonsEl: HTMLDivElement
// when a new button is added, observe it
const buttonContainerObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLDivElement && node.classList.contains('button-container')) {
observer.observe(node)
}
})
})
})
let refs: HTMLDivElement[] = []
onMount(() => {
buttonContainerObserver.observe(buttonsEl, {
childList: true,
})
// observe initial buttons
refs.forEach((ref) => {
observer.observe(ref)
})
})
onDestroy(() => {
refs.forEach((ref) => {
observer.unobserve(ref)
})
buttonContainerObserver.disconnect()
})
let matchingTextIndexes = new Set<number>()
let buttonEntries: [number, string][] = [...data.buttons.entries()]
searchQuery.subscribe(updateSearch)
sort.subscribe(updateSearch)
function updateSearch() {
const value = $searchQuery
const sortValue = $sort
const newMatchingTextIndexes = new Set<number>()
if (value !== '') {
for (let textIndex = 0; textIndex < data.texts.length; textIndex++) {
if (data.texts[textIndex].toLowerCase().includes(value.toLowerCase())) {
newMatchingTextIndexes.add(textIndex)
}
}
}
matchingTextIndexes = newMatchingTextIndexes
// filter buttonEntries
const newButtonEntriesWithScore: [number, [number, string]][] = []
for (let buttonIndex = 0; buttonIndex < data.button_names.length; buttonIndex++) {
const textIndexes = data.button_names[buttonIndex]
if (value === '' || textIndexes.some((textIndex) => matchingTextIndexes.has(textIndex))) {
// lower score is better
let score: number
if (sortValue === 'relevance') {
if (value === '') {
// relevance search doesn't make sense if there's no query
score = 0
} else {
// shortest text index
const textIndexLengths = textIndexes
.map((textIndex) => data.texts[textIndex])
.filter((text) => {
return text.toLowerCase().includes(value.toLowerCase())
})
.map((text) => text.length)
score = Math.min(...textIndexLengths)
}
} else if (sortValue === 'popularity') {
score = 1 / data.button_backlinks[buttonIndex].length
} else if (sortValue === 'random') {
score = Math.random()
} else {
throw new Error(`Unknown sort value: ${sortValue}`)
}
newButtonEntriesWithScore.push([score, [buttonIndex, data.buttons[buttonIndex]]])
}
}
const newButtonEntries = newButtonEntriesWithScore
.sort((a, b) => a[0] - b[0])
.map((entry) => entry[1])
buttonEntries = newButtonEntries
}
let selectedButtonHash = writable<string | null>(null)
$: selectedButtonIndex =
$selectedButtonHash === null ? null : buttonIndexFromHash($selectedButtonHash)
let selectedPageName = writable<string | null>(null)
$: selectedPageIndex = $selectedPageName === null ? null : pageIndexFromName($selectedPageName)
page.subscribe(async (page) => {
// this is to work around a sveltekit bug that makes it click the hash twice, which clicks the wrong link the second time
await new Promise((r) => requestAnimationFrame(r))
// hash
const hash = page.url.hash.slice(1)
// if the hash has a . then it's a page name
if (hash === '') {
selectedButtonHash.set(null)
selectedPageName.set(null)
} else if (hash.includes('.')) {
selectedButtonHash.set(null)
selectedPageName.set(hash)
} else {
selectedButtonHash.set(hash)
selectedPageName.set(null)
}
})
</script>
{#if selectedButtonIndex !== null}
<h1>
<img src={buttonUrlFromIndex(selectedButtonIndex)} alt="Button" class="button" />
</h1>
<p>Links to ({data.button_links[selectedButtonIndex].length}):</p>
<ul>
{#each data.button_links[selectedButtonIndex] as pageIndex, i}
<li>
<ExternalLink {pageIndex} />
</li>
{/each}
</ul>
<p>Linked from ({data.button_backlinks[selectedButtonIndex].length}):</p>
<ul>
{#each data.button_backlinks[selectedButtonIndex] as pageIndex, i}
<li>
<ExternalLink {pageIndex} />
</li>
{/each}
</ul>
{:else if selectedPageIndex !== null}
<h1>
{$selectedPageName}
<a href="https://{data.pages[selectedPageIndex]}">
<ExternalLinkIcon />
</a>
</h1>
<p>Buttons ({data.links[selectedPageIndex].length}):</p>
<div class="normal-button-grid">
{#each data.links[selectedPageIndex] as linkedPageIndex, i}
<ButtonLink
pageIndex={linkedPageIndex}
buttonIndex={data.link_buttons[selectedPageIndex][i]}
/>
{/each}
</div>
<p>Linked from ({data.backlinks[selectedPageIndex].length}):</p>
<div class="normal-button-grid">
{#each data.backlinks[selectedPageIndex] as backlinkedPageIndex, i}
<ButtonLink
pageIndex={backlinkedPageIndex}
buttonIndex={data.backlink_buttons[selectedPageIndex][i]}
/>
{/each}
</div>
{/if}
<div class:hidden={selectedButtonIndex !== null || selectedPageIndex !== null}>
<input type="text" placeholder="Search" bind:value={$searchQuery} />
<select bind:value={$sort}>
<option value="relevance">Relevance</option>
<option value="popularity">Popularity</option>
<option value="random">Random</option>
</select>
<p><b>{buttonEntries.length.toLocaleString()}</b> buttons</p>
<div class="compact-button-grid" bind:this={buttonsEl}>
{#each buttonEntries as [index, buttonHash] (buttonHash)}
<div class="button-container" id={buttonHash} bind:this={refs[index]}>
{#if visibleButtons.has(buttonHash)}
<a href="/buttons#{buttonHash}">
<img src={buttonUrlFromIndex(index)} alt="Button" class="button" />
</a>
{/if}
</div>
{/each}
</div>
</div>
<style>
.compact-button-grid {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
.normal-button-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.button-container {
display: inline-block;
width: 88px;
height: 31px;
}
.hidden {
display: none;
}
</style>

View file

@ -0,0 +1,62 @@
import { decode } from 'cbor-x/decode'
interface Data {
pages: string[]
buttons: string[]
texts: string[]
button_file_exts: string[]
button_names: number[][]
button_links: number[][]
button_backlinks: number[][]
links: number[][]
link_buttons: number[][]
link_button_alts: (number | null)[][]
link_button_titles: (number | null)[][]
backlinks: number[][]
backlink_buttons: number[][]
}
const res = await fetch('https://matdoes.dev/buttons/88x31.cbor')
const buffer = await res.arrayBuffer()
export const data: Data = decode(new Uint8Array(buffer))
export function buttonUrlFromIndex(index: number) {
const hash = buttonHashFromIndex(index)
const ext = data.button_file_exts[index]
return `https://matdoes.dev/buttons/i/${hash}.${ext}`
}
export function buttonUrlFromHash(hash: string) {
return `https://matdoes.dev/buttons/i/${hash}`
}
export function buttonHashFromIndex(index: number) {
return data.buttons[index]
}
function binarySearch<T>(arr: T[], key: T): number | null {
let low = 0
let high = arr.length - 1
while (low <= high) {
const mid = (low + high) >>> 1
const midVal = arr[mid]
if (midVal < key) low = mid + 1
else if (midVal > key) high = mid - 1
else return mid
}
return null
}
export function pageIndexFromName(name: string): number | null {
return binarySearch(data.pages, name)
}
export function buttonIndexFromHash(hash: string): number | null {
return binarySearch(data.buttons, hash)
}

View file

@ -0,0 +1,25 @@
<script lang="ts">
import { buttonHashFromIndex, buttonUrlFromIndex, data } from './88x31'
import ExternalLink from './ExternalLink.svelte'
import ExternalLinkIcon from './ExternalLinkIcon.svelte'
export let pageIndex: number
export let buttonIndex: number
</script>
<div class="button-with-link-container">
{#if pageIndex !== null}
<ExternalLink {pageIndex} />
{/if}
<a href="/buttons#{buttonHashFromIndex(buttonIndex)}">
<img src={buttonUrlFromIndex(buttonIndex)} alt="Button" class="button" />
</a>
</div>
<style>
.button-with-link-container {
display: inline-flex;
flex-direction: column;
max-width: 100px;
}
</style>

View file

@ -0,0 +1,26 @@
<script lang="ts">
import { data } from './88x31'
import ExternalLinkIcon from './ExternalLinkIcon.svelte'
export let pageIndex: number
function cutOff(str: string, length: number) {
if (str.length <= length) return str
return str.slice(0, length - 1) + '…'
}
</script>
<div>
<a href="/buttons#{data.pages[pageIndex]}">{cutOff(data.pages[pageIndex], 32)}</a>
<a href="https://{data.pages[pageIndex]}">
<ExternalLinkIcon />
</a>
</div>
<style>
a {
word-break: break-all;
overflow: hidden;
width: fit-content;
}
</style>

View file

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path
d="M432 320H400a16 16 0 0 0 -16 16V448H64V128H208a16 16 0 0 0 16-16V80a16 16 0 0 0 -16-16H48A48 48 0 0 0 0 112V464a48 48 0 0 0 48 48H400a48 48 0 0 0 48-48V336A16 16 0 0 0 432 320zM488 0h-128c-21.4 0-32.1 25.9-17 41l35.7 35.7L135 320.4a24 24 0 0 0 0 34L157.7 377a24 24 0 0 0 34 0L435.3 133.3 471 169c15 15 41 4.5 41-17V24A24 24 0 0 0 488 0z"
/>
</svg>
<style>
svg {
fill: currentColor;
height: 0.8em;
}
</style>

After

Width:  |  Height:  |  Size: 491 B

View file

@ -0,0 +1,31 @@
body {
background-color: #1e1e2e;
color: #cdd6f4;
/* serif is chosen intentionally as it makes the website look worse */
font-family: serif;
margin: 0.5rem;
}
input,
button,
select {
background-color: #313244;
color: #cdd6f4;
border: 1px solid #9399b2;
border-radius: 4px;
padding: 0.25em;
}
button {
cursor: pointer;
}
a {
color: #89b4fa;
}
.button {
width: 88px;
height: 31px;
image-rendering: pixelated;
}

View file

@ -0,0 +1,169 @@
<script lang="ts">
import { writable } from 'svelte/store'
import { pageIndexFromName, data } from '../88x31'
import ButtonLink from '../ButtonLink.svelte'
import { onMount } from 'svelte'
import { page } from '$app/stores'
let originPage = writable('')
let targetPage = writable('')
let originPageId: number | null
let targetPageId: number | null
let pageAndButtonIndexes: [number, number][] | null = []
function calculatePath() {
originPageId = pageIndexFromName($originPage)
targetPageId = pageIndexFromName($targetPage)
if (originPageId === null || targetPageId === null) return
// determine the button for site 1 (since we won't find it by following links here)
const originButtonIndexes: number[] = data.backlink_buttons[originPageId]
const originButtonIndex = originButtonIndexes.sort(
(a, b) =>
originButtonIndexes.filter((v) => v === a).length -
originButtonIndexes.filter((v) => v === b).length
)[0]
if (originPageId === targetPageId) {
pageAndButtonIndexes = [[originPageId, originButtonIndex]]
return
}
// breadth first search
let nextQueue = [originPageId]
let visited = new Set<number>()
let found = false
let cameFrom = new Map<number, number>()
while (nextQueue.length > 0) {
let queue = nextQueue
nextQueue = []
for (let pageId of queue) {
if (pageId === targetPageId) {
found = true
break
}
for (let link of data.links[pageId]) {
if (link === null) continue
if (visited.has(link)) continue
visited.add(link)
nextQueue.push(link)
cameFrom.set(link, pageId)
}
}
if (found) break
}
console.log('found', found)
if (!found) {
pageAndButtonIndexes = null
return
}
console.log('targetPageId', targetPageId)
let nextItem: number = targetPageId
let current: number = cameFrom.get(nextItem)!
const targetBacklinkIndex = data.links[current]?.indexOf(nextItem)
const targetButtonIndex =
targetBacklinkIndex === undefined ? -1 : data.link_buttons[current][targetBacklinkIndex]
// reconstruct path
let pageAndButtonIndexesReversed: [number, number][] = [[targetPageId, targetButtonIndex]]
while (current !== originPageId) {
nextItem = cameFrom.get(current)!
const backlinkIndex = data.links[nextItem]?.indexOf(current)
const buttonIndex =
backlinkIndex === undefined ? -1 : data.link_buttons[nextItem][backlinkIndex]
pageAndButtonIndexesReversed.push([current, buttonIndex])
current = nextItem
}
pageAndButtonIndexesReversed.push([originPageId, originButtonIndex])
pageAndButtonIndexes = pageAndButtonIndexesReversed.reverse()
localStorage.setItem('88x31-degrees-originPage', $originPage)
localStorage.setItem('88x31-degrees-targetPage', $targetPage)
}
onMount(() => {
return page.subscribe(async (page) => {
const hash = decodeURIComponent(page.url.hash.slice(1))
let [origin, target] = hash.split('→')
if (origin === undefined) origin = ''
if (target === undefined) target = ''
if (origin === '') origin = localStorage.getItem('88x31-degrees-originPage') ?? ''
if (target === '') target = localStorage.getItem('88x31-degrees-targetPage') ?? ''
if (origin !== '' && $originPage !== origin) originPage.set(origin)
if (target !== '' && $targetPage !== target) targetPage.set(target)
})
})
originPage.subscribe(calculatePath)
targetPage.subscribe(calculatePath)
originPage.subscribe(updateHash)
targetPage.subscribe(updateHash)
function updateHash() {
history.replaceState(null, '', `#${$originPage}→${$targetPage}`)
}
</script>
<input
type="text"
bind:value={$originPage}
placeholder="Origin page"
class:invalid={originPageId === null}
/>
<input
type="text"
bind:value={$targetPage}
placeholder="Target page"
class:invalid={targetPageId === null}
/>
<div>
{#if originPageId !== null && targetPageId !== null}
{#if pageAndButtonIndexes === null}
<p><b>No path :&#40;</b></p>
{:else}
<p>
{#if pageAndButtonIndexes.length - 1 === 1}
<b>1</b> degree of separation
{:else}
<b>{pageAndButtonIndexes.length - 1}</b> degrees of separation
{/if}
</p>
{#each pageAndButtonIndexes as [pageIndex, buttonIndex], i}
{#if i > 0}
<span class="arrow"></span>
{/if}
<ButtonLink {pageIndex} {buttonIndex} />
{/each}
{/if}
{/if}
</div>
<style>
.invalid {
border-color: red;
}
</style>

View file

View file

@ -1,7 +1,7 @@
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"module": "es2022",
"lib": ["es2020", "DOM", "WebWorker"],
"target": "es2020",
/**

View file

@ -22,6 +22,48 @@ __metadata:
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-darwin-arm64@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-darwin-arm64@npm:2.1.1"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-darwin-x64@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-darwin-x64@npm:2.1.1"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-linux-arm64@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-linux-arm64@npm:2.1.1"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-linux-arm@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-linux-arm@npm:2.1.1"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-linux-x64@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-linux-x64@npm:2.1.1"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
"@cbor-extract/cbor-extract-win32-x64@npm:2.1.1":
version: 2.1.1
resolution: "@cbor-extract/cbor-extract-win32-x64@npm:2.1.1"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@emnapi/runtime@npm:^0.44.0":
version: 0.44.0
resolution: "@emnapi/runtime@npm:0.44.0"
@ -1275,6 +1317,49 @@ __metadata:
languageName: node
linkType: hard
"cbor-extract@npm:^2.1.1":
version: 2.1.1
resolution: "cbor-extract@npm:2.1.1"
dependencies:
"@cbor-extract/cbor-extract-darwin-arm64": "npm:2.1.1"
"@cbor-extract/cbor-extract-darwin-x64": "npm:2.1.1"
"@cbor-extract/cbor-extract-linux-arm": "npm:2.1.1"
"@cbor-extract/cbor-extract-linux-arm64": "npm:2.1.1"
"@cbor-extract/cbor-extract-linux-x64": "npm:2.1.1"
"@cbor-extract/cbor-extract-win32-x64": "npm:2.1.1"
node-gyp: "npm:latest"
node-gyp-build-optional-packages: "npm:5.0.3"
dependenciesMeta:
"@cbor-extract/cbor-extract-darwin-arm64":
optional: true
"@cbor-extract/cbor-extract-darwin-x64":
optional: true
"@cbor-extract/cbor-extract-linux-arm":
optional: true
"@cbor-extract/cbor-extract-linux-arm64":
optional: true
"@cbor-extract/cbor-extract-linux-x64":
optional: true
"@cbor-extract/cbor-extract-win32-x64":
optional: true
bin:
download-cbor-prebuilds: bin/download-prebuilds.js
checksum: e7471f9ad421d352d60079faa63234ea7795d4ae64ce617a49a5f3b82a1a95e81c141f75bc1d7c0ae3d7dca924a78f9109aab5ee2a2113830bf67705c08839d0
languageName: node
linkType: hard
"cbor-x@npm:^1.5.6":
version: 1.5.6
resolution: "cbor-x@npm:1.5.6"
dependencies:
cbor-extract: "npm:^2.1.1"
dependenciesMeta:
cbor-extract:
optional: true
checksum: c9ac318e4a47bccae73f7e697a28a5738670edac87f9df5bd673cd9ca9a35eae9fe7897b25773a5d2577208f5fc0cdbb9d688a2de0b1db6d3352f503f6e3efcd
languageName: node
linkType: hard
"chalk@npm:^4.0.0, chalk@npm:^4.1.2":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
@ -2565,6 +2650,7 @@ __metadata:
"@types/js-yaml": "npm:^4.0.9"
"@typescript-eslint/eslint-plugin": "npm:^6.13.2"
"@typescript-eslint/parser": "npm:^6.13.2"
cbor-x: "npm:^1.5.6"
cookie: "npm:^0.6.0"
eslint: "npm:^8.55.0"
eslint-config-prettier: "npm:^9.1.0"
@ -2821,6 +2907,17 @@ __metadata:
languageName: node
linkType: hard
"node-gyp-build-optional-packages@npm:5.0.3":
version: 5.0.3
resolution: "node-gyp-build-optional-packages@npm:5.0.3"
bin:
node-gyp-build-optional-packages: bin.js
node-gyp-build-optional-packages-optional: optional.js
node-gyp-build-optional-packages-test: build-test.js
checksum: 334336bdefb398469a115a2c9d4c141d28e093fd703be7adc1448f9dd3e1b5525281a789be8a60a778c91212daaa310155b1908b1fb9a987cec61a9fe04d774a
languageName: node
linkType: hard
"node-gyp@npm:latest":
version: 10.0.0
resolution: "node-gyp@npm:10.0.0"