Compare commits

..

2 Commits

Author SHA1 Message Date
706308148e update to sync jar and npm versions
update to v0.9.3
2026-03-08 00:50:36 -05:00
1c06197be0 resolve issue with missing vite-plugin-node-polyfills
add LibreJS licenses to all demo JS
split browser build from node build
add copyright info to license files
update to use yarn v4.13.0
update to v0.9.2
2026-03-07 20:47:14 -05:00
52 changed files with 259 additions and 57 deletions

View File

@@ -1 +1,7 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/

View File

@@ -8,10 +8,11 @@ import {
rm,
writeFile,
} from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig, build as viteBuild } from "vite";
import noBundlePlugin from "vite-plugin-no-bundle";
import { nodePolyfills } from "vite-plugin-node-polyfills";
const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -21,27 +22,25 @@ const browserOutPath = `${outputPathPrefix}-browser`;
const browserOutDir = resolve(__dirname, browserOutPath);
const demoOutDir = resolve(__dirname, `${outputPathPrefix}-demo`);
const entry = "src/index.ts";
const globalConfig = {
libraryName: "twtxt-lib",
basePath: resolve(__dirname),
outDir: resolve(__dirname, outputPathPrefix),
builds: [
{
entry,
entry: "src/browser.ts",
outDir: browserOutDir,
outfile: "twtxt-lib.js",
target: "browser",
},
{
entry,
entry: "src/browser.ts",
outDir: browserOutDir,
outfile: "twtxt-lib.min.js",
target: "browser",
},
{
entry,
entry: "src/index.ts",
outDir: resolve(__dirname, `${outputPathPrefix}-node`),
target: "node",
},
@@ -84,7 +83,18 @@ const buildWithVite = async (config) => {
const plugins = [
dts({ exclude: ["./vitest.setup.ts", "**/__tests__/*.*"] }),
];
if (config.target !== "browser") plugins.push(noBundlePlugin());
if (config.target !== "browser") {
plugins.push([
noBundlePlugin(),
nodePolyfills({
include: ["buffer"],
globals: {
Buffer: true,
},
}),
]);
}
await viteBuild(
defineConfig({

5
dist-browser/browser.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export type * from './types.ts';
export { default as hashTwt } from './hashTwt.ts';
export { default as loadAndParseTwtxtFile } from './loadAndParseTwtxt.ts';
export { default as parseTwtxt } from './parseTwtxt.ts';
export { base32Encode } from './utils.ts';

View File

@@ -1,4 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
@@ -2894,7 +2900,6 @@ const base32Encode = (payload) => {
return encoder.write(payload).finalize();
};
const getValueOrFirstEntry = (value) => Array.isArray(value) && value.length ? value[0] : value;
globalThis.Buffer = Buffer$1;
const dateRegex = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/;
const formatRFC3339 = (date) => {
const pad = (num = 0) => `${+num < 10 ? 0 : ""}${+num}`;
@@ -3391,6 +3396,7 @@ function loadAndParseTwtxtFile(url = "") {
}
});
}
globalThis.Buffer = Buffer$1;
export {
base32Encode,
hashTwt,

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/
var er = Object.defineProperty, nr = Object.defineProperties;
var ir = Object.getOwnPropertyDescriptors;
var _t = Object.getOwnPropertySymbols;
@@ -1847,9 +1853,7 @@ function br() {
})(kt)), kt;
}
var Br = br();
const Er = /* @__PURE__ */ Mt(Br), Ir = (f) => new Er.Encoder({ type: "rfc4648" }).write(f).finalize(), $r = (f) => Array.isArray(f) && f.length ? f[0] : f;
globalThis.Buffer = yr;
const Fr = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/, Ur = (f) => {
const Er = /* @__PURE__ */ Mt(Br), Ir = (f) => new Er.Encoder({ type: "rfc4648" }).write(f).finalize(), $r = (f) => Array.isArray(f) && f.length ? f[0] : f, Fr = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/, Ur = (f) => {
const l = (p = 0) => `${+p < 10 ? 0 : ""}${+p}`, x = (p = 0) => `${+p < 1e3 ? 0 : ""}${+p < 100 ? 0 : ""}${+p < 10 ? 0 : ""}${+p}`;
let d = Fr.exec(f);
d && (d == null ? void 0 : d[9]) === void 0 && (d[9] = "+00"), d && (d == null ? void 0 : d[10]) === void 0 && (d[10] = "00");
@@ -2308,6 +2312,7 @@ function te(f = "") {
}
});
}
globalThis.Buffer = yr;
export {
Ir as base32Encode,
Ar as hashTwt,

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
// add default #overview route
if (!window.location.hash) {
window.location.hash = "overview";
}
});
// @license-end

View File

@@ -0,0 +1,7 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
const isGecko = !!navigator.userAgent.match(/gecko/i);
if (isGecko) document.body.classList.add("isGecko");
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
const currentHost = window.location.hostname;
@@ -10,3 +12,5 @@ document.addEventListener("DOMContentLoaded", () => {
}
});
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
export default function formatSource(source, panelId) {
source = (source ?? "").trim();
@@ -42,3 +44,5 @@ export default function formatSource(source, panelId) {
.getElementById(panelId)
.insertAdjacentHTML("beforeend", sourceHTML);
}
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { hashTwt } from "/dist-browser/twtxt-lib.js";
let wasHashTwtResultAppended = false;
@@ -61,3 +63,5 @@ formHash.addEventListener("submit", (e) => {
document.body.classList.add("isLoaded");
wasHashTwtResultAppended = true;
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -38,3 +40,5 @@ formatSource(
`,
"tabHashTwt-panel",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
const tabLoadAndParsePanel = document.getElementById("tabLoadAndParse-panel");
@@ -77,3 +79,5 @@ const loadAndParseClickHandler = (ev) => {
.getElementById(curr)
.addEventListener("click", loadAndParseClickHandler);
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -23,3 +25,5 @@ formatSource(
`,
"tabLoadAndParse-panel",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
// run in an IIFE (or event listener) to avoid issues with top-level await
@@ -34,3 +36,5 @@ import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
console.error(err);
}
})();
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -22,3 +24,5 @@ formatSource(
`,
"tabOverview-example",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { parseTwtxt } from "/dist-browser/twtxt-lib.js";
const tabParsePanel = document.getElementById("tabParse-panel");
@@ -74,3 +76,5 @@ const parseClickHandler = (ev) => {
.addEventListener("click", parseClickHandler);
},
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -25,3 +27,5 @@ formatSource(
`,
"tabParse-panel",
);
// @license-end

View File

@@ -365,24 +365,37 @@ body:not(:has(:target)) #tabOverview-link {
margin-top: -4.55rem;
}
.tab:target .tab-panel {
position: absolute;
z-index: 1;
}
body:not(:has(:target)) #tabOverview-panel {
display: block;
position: absolute;
z-index: 1;
}
.themeToggle-button {
bottom: auto;
position: absolute;
right: 1rem;
top: 1rem;
}
body:not(:has(:target)) #tabOverview-panel {
display: block;
position: absolute;
z-index: 1;
}
body.isGecko .tab-link {
margin-top: -4.65rem;
}
body.isGecko .tab-link:hover {
margin-top: -4.9rem;
}
body.isGecko .tab:target .tab-link,
body.isGecko .tab:target .tab-link:hover {
margin-top: -4.85rem;
}
}
/** State-Based Overrides */

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
const toggle = document.createElement("button");
@@ -27,3 +29,5 @@ document.addEventListener("DOMContentLoaded", () => {
document.body.appendChild(toggle);
});
// @license-end

5
dist-demo/dist-browser/browser.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export type * from './types.ts';
export { default as hashTwt } from './hashTwt.ts';
export { default as loadAndParseTwtxtFile } from './loadAndParseTwtxt.ts';
export { default as parseTwtxt } from './parseTwtxt.ts';
export { base32Encode } from './utils.ts';

View File

@@ -1,4 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
@@ -2894,7 +2900,6 @@ const base32Encode = (payload) => {
return encoder.write(payload).finalize();
};
const getValueOrFirstEntry = (value) => Array.isArray(value) && value.length ? value[0] : value;
globalThis.Buffer = Buffer$1;
const dateRegex = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/;
const formatRFC3339 = (date) => {
const pad = (num = 0) => `${+num < 10 ? 0 : ""}${+num}`;
@@ -3391,6 +3396,7 @@ function loadAndParseTwtxtFile(url = "") {
}
});
}
globalThis.Buffer = Buffer$1;
export {
base32Encode,
hashTwt,

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/
var er = Object.defineProperty, nr = Object.defineProperties;
var ir = Object.getOwnPropertyDescriptors;
var _t = Object.getOwnPropertySymbols;
@@ -1847,9 +1853,7 @@ function br() {
})(kt)), kt;
}
var Br = br();
const Er = /* @__PURE__ */ Mt(Br), Ir = (f) => new Er.Encoder({ type: "rfc4648" }).write(f).finalize(), $r = (f) => Array.isArray(f) && f.length ? f[0] : f;
globalThis.Buffer = yr;
const Fr = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/, Ur = (f) => {
const Er = /* @__PURE__ */ Mt(Br), Ir = (f) => new Er.Encoder({ type: "rfc4648" }).write(f).finalize(), $r = (f) => Array.isArray(f) && f.length ? f[0] : f, Fr = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/, Ur = (f) => {
const l = (p = 0) => `${+p < 10 ? 0 : ""}${+p}`, x = (p = 0) => `${+p < 1e3 ? 0 : ""}${+p < 100 ? 0 : ""}${+p < 10 ? 0 : ""}${+p}`;
let d = Fr.exec(f);
d && (d == null ? void 0 : d[9]) === void 0 && (d[9] = "+00"), d && (d == null ? void 0 : d[10]) === void 0 && (d[10] = "00");
@@ -2308,6 +2312,7 @@ function te(f = "") {
}
});
}
globalThis.Buffer = yr;
export {
Ir as base32Encode,
Ar as hashTwt,

File diff suppressed because one or more lines are too long

View File

@@ -318,9 +318,10 @@
</ul>
<script src="/dist-browser/twtxt-lib.js" type="module"></script>
<script src="/demo/theme-toggle.js" type="module"></script>
<script src="/demo/external-links.js" type="module"></script>
<script src="/demo/add-default-route.js" type="module"></script>
<script src="/demo/browser-detection.js" type="module"></script>
<script src="/demo/external-links.js" type="module"></script>
<script src="/demo/theme-toggle.js" type="module"></script>
<script src="/demo/overview-example-source.js" type="module"></script>
<script src="/demo/overview-example-result.js" type="module"></script>
<script src="/demo/hashTwt-example-source.js" type="module"></script>

5
dist-node/browser.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export type * from './types.ts';
export { default as hashTwt } from './hashTwt.ts';
export { default as loadAndParseTwtxtFile } from './loadAndParseTwtxt.ts';
export { default as parseTwtxt } from './parseTwtxt.ts';
export { base32Encode } from './utils.ts';

View File

@@ -1,7 +1,5 @@
import { Buffer } from "vite-plugin-node-polyfills/shims/buffer";
import { blake2b } from "@exodus/blakejs";
import { base32Encode } from "./utils.js";
globalThis.Buffer = Buffer;
const dateRegex = /^(\d{4})-(\d{2})-(\d{2})([tT ])(\d{2}):(\d{2}):(\d{2})\.?(\d{3})?(?:(?:([+-]\d{2}):?(\d{2}))|Z)?$/;
const formatRFC3339 = (date) => {
const pad = (num = 0) => `${+num < 10 ? 0 : ""}${+num}`;

View File

@@ -1 +1 @@
{"version":3,"file":"hashTwt.js","sources":["../src/hashTwt.ts"],"sourcesContent":["import { Buffer } from \"buffer\";\nglobalThis.Buffer = Buffer;\n\nimport type { Twt } from \"./types.ts\";\n\nimport { blake2b } from \"@exodus/blakejs\";\n\nimport { base32Encode } from \"./utils.ts\";\n\nconst dateRegex =\n\t/^(\\d{4})-(\\d{2})-(\\d{2})([tT ])(\\d{2}):(\\d{2}):(\\d{2})\\.?(\\d{3})?(?:(?:([+-]\\d{2}):?(\\d{2}))|Z)?$/;\n\nconst formatRFC3339 = (date: string) => {\n\tconst pad = (num: number | string = 0) => `${+num < 10 ? 0 : \"\"}${+num}`;\n\tconst padYear = (num: number | string = 0) =>\n\t\t`${+num < 1000 ? 0 : \"\"}${+num < 100 ? 0 : \"\"}${\n\t\t\t+num < 10 ? 0 : \"\"\n\t\t}${+num}`;\n\n\tlet m = dateRegex.exec(date);\n\n\t//if timezone is undefined, it must be Z or nothing (otherwise the group would have captured).\n\tif (m && m?.[9] === undefined) {\n\t\t//Use UTC.\n\t\tm[9] = \"+00\";\n\t}\n\tif (m && m?.[10] === undefined) {\n\t\tm[10] = \"00\";\n\t}\n\n\tconst offset = `${m?.[9]}:${m?.[10]}`.replace(/[+-]?00:00$/, \"Z\");\n\n\treturn [\n\t\tpadYear(m?.[1]),\n\t\t\"-\",\n\t\tpad(m?.[2]),\n\t\t\"-\",\n\t\tpad(m?.[3]),\n\t\tm?.[4],\n\t\tpad(m?.[5]),\n\t\t\":\",\n\t\tpad(m?.[6]),\n\t\t\":\",\n\t\tpad(m?.[7]),\n\t\t//ignore milliseconds (m[8])\n\t\toffset,\n\t].join(\"\");\n};\n\nexport default function hashTwt(twt: Twt): string {\n\tconst created = formatRFC3339(twt.created);\n\tconst payload = [twt.url, created, twt.content].join(\"\\n\");\n\n\treturn base32Encode(blake2b(payload, undefined, 32))\n\t\t.toLowerCase()\n\t\t.slice(-7);\n}\n"],"names":[],"mappings":";;;AACA,WAAW,SAAS;AAQpB,MAAM,YACL;AAED,MAAM,gBAAgB,CAAC,SAAiB;AACvC,QAAM,MAAM,CAAC,MAAuB,MAAM,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,GAAG,CAAC,GAAG;AACtE,QAAM,UAAU,CAAC,MAAuB,MACvC,GAAG,CAAC,MAAM,MAAO,IAAI,EAAE,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,GAC5C,CAAC,MAAM,KAAK,IAAI,EACjB,GAAG,CAAC,GAAG;AAER,MAAI,IAAI,UAAU,KAAK,IAAI;AAG3B,MAAI,KAAK,IAAI,CAAC,MAAM,QAAW;AAE9B,MAAE,CAAC,IAAI;AAAA,EACR;AACA,MAAI,KAAK,IAAI,EAAE,MAAM,QAAW;AAC/B,MAAE,EAAE,IAAI;AAAA,EACT;AAEA,QAAM,SAAS,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,QAAQ,eAAe,GAAG;AAEhE,SAAO;AAAA,IACN,QAAQ,IAAI,CAAC,CAAC;AAAA,IACd;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV,IAAI,CAAC;AAAA,IACL,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA;AAAA,IAEV;AAAA,EAAA,EACC,KAAK,EAAE;AACV;AAEA,SAAwB,QAAQ,KAAkB;AACjD,QAAM,UAAU,cAAc,IAAI,OAAO;AACzC,QAAM,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,IAAI;AAEzD,SAAO,aAAa,QAAQ,SAAS,QAAW,EAAE,CAAC,EACjD,YAAA,EACA,MAAM,EAAE;AACX;"}
{"version":3,"file":"hashTwt.js","sources":["../src/hashTwt.ts"],"sourcesContent":["import type { Twt } from \"./types.ts\";\n\nimport { blake2b } from \"@exodus/blakejs\";\n\nimport { base32Encode } from \"./utils.ts\";\n\nconst dateRegex =\n\t/^(\\d{4})-(\\d{2})-(\\d{2})([tT ])(\\d{2}):(\\d{2}):(\\d{2})\\.?(\\d{3})?(?:(?:([+-]\\d{2}):?(\\d{2}))|Z)?$/;\n\nconst formatRFC3339 = (date: string) => {\n\tconst pad = (num: number | string = 0) => `${+num < 10 ? 0 : \"\"}${+num}`;\n\tconst padYear = (num: number | string = 0) =>\n\t\t`${+num < 1000 ? 0 : \"\"}${+num < 100 ? 0 : \"\"}${\n\t\t\t+num < 10 ? 0 : \"\"\n\t\t}${+num}`;\n\n\tlet m = dateRegex.exec(date);\n\n\t//if timezone is undefined, it must be Z or nothing (otherwise the group would have captured).\n\tif (m && m?.[9] === undefined) {\n\t\t//Use UTC.\n\t\tm[9] = \"+00\";\n\t}\n\tif (m && m?.[10] === undefined) {\n\t\tm[10] = \"00\";\n\t}\n\n\tconst offset = `${m?.[9]}:${m?.[10]}`.replace(/[+-]?00:00$/, \"Z\");\n\n\treturn [\n\t\tpadYear(m?.[1]),\n\t\t\"-\",\n\t\tpad(m?.[2]),\n\t\t\"-\",\n\t\tpad(m?.[3]),\n\t\tm?.[4],\n\t\tpad(m?.[5]),\n\t\t\":\",\n\t\tpad(m?.[6]),\n\t\t\":\",\n\t\tpad(m?.[7]),\n\t\t//ignore milliseconds (m[8])\n\t\toffset,\n\t].join(\"\");\n};\n\nexport default function hashTwt(twt: Twt): string {\n\tconst created = formatRFC3339(twt.created);\n\tconst payload = [twt.url, created, twt.content].join(\"\\n\");\n\n\treturn base32Encode(blake2b(payload, undefined, 32))\n\t\t.toLowerCase()\n\t\t.slice(-7);\n}\n"],"names":[],"mappings":";;AAMA,MAAM,YACL;AAED,MAAM,gBAAgB,CAAC,SAAiB;AACvC,QAAM,MAAM,CAAC,MAAuB,MAAM,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,GAAG,CAAC,GAAG;AACtE,QAAM,UAAU,CAAC,MAAuB,MACvC,GAAG,CAAC,MAAM,MAAO,IAAI,EAAE,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,GAC5C,CAAC,MAAM,KAAK,IAAI,EACjB,GAAG,CAAC,GAAG;AAER,MAAI,IAAI,UAAU,KAAK,IAAI;AAG3B,MAAI,KAAK,IAAI,CAAC,MAAM,QAAW;AAE9B,MAAE,CAAC,IAAI;AAAA,EACR;AACA,MAAI,KAAK,IAAI,EAAE,MAAM,QAAW;AAC/B,MAAE,EAAE,IAAI;AAAA,EACT;AAEA,QAAM,SAAS,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,QAAQ,eAAe,GAAG;AAEhE,SAAO;AAAA,IACN,QAAQ,IAAI,CAAC,CAAC;AAAA,IACd;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV,IAAI,CAAC;AAAA,IACL,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA,IACV;AAAA,IACA,IAAI,IAAI,CAAC,CAAC;AAAA;AAAA,IAEV;AAAA,EAAA,EACC,KAAK,EAAE;AACV;AAEA,SAAwB,QAAQ,KAAkB;AACjD,QAAM,UAAU,cAAc,IAAI,OAAO;AACzC,QAAM,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,IAAI;AAEzD,SAAO,aAAa,QAAQ,SAAS,QAAW,EAAE,CAAC,EACjD,YAAA,EACA,MAAM,EAAE;AACX;"}

View File

@@ -1,4 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
/*
* twtxt-lib
* https://twtxt-lib.itsericwoodward.com/
* Copyright (c) 2026 Eric Woodward
* Released under the MIT License
*/
import { default as default2 } from "./hashTwt.js";
import { default as default3 } from "./loadAndParseTwtxt.js";
import { default as default4 } from "./parseTwtxt.js";

View File

@@ -318,9 +318,10 @@
</ul>
<script src="/dist-browser/twtxt-lib.js" type="module"></script>
<script src="/demo/theme-toggle.js" type="module"></script>
<script src="/demo/external-links.js" type="module"></script>
<script src="/demo/add-default-route.js" type="module"></script>
<script src="/demo/browser-detection.js" type="module"></script>
<script src="/demo/external-links.js" type="module"></script>
<script src="/demo/theme-toggle.js" type="module"></script>
<script src="/demo/overview-example-source.js" type="module"></script>
<script src="/demo/overview-example-result.js" type="module"></script>
<script src="/demo/hashTwt-example-source.js" type="module"></script>

View File

@@ -1,6 +1,5 @@
{
"name": "@itsericwoodward/twtxt-lib",
"version": "0.9.1",
"license": "MIT",
"exports": "./src/index.ts"
}

View File

@@ -1,6 +1,6 @@
{
"name": "twtxt-lib",
"version": "0.9.1",
"version": "0.9.3",
"description": "An isomorphic TypeScript library of utility functions for parsing and interacting with twtxt.txt files.",
"license": "MIT",
"author": {
@@ -33,6 +33,9 @@
"preview": "vite preview",
"prepublishOnly": "yarn build",
"postpublish": "git push && git push --tags",
"publish": "npm publish && npx jsr publish",
"publish:jsr": "npx jsr publish",
"publish:npm": "npm publish",
"test": "vitest"
},
"dependencies": {
@@ -41,7 +44,7 @@
"dayjs": "^1.11.19"
},
"devDependencies": {
"@types/node": "^25.3.0",
"@types/node": "^25.3.5",
"prettier": "^3.8.1",
"typescript": "^5.9.3",
"unplugin-dts": "1.0.0-beta.6",
@@ -50,5 +53,5 @@
"vite-plugin-node-polyfills": "^0.25.0",
"vitest": "^4.0.18"
},
"packageManager": "yarn@4.12.0"
"packageManager": "yarn@4.13.0"
}

View File

@@ -1,6 +1,10 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
// add default #overview route
if (!window.location.hash) {
window.location.hash = "overview";
}
});
// @license-end

View File

@@ -0,0 +1,7 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
const isGecko = !!navigator.userAgent.match(/gecko/i);
if (isGecko) document.body.classList.add("isGecko");
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
const currentHost = window.location.hostname;
@@ -10,3 +12,5 @@ document.addEventListener("DOMContentLoaded", () => {
}
});
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
export default function formatSource(source, panelId) {
source = (source ?? "").trim();
@@ -42,3 +44,5 @@ export default function formatSource(source, panelId) {
.getElementById(panelId)
.insertAdjacentHTML("beforeend", sourceHTML);
}
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { hashTwt } from "/dist-browser/twtxt-lib.js";
let wasHashTwtResultAppended = false;
@@ -61,3 +63,5 @@ formHash.addEventListener("submit", (e) => {
document.body.classList.add("isLoaded");
wasHashTwtResultAppended = true;
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -38,3 +40,5 @@ formatSource(
`,
"tabHashTwt-panel",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
const tabLoadAndParsePanel = document.getElementById("tabLoadAndParse-panel");
@@ -77,3 +79,5 @@ const loadAndParseClickHandler = (ev) => {
.getElementById(curr)
.addEventListener("click", loadAndParseClickHandler);
});
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -23,3 +25,5 @@ formatSource(
`,
"tabLoadAndParse-panel",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
// run in an IIFE (or event listener) to avoid issues with top-level await
@@ -34,3 +36,5 @@ import { loadAndParseTwtxtFile } from "/dist-browser/twtxt-lib.js";
console.error(err);
}
})();
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -22,3 +24,5 @@ formatSource(
`,
"tabOverview-example",
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import { parseTwtxt } from "/dist-browser/twtxt-lib.js";
const tabParsePanel = document.getElementById("tabParse-panel");
@@ -74,3 +76,5 @@ const parseClickHandler = (ev) => {
.addEventListener("click", parseClickHandler);
},
);
// @license-end

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
import formatSource from "./format-source.js";
formatSource(
@@ -25,3 +27,5 @@ formatSource(
`,
"tabParse-panel",
);
// @license-end

View File

@@ -365,24 +365,37 @@ body:not(:has(:target)) #tabOverview-link {
margin-top: -4.55rem;
}
.tab:target .tab-panel {
position: absolute;
z-index: 1;
}
body:not(:has(:target)) #tabOverview-panel {
display: block;
position: absolute;
z-index: 1;
}
.themeToggle-button {
bottom: auto;
position: absolute;
right: 1rem;
top: 1rem;
}
body:not(:has(:target)) #tabOverview-panel {
display: block;
position: absolute;
z-index: 1;
}
body.isGecko .tab-link {
margin-top: -4.65rem;
}
body.isGecko .tab-link:hover {
margin-top: -4.9rem;
}
body.isGecko .tab:target .tab-link,
body.isGecko .tab:target .tab-link:hover {
margin-top: -4.85rem;
}
}
/** State-Based Overrides */

View File

@@ -1,3 +1,5 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
document.addEventListener("DOMContentLoaded", () => {
const toggle = document.createElement("button");
@@ -27,3 +29,5 @@ document.addEventListener("DOMContentLoaded", () => {
document.body.appendChild(toggle);
});
// @license-end

9
src/browser.ts Normal file
View File

@@ -0,0 +1,9 @@
export type * from "./types.ts";
import { Buffer } from "buffer";
globalThis.Buffer = Buffer;
export { default as hashTwt } from "./hashTwt.ts";
export { default as loadAndParseTwtxtFile } from "./loadAndParseTwtxt.ts";
export { default as parseTwtxt } from "./parseTwtxt.ts";
export { base32Encode } from "./utils.ts";

View File

@@ -1,6 +1,3 @@
import { Buffer } from "buffer";
globalThis.Buffer = Buffer;
import type { Twt } from "./types.ts";
import { blake2b } from "@exodus/blakejs";

View File

@@ -6,16 +6,15 @@ import { nodePolyfills } from "vite-plugin-node-polyfills";
const __dirname = dirname(fileURLToPath(import.meta.url));
/* Only used for development, does not affect build */
export default defineConfig({
plugins: [
dts({ exclude: ["**/__tests__/*.*"] }),
nodePolyfills({
// Specify which polyfills to include (optional, but recommended for bundle size)
include: ["buffer"], // Only polyfill 'buffer' (add others like 'process' if needed)
// Configure global variables (e.g., expose Buffer to window)
include: ["buffer"],
globals: {
Buffer: true, // Expose Buffer as a global variable (optional but useful for some cases)
Buffer: true,
},
}),
],

View File

@@ -529,12 +529,12 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:^25.3.0":
version: 25.3.0
resolution: "@types/node@npm:25.3.0"
"@types/node@npm:^25.3.5":
version: 25.3.5
resolution: "@types/node@npm:25.3.5"
dependencies:
undici-types: "npm:~7.18.0"
checksum: 10c0/7b2b18c9d68047157367fc2f786d4f166d22dc0ad9f82331ca02fb16f2f391854123dbe604dcb938cda119c87051e4bb71dcb9ece44a579f483a6f96d4bd41de
checksum: 10c0/4cf0834a6f6933bf0aca6afead117ae3db3b8f02a5f7187a24f871db0fb9344e5e46573ba387bc53b7505e1e219c4c535cbe67221ced95bb5ad98573223b19d0
languageName: node
linkType: hard
@@ -2909,7 +2909,7 @@ __metadata:
resolution: "twtxt-lib@workspace:."
dependencies:
"@exodus/blakejs": "npm:^1.1.1-exodus.0"
"@types/node": "npm:^25.3.0"
"@types/node": "npm:^25.3.5"
base32.js: "npm:^0.1.0"
dayjs: "npm:^1.11.19"
prettier: "npm:^3.8.1"