Fix tabbing

This commit is contained in:
Dominic Ferrando
2026-06-14 13:14:01 -04:00
parent 42f47c8601
commit 05dc26adb5
31 changed files with 9137 additions and 8508 deletions
+4 -1
View File
@@ -2,4 +2,7 @@
// //
// For a full list of overridable settings, and general information on folder-specific settings, // For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files // see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{} {
"tab_size": 4,
"hard_tabs": false
}
+12 -12
View File
@@ -1,14 +1,14 @@
{ {
"name": "@blade-and-brawn/api", "name": "@blade-and-brawn/api",
"module": "index.ts", "module": "index.ts",
"type": "module", "type": "module",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@elysiajs/cors": "^1.4.1", "@elysiajs/cors": "^1.4.2",
"elysia": "^1.4.27", "elysia": "^1.4.28",
"zipcodes-us": "^1.1.2", "zipcodes-us": "^1.1.3",
"@blade-and-brawn/calculator": "workspace:*", "@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*", "@blade-and-brawn/commerce": "workspace:*",
"ml-levenberg-marquardt": "^5.0.0" "ml-levenberg-marquardt": "^5.0.1"
} }
} }
+186 -173
View File
@@ -1,195 +1,208 @@
import { import {
DEFAULT_STANDARDS_DATA, DEFAULT_STANDARDS_DATA,
LevelCalculator, LevelCalculator,
Standards, Standards,
type ActivityPerformance, type ActivityPerformance,
type Player, type Player,
} from "@blade-and-brawn/calculator"; } from "@blade-and-brawn/calculator";
import { cors } from "@elysiajs/cors"; import { cors } from "@elysiajs/cors";
import { Elysia, NotFoundError } from "elysia"; import { Elysia, NotFoundError } from "elysia";
import { PrintfulService, SyncService, WebflowService, Printful, Webflow, FetchError } from "@blade-and-brawn/commerce"; import {
PrintfulService,
SyncService,
WebflowService,
Printful,
Webflow,
FetchError,
} from "@blade-and-brawn/commerce";
import zipcodesUs from "zipcodes-us"; import zipcodesUs from "zipcodes-us";
const levelCalculator = new LevelCalculator(new Standards(DEFAULT_STANDARDS_DATA)); const levelCalculator = new LevelCalculator(
new Standards(DEFAULT_STANDARDS_DATA),
);
export const app = new Elysia() export const app = new Elysia()
.use( .use(
cors({ cors({
origin: [ origin: [
// bladeandbrawn.com (apex + any subdomain) // bladeandbrawn.com (apex + any subdomain)
/^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.com$/i, /^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.com$/i,
// Webflow preview domains // Webflow preview domains
/^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.webflow\.io$/i, /^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.webflow\.io$/i,
// Fly app host (this one already works) // Fly app host (this one already works)
/^https?:\/\/blade-and-brawn\.fly\.dev$/i, /^https?:\/\/blade-and-brawn\.fly\.dev$/i,
// Local dev portal // Local dev portal
"http://localhost:5173", "http://localhost:5173",
], ],
}), }),
) )
.error({ .error({
FetchError, FetchError,
}) })
.onError(async ({ code, error }) => { .onError(async ({ code, error }) => {
switch (code) { switch (code) {
case "FetchError": case "FetchError":
console.error(error.message, await error.parse()); console.error(error.message, await error.parse());
return error; return error;
}
})
.onAfterHandle(({ request, set }) => {
console.log(
JSON.stringify({
lvl: "info",
msg: "req",
method: request.method,
path: new URL(request.url).pathname,
status: set.status ?? 200,
}),
);
})
.get("/", () => "Hello world")
// CALCULATOR
.post("/calculate", async ({ body, query }) => {
interface CalcRequest {
player: Player;
activityPerformances: ActivityPerformance[];
}
const { player, activityPerformances } = body as CalcRequest;
const output = {
levels: levelCalculator.calculate(player, activityPerformances),
};
// console.log({ log: query?.log });
// if (query?.log === "true") {
// void fetch("https://kv-logger.xominus.workers.dev", {
// method: "POST",
// headers: { "content-type": "application/json" },
// body: JSON.stringify({ output, player, activityPerformances }),
// }).catch(() => {});
// }
return output;
})
// COMMERCE
// TODO: protect with api key/token
.group("/products", (app) =>
app
.group("/sync", (app) =>
app
.get("/", async ({ }) => SyncService.state)
.post("/:printfulProductId?", async ({ params, set }) => {
if (SyncService.state.isSyncing) {
set.status = 409;
return { error: "Sync already in progress" };
}
const printfulProductId = params.printfulProductId
? +params.printfulProductId
: undefined;
await SyncService.sync(printfulProductId);
return { ok: true };
}),
)
.get("/:printfulProductId", async ({ params }) => {
const printfulProductId = +params.printfulProductId;
const printfulProduct =
await PrintfulService.Products.get(printfulProductId);
if (!printfulProduct) {
return new NotFoundError();
} }
})
const webflowProductId = .onAfterHandle(({ request, set }) => {
printfulProduct.sync_product.external_id.split("-")[0]; console.log(
if (!webflowProductId) { JSON.stringify({
return new NotFoundError(); lvl: "info",
} msg: "req",
method: request.method,
const webflowProduct = path: new URL(request.url).pathname,
await WebflowService.Products.get(webflowProductId); status: set.status ?? 200,
}),
return { printfulProduct, webflowProduct };
}),
)
// WEBHOOKS
.post("/webhook/printful", async ({ body }) => {
const payload = body as Printful.Webhook.EventPayload;
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const printfulProduct = payload.data.sync_product;
await SyncService.sync(printfulProduct.id);
break;
}
case Printful.Webhook.Event.ProductDeleted: {
await WebflowService.Products.remove(
payload.data.sync_product.external_id,
); );
break; })
}
case Printful.Webhook.Event.PackageShipped: {
const webflowOrderId = payload.data.order.external_id;
const shipInfo = payload.data.shipment;
await WebflowService.Orders.update(webflowOrderId, { .get("/", () => "Hello world")
shippingTrackingURL: shipInfo.tracking_url,
shippingTracking: shipInfo.tracking_number,
shippingProvider: shipInfo.carrier,
});
await WebflowService.Orders.fulfill(webflowOrderId, {
sendOrderFulfilledEmail: true,
});
break;
}
}
return { ok: true }; // CALCULATOR
})
.post("/webhook/webflow", async ({ request, body, set }) => {
if (!WebflowService.Util.verifyWebflowSignature(request, body)) {
set.status = 400;
return "Invalid signature";
}
const payload = body as Webflow.Webhook.EventPayload; .post("/calculate", async ({ body, query }) => {
interface CalcRequest {
player: Player;
activityPerformances: ActivityPerformance[];
}
const { player, activityPerformances } = body as CalcRequest;
const output = {
levels: levelCalculator.calculate(player, activityPerformances),
};
switch (payload.triggerType) { // console.log({ log: query?.log });
case Webflow.Webhook.Event.OrderCreated: { // if (query?.log === "true") {
const webflowOrder = payload.payload; // void fetch("https://kv-logger.xominus.workers.dev", {
// method: "POST",
// headers: { "content-type": "application/json" },
// body: JSON.stringify({ output, player, activityPerformances }),
// }).catch(() => {});
// }
await PrintfulService.Orders.create({ return output;
external_id: webflowOrder.orderId, })
// TODO: derive from webflow
shipping: "STANDARD",
recipient: {
name: webflowOrder.shippingAddress.addressee,
address1: webflowOrder.shippingAddress.line1,
address2: webflowOrder.shippingAddress.line2,
city: webflowOrder.shippingAddress.city,
state_code: zipcodesUs.find(
webflowOrder.shippingAddress.postalCode.split("-")[0] ?? "",
).stateCode,
country_code: webflowOrder.shippingAddress.country,
zip: webflowOrder.shippingAddress.postalCode,
},
items: webflowOrder.purchasedItems.map((webflowOrderSku) => ({
external_variant_id: webflowOrderSku.variantId,
quantity: webflowOrderSku.count,
})),
});
break; // COMMERCE
} // TODO: protect with api key/token
} .group("/products", (app) =>
app
.group("/sync", (app) =>
app
.get("/", async ({}) => SyncService.state)
.post("/:printfulProductId?", async ({ params, set }) => {
if (SyncService.state.isSyncing) {
set.status = 409;
return { error: "Sync already in progress" };
}
const printfulProductId = params.printfulProductId
? +params.printfulProductId
: undefined;
await SyncService.sync(printfulProductId);
return { ok: true };
}),
)
.get("/:printfulProductId", async ({ params }) => {
const printfulProductId = +params.printfulProductId;
const printfulProduct =
await PrintfulService.Products.get(printfulProductId);
if (!printfulProduct) {
return new NotFoundError();
}
return { ok: true }; const webflowProductId =
}); printfulProduct.sync_product.external_id.split("-")[0];
if (!webflowProductId) {
return new NotFoundError();
}
const webflowProduct =
await WebflowService.Products.get(webflowProductId);
return { printfulProduct, webflowProduct };
}),
)
// WEBHOOKS
.post("/webhook/printful", async ({ body }) => {
const payload = body as Printful.Webhook.EventPayload;
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const printfulProduct = payload.data.sync_product;
await SyncService.sync(printfulProduct.id);
break;
}
case Printful.Webhook.Event.ProductDeleted: {
await WebflowService.Products.remove(
payload.data.sync_product.external_id,
);
break;
}
case Printful.Webhook.Event.PackageShipped: {
const webflowOrderId = payload.data.order.external_id;
const shipInfo = payload.data.shipment;
await WebflowService.Orders.update(webflowOrderId, {
shippingTrackingURL: shipInfo.tracking_url,
shippingTracking: shipInfo.tracking_number,
shippingProvider: shipInfo.carrier,
});
await WebflowService.Orders.fulfill(webflowOrderId, {
sendOrderFulfilledEmail: true,
});
break;
}
}
return { ok: true };
})
.post("/webhook/webflow", async ({ request, body, set }) => {
if (!WebflowService.Util.verifyWebflowSignature(request, body)) {
set.status = 400;
return "Invalid signature";
}
const payload = body as Webflow.Webhook.EventPayload;
switch (payload.triggerType) {
case Webflow.Webhook.Event.OrderCreated: {
const webflowOrder = payload.payload;
await PrintfulService.Orders.create({
external_id: webflowOrder.orderId,
// TODO: derive from webflow
shipping: "STANDARD",
recipient: {
name: webflowOrder.shippingAddress.addressee,
address1: webflowOrder.shippingAddress.line1,
address2: webflowOrder.shippingAddress.line2,
city: webflowOrder.shippingAddress.city,
state_code: zipcodesUs.find(
webflowOrder.shippingAddress.postalCode.split(
"-",
)[0] ?? "",
).stateCode,
country_code: webflowOrder.shippingAddress.country,
zip: webflowOrder.shippingAddress.postalCode,
},
items: webflowOrder.purchasedItems.map(
(webflowOrderSku) => ({
external_variant_id: webflowOrderSku.variantId,
quantity: webflowOrderSku.count,
}),
),
});
break;
}
}
return { ok: true };
});
app.listen(3000); app.listen(3000);
+78 -78
View File
@@ -1,87 +1,87 @@
import { import {
type Levels, type Levels,
DEFAULT_STANDARDS_DATA, DEFAULT_STANDARDS_DATA,
} from "@blade-and-brawn/calculator"; } from "@blade-and-brawn/calculator";
import { Activity, clamp, Gender, range } from "@blade-and-brawn/calculator"; import { Activity, clamp, Gender, range } from "@blade-and-brawn/calculator";
import { levenbergMarquardt as LM } from "ml-levenberg-marquardt"; import { levenbergMarquardt as LM } from "ml-levenberg-marquardt";
for (const activity of Object.values(Activity)) { for (const activity of Object.values(Activity)) {
const DATASET_MAX_LEVEL = 5; const DATASET_MAX_LEVEL = 5;
const NEW_LEVEL_COUNT = 2; const NEW_LEVEL_COUNT = 2;
const RATIO_CLAMP = 1.4; const RATIO_CLAMP = 1.4;
function expDecayModel([A, B, C]: number[]) { function expDecayModel([A, B, C]: number[]) {
return (i: number) => A! * Math.exp(-B! * i) + C!; return (i: number) => A! * Math.exp(-B! * i) + C!;
} }
for (const gender of Object.values(Gender)) { for (const gender of Object.values(Gender)) {
const standardsByGender = DEFAULT_STANDARDS_DATA[activity].standards.filter( const standardsByGender = DEFAULT_STANDARDS_DATA[
(s) => s["metrics"].gender === gender, activity
); ].standards.filter((s) => s["metrics"].gender === gender);
const ages = [...new Set(standardsByGender.map((s) => s.metrics.age))]; const ages = [...new Set(standardsByGender.map((s) => s.metrics.age))];
for (const age of ages) { for (const age of ages) {
const standards = standardsByGender.filter( const standards = standardsByGender.filter(
(s) => s.metrics.age === age, (s) => s.metrics.age === age,
); );
const data = { const data = {
x: [] as number[], x: [] as number[],
y: [] as number[], y: [] as number[],
}; };
const isIncreasing = const isIncreasing =
standards[0]!.levels["2"]! > standards[0]!.levels["1"]!; standards[0]!.levels["2"]! > standards[0]!.levels["1"]!;
for (const i of range(DATASET_MAX_LEVEL).slice(0, -1)) { for (const i of range(DATASET_MAX_LEVEL).slice(0, -1)) {
const level = i + 1; const level = i + 1;
const progressionRatios: number[] = []; const progressionRatios: number[] = [];
for (const standard of standards) { for (const standard of standards) {
const curr = standard.levels[level]!; const curr = standard.levels[level]!;
const next = standard.levels[level]!; const next = standard.levels[level]!;
progressionRatios.push( progressionRatios.push(
isIncreasing ? next / curr : curr / next, isIncreasing ? next / curr : curr / next,
); );
} }
const sum = progressionRatios.reduce((p, c) => p + c, 0); const sum = progressionRatios.reduce((p, c) => p + c, 0);
const progressionRatioAvg = sum / progressionRatios.length; const progressionRatioAvg = sum / progressionRatios.length;
data.x.push(i); data.x.push(i);
data.y.push(progressionRatioAvg); data.y.push(progressionRatioAvg);
} }
const fittedParams = LM(data, expDecayModel, { const fittedParams = LM(data, expDecayModel, {
initialValues: [0.4, 0.5, 1.1], initialValues: [0.4, 0.5, 1.1],
minValues: [0.0, 0.0, 1.02], minValues: [0.0, 0.0, 1.02],
maxValues: [1.0, 2.0, 1.25], maxValues: [1.0, 2.0, 1.25],
maxIterations: 200, maxIterations: 200,
}); });
const getDecayRatio = (i: number) => const getDecayRatio = (i: number) =>
clamp( clamp(
expDecayModel(fittedParams.parameterValues)(i), expDecayModel(fittedParams.parameterValues)(i),
1, 1,
RATIO_CLAMP, RATIO_CLAMP,
); );
// UPDATE THE DATA // UPDATE THE DATA
for (const standard of standards) { for (const standard of standards) {
const newLevels: Levels = {}; const newLevels: Levels = {};
let prev = standard.levels["1"]!; let prev = standard.levels["1"]!;
for (const i of range(NEW_LEVEL_COUNT)) { for (const i of range(NEW_LEVEL_COUNT)) {
const level = i + 1; const level = i + 1;
const ratio = getDecayRatio(level - NEW_LEVEL_COUNT); const ratio = getDecayRatio(level - NEW_LEVEL_COUNT);
prev = isIncreasing ? prev / ratio : prev * ratio; prev = isIncreasing ? prev / ratio : prev * ratio;
newLevels[level] = Math.round(prev); newLevels[level] = Math.round(prev);
} }
const oldLevels = standard.levels as Levels; const oldLevels = standard.levels as Levels;
for (const i of range(DATASET_MAX_LEVEL)) { for (const i of range(DATASET_MAX_LEVEL)) {
const level = i + 1; const level = i + 1;
newLevels[level + NEW_LEVEL_COUNT] = oldLevels[level]!; newLevels[level + NEW_LEVEL_COUNT] = oldLevels[level]!;
} }
standard.levels = newLevels; standard.levels = newLevels;
} }
}
} }
}
} }
+57 -53
View File
@@ -1,75 +1,79 @@
import { PrintfulService, SyncService, WebflowService } from "@blade-and-brawn/commerce"; import {
PrintfulService,
SyncService,
WebflowService,
} from "@blade-and-brawn/commerce";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
type Validation = { type Validation = {
isValid: boolean; isValid: boolean;
message: string; message: string;
}; };
const validateEquality = (wValue: any, pValue: any): Validation => { const validateEquality = (wValue: any, pValue: any): Validation => {
const validation = { const validation = {
isValid: true, isValid: true,
message: "Valid", message: "Valid",
}; };
if (wValue !== pValue) { if (wValue !== pValue) {
validation.isValid = false; validation.isValid = false;
validation.message = `${wValue} !== ${pValue}`; validation.message = `${wValue} !== ${pValue}`;
} }
return validation; return validation;
}; };
const wProducts = await WebflowService.Products.getAll(); const wProducts = await WebflowService.Products.getAll();
let invalidCount = 0; let invalidCount = 0;
for (const wProduct of wProducts) { for (const wProduct of wProducts) {
for (const sku of wProduct.skus ?? []) { for (const sku of wProduct.skus ?? []) {
console.log("Webflow: " + sku.id, sku.fieldData.name); console.log("Webflow: " + sku.id, sku.fieldData.name);
const pVariant = await PrintfulService.Products.Variants.get( const pVariant = await PrintfulService.Products.Variants.get(
`@${sku.id}`, `@${sku.id}`,
); );
if (pVariant) { if (pVariant) {
console.log("Printful: " + pVariant.id, pVariant.name); console.log("Printful: " + pVariant.id, pVariant.name);
const validations = [ const validations = [
// validateEquality(sku.fieldData.name, pVariant.name), // validateEquality(sku.fieldData.name, pVariant.name),
validateEquality( validateEquality(
sku.fieldData["sku-values"]?.["color"], sku.fieldData["sku-values"]?.["color"],
SyncService.findColorInProductName(pVariant.name), SyncService.findColorInProductName(pVariant.name),
), ),
validateEquality( validateEquality(
sku.fieldData["sku-values"]?.["size"], sku.fieldData["sku-values"]?.["size"],
pVariant.size, pVariant.size,
), ),
validateEquality( validateEquality(
sku.fieldData.price.value, sku.fieldData.price.value,
Math.floor(+pVariant.retail_price * 100), Math.floor(+pVariant.retail_price * 100),
), ),
]; ];
// if (!validateEquality(sku.fieldData.name, pVariant.name).isValid) { // if (!validateEquality(sku.fieldData.name, pVariant.name).isValid) {
// sku.fieldData.name = pVariant.name; // sku.fieldData.name = pVariant.name;
// await WebflowService.Products.Skus.update(wProduct.product.id, sku.id, sku); // await WebflowService.Products.Skus.update(wProduct.product.id, sku.id, sku);
// } // }
const errors = validations.filter((v) => !v.isValid); const errors = validations.filter((v) => !v.isValid);
if (errors.length) { if (errors.length) {
++invalidCount; ++invalidCount;
console.log("INVALID: "); console.log("INVALID: ");
console.log(errors.map((e) => e.message).join(", ")); console.log(errors.map((e) => e.message).join(", "));
} else { } else {
console.log("VALID"); console.log("VALID");
} }
} else { } else {
++invalidCount; ++invalidCount;
console.log("INVALID"); console.log("INVALID");
console.log("Not found"); console.log("Not found");
}
console.log();
} }
console.log(); await sleep(3000);
}
await sleep(3000);
} }
console.log("INVALID COUNT: " + invalidCount); console.log("INVALID COUNT: " + invalidCount);
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json"
} }
+28 -28
View File
@@ -1,30 +1,30 @@
{ {
"name": "@blade-and-brawn/portal", "name": "@blade-and-brawn/portal",
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@sveltejs/kit": "^2.54.0", "@sveltejs/kit": "^2.65.1",
"@sveltejs/vite-plugin-svelte": "^6.2.4", "@sveltejs/vite-plugin-svelte": "^6.2.4",
"@types/bun": "^1.3.10", "@types/bun": "^1.3.14",
"svelte": "^5.53.10", "svelte": "^5.56.3",
"svelte-adapter-bun": "^0.5.2", "svelte-adapter-bun": "^0.5.2",
"svelte-check": "^4.4.5", "svelte-check": "^4.6.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^7.3.1" "vite": "^7.3.5"
}, },
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"prepare": "svelte-kit sync || echo ''", "prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.2.1", "@tailwindcss/vite": "^4.3.1",
"daisyui": "^5.5.19", "daisyui": "^5.5.23",
"memoirist": "^0.4.0", "memoirist": "^0.4.0",
"tailwindcss": "^4.2.1", "tailwindcss": "^4.3.1",
"@blade-and-brawn/calculator": "workspace:*", "@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*" "@blade-and-brawn/commerce": "workspace:*"
} }
} }
@@ -1,11 +1,11 @@
import { PrintfulService, WebflowService } from "@blade-and-brawn/commerce"; import { PrintfulService, WebflowService } from "@blade-and-brawn/commerce";
import type { PageServerLoad } from "./$types"; import type { PageServerLoad } from "./$types";
export const load = async ({ }: Parameters<PageServerLoad>[0]) => { export const load = async ({}: Parameters<PageServerLoad>[0]) => {
return { return {
products: { products: {
printful: PrintfulService.Products.getAll(), printful: PrintfulService.Products.getAll(),
webflow: WebflowService.Products.getAll(), webflow: WebflowService.Products.getAll(),
}, },
}; };
}; };
+2 -2
View File
@@ -10,6 +10,6 @@
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"moduleResolution": "bundler", "moduleResolution": "bundler"
}, }
} }
+68 -71
View File
@@ -1,13 +1,14 @@
{ {
"lockfileVersion": 1, "lockfileVersion": 1,
"configVersion": 0,
"workspaces": { "workspaces": {
"": { "": {
"name": "blade-and-brawn", "name": "blade-and-brawn",
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.9", "@types/bun": "^1.3.14",
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5", "typescript": "^5.9.3",
}, },
}, },
"apps/api": { "apps/api": {
@@ -15,10 +16,10 @@
"dependencies": { "dependencies": {
"@blade-and-brawn/calculator": "workspace:*", "@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*", "@blade-and-brawn/commerce": "workspace:*",
"@elysiajs/cors": "^1.4.1", "@elysiajs/cors": "^1.4.2",
"elysia": "^1.4.27", "elysia": "^1.4.28",
"ml-levenberg-marquardt": "^5.0.0", "ml-levenberg-marquardt": "^5.0.1",
"zipcodes-us": "^1.1.2", "zipcodes-us": "^1.1.3",
}, },
}, },
"apps/portal": { "apps/portal": {
@@ -32,12 +33,12 @@
"tailwindcss": "^4.2.1", "tailwindcss": "^4.2.1",
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/kit": "^2.53.4", "@sveltejs/kit": "^2.54.0",
"@sveltejs/vite-plugin-svelte": "^6.2.4", "@sveltejs/vite-plugin-svelte": "^6.2.4",
"@types/bun": "^1.3.9", "@types/bun": "^1.3.10",
"svelte": "^5.53.6", "svelte": "^5.53.10",
"svelte-adapter-bun": "^0.5.2", "svelte-adapter-bun": "^0.5.2",
"svelte-check": "^4.4.4", "svelte-check": "^4.4.5",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^7.3.1", "vite": "^7.3.1",
}, },
@@ -65,7 +66,7 @@
"@borewit/text-codec": ["@borewit/text-codec@0.2.1", "", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="], "@borewit/text-codec": ["@borewit/text-codec@0.2.1", "", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="],
"@elysiajs/cors": ["@elysiajs/cors@1.4.1", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-lQfad+F3r4mNwsxRKbXyJB8Jg43oAOXjRwn7sKUL6bcOW3KjUqUimTS+woNpO97efpzjtDE0tEjGk9DTw8lqTQ=="], "@elysiajs/cors": ["@elysiajs/cors@1.4.2", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-FTCcbH35brTLigF1W7BYySRZomgI/dBEMK9BgK9RP9Nez7zmpGh4koL/Yr1BFv8nYz7CfhRvcM8d/c+XnwMaVQ=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
@@ -185,49 +186,51 @@
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.9", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA=="], "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.10", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA=="],
"@sveltejs/kit": ["@sveltejs/kit@2.54.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.6.4", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-WDJApQ1ipZLbaC4YjqJjwYR9y7QQgTqVwEObgNZ8Mu/eVQJqn4Qzw9a+n7mr5xnBYiAYz9UdJOOl+aqVbfGXcA=="], "@sveltejs/kit": ["@sveltejs/kit@2.65.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.9", "@types/cookie": "^0.6.0", "acorn": "^8.16.0", "cookie": "^0.6.0", "devalue": "^5.8.1", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-Sa1rFYYqBB+zv3rIxAg/CsFskR/x4aj5BY/hvLxBd9r/mqbipxM945As1K3PqsDicJAyekPR0BlWoVIiw2OHYg=="],
"@sveltejs/load-config": ["@sveltejs/load-config@0.1.1", "", {}, "sha512-BXXm+VOH/9X4N7Dd1iZ2MqA1h7M+9i2noI8QYuLDY8QcN2WHYn7D/VK/+IJNfcAmRw7ACNJ538UT9GXIhnBTiA=="],
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.4", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", "magic-string": "^0.30.21", "obug": "^2.1.0", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA=="], "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.4", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", "magic-string": "^0.30.21", "obug": "^2.1.0", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA=="],
"@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.2", "", { "dependencies": { "obug": "^2.1.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig=="], "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.2", "", { "dependencies": { "obug": "^2.1.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig=="],
"@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="], "@tailwindcss/node": ["@tailwindcss/node@4.3.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.1" } }, "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.1", "@tailwindcss/oxide-darwin-arm64": "4.3.1", "@tailwindcss/oxide-darwin-x64": "4.3.1", "@tailwindcss/oxide-freebsd-x64": "4.3.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", "@tailwindcss/oxide-linux-x64-musl": "4.3.1", "@tailwindcss/oxide-wasm32-wasi": "4.3.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="], "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.1", "", { "os": "android", "cpu": "arm64" }, "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="], "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="], "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="], "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="], "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="], "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="], "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="], "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="], "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="], "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.1", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="], "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="], "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.2.1", "", { "dependencies": { "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "tailwindcss": "4.2.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w=="], "@tailwindcss/vite": ["@tailwindcss/vite@4.3.1", "", { "dependencies": { "@tailwindcss/node": "4.3.1", "@tailwindcss/oxide": "4.3.1", "tailwindcss": "4.3.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ=="],
"@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="],
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="], "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
@@ -243,7 +246,7 @@
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
@@ -251,7 +254,7 @@
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
"daisyui": ["daisyui@5.5.19", "", {}, "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA=="], "daisyui": ["daisyui@5.5.23", "", {}, "sha512-xuheNUSL4T6ZVtWXoioqcNkjoyGX85QTDz4HTw2aBPfqk4fuMjax5HDo8qCmpV6M1YN8bGvfx5BpYCoDeRlt+A=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
@@ -259,17 +262,17 @@
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"devalue": ["devalue@5.6.4", "", {}, "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA=="], "devalue": ["devalue@5.8.1", "", {}, "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="],
"elysia": ["elysia@1.4.27", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.7", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-2UlmNEjPJVA/WZVPYKy+KdsrfFwwNlqSBW1lHz6i2AHc75k7gV4Rhm01kFeotH7PDiHIX2G8X3KnRPc33SGVIg=="], "elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.7", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="],
"enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="], "enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="],
"esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
"esrap": ["esrap@2.2.3", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ=="], "esrap": ["esrap@2.2.11", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, "peerDependencies": { "@typescript-eslint/types": "^8.2.0" }, "optionalPeers": ["@typescript-eslint/types"] }, "sha512-gPdx+I+BjYEinNMQaBXFjbaJVyoPMU4ZODg5mE+M4DqVG9VusAVHHjcBX+zqyITlI0DIARwDMMzZwAWj36dRoQ=="],
"exact-mirror": ["exact-mirror@0.2.7", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg=="], "exact-mirror": ["exact-mirror@0.2.7", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg=="],
@@ -289,37 +292,37 @@
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"is-any-array": ["is-any-array@2.0.1", "", {}, "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ=="], "is-any-array": ["is-any-array@3.0.0", "", {}, "sha512-o4h+tylWykC4BD1vaejp6gDxoM13bwW8FGuNs4yIKpj8xbBJcRxJx8vZpq0dCr7ZDEfeKjmsi/euolKhX6f/ww=="],
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="], "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="], "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="], "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="], "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="], "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="], "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="], "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="], "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="], "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
@@ -327,15 +330,15 @@
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
"ml-array-max": ["ml-array-max@1.2.4", "", { "dependencies": { "is-any-array": "^2.0.0" } }, "sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ=="], "ml-array-max": ["ml-array-max@2.0.0", "", { "dependencies": { "is-any-array": "^3.0.0" } }, "sha512-QQZ4kENwpWmyNb98UXRDFXrmtIXuXtt1+bSbda/2KA85+F+rrJP8hZk6QOkCQXM2Th9mUDYdq/PNByPdT9ID4A=="],
"ml-array-min": ["ml-array-min@1.2.3", "", { "dependencies": { "is-any-array": "^2.0.0" } }, "sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q=="], "ml-array-min": ["ml-array-min@2.0.0", "", { "dependencies": { "is-any-array": "^3.0.0" } }, "sha512-GRj6Ky6sW9vGL6yIjgsHmXZ9YgrdmcQ8nCxPqEGeKc6dkfYg1XDYxGFxADUjNuZyoCd5PUscWAS4N+cFaX6hFg=="],
"ml-array-rescale": ["ml-array-rescale@1.3.7", "", { "dependencies": { "is-any-array": "^2.0.0", "ml-array-max": "^1.2.4", "ml-array-min": "^1.2.3" } }, "sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ=="], "ml-array-rescale": ["ml-array-rescale@2.0.0", "", { "dependencies": { "is-any-array": "^3.0.0", "ml-array-max": "^2.0.0", "ml-array-min": "^2.0.0" } }, "sha512-2GGtKfSno94/kIloWGvpp/U5Q5vLvLrza+SAaGsLeo6Xj4mEbA6Gqx+oTfZFkxnd1grT2X007HfJNs3T5BsiVg=="],
"ml-levenberg-marquardt": ["ml-levenberg-marquardt@5.0.0", "", { "dependencies": { "is-any-array": "^2.0.1", "ml-matrix": "^6.12.1" } }, "sha512-vCFoO2DyYKGZFp+KxofN2cAvSc/3gufJHj/oaDHA2nV+NZH509fD7m35zQR2ZXA8fepxpVrwgCAQ0aAIsV2WtA=="], "ml-levenberg-marquardt": ["ml-levenberg-marquardt@5.0.1", "", { "dependencies": { "is-any-array": "^3.0.0", "ml-matrix": "^6.12.2" } }, "sha512-sOaxcZ2aIBiRrPi3v7RmqSuNmjNKHURUB9Ft2Vcr8MWes152VF1DDkcZz3N8Nj/cWbFB359cNg/o7Z99vt58Iw=="],
"ml-matrix": ["ml-matrix@6.12.1", "", { "dependencies": { "is-any-array": "^2.0.1", "ml-array-rescale": "^1.3.7" } }, "sha512-TJ+8eOFdp+INvzR4zAuwBQJznDUfktMtOB6g/hUcGh3rcyjxbz4Te57Pgri8Q9bhSQ7Zys4IYOGhFdnlgeB6Lw=="], "ml-matrix": ["ml-matrix@6.12.2", "", { "dependencies": { "is-any-array": "^3.0.0", "ml-array-rescale": "^2.0.0" } }, "sha512-GC+BnW+pBh8Auap8goAxY0senAmF0IEoc3HNVSfnfbvGw0buuDIYb9kAKMS1l+GiwJ1rfK2bzJ8IHhwjzATSFA=="],
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
@@ -369,15 +372,15 @@
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
"svelte": ["svelte@5.53.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-UcNfWzbrjvYXYSk+U2hME25kpb87oq6/WVLeBF4khyQrb3Ob/URVlN23khal+RbdCUTMfg4qWjI9KZjCNFtYMQ=="], "svelte": ["svelte@5.56.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.10", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.8.1", "esm-env": "^1.2.1", "esrap": "^2.2.11", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-w7JvrM5IFl5cmfbY0TLik9o7mjRUJmRMhOR51tBPu708Gr/MjbGs7VnJnr/B0CaXeI4vtnOh7RKxDr0cwhMdDA=="],
"svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="], "svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="],
"svelte-check": ["svelte-check@4.4.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw=="], "svelte-check": ["svelte-check@4.6.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "@sveltejs/load-config": "0.1.1", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-KhVnDFDSid57mmZtHz8gfW8AAGylOZ0vPnOIzVmAL+urzwK8sBYXRss953gD8T0OdgAQ11mdWhE6uadmtOz8TQ=="],
"tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], "tailwindcss": ["tailwindcss@4.3.1", "", {}, "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="], "tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="],
@@ -393,32 +396,26 @@
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], "vite": ["vite@7.3.5", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww=="],
"vitefu": ["vitefu@1.1.2", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw=="], "vitefu": ["vitefu@1.1.2", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw=="],
"zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
"zipcodes-us": ["zipcodes-us@1.1.2", "", {}, "sha512-UmUTS0O0/IHb0hbxv5r6IfATvD2B7FKcJTLsSv/dENBRiNACFUrGmhPuVss3kAhuhEpPH6NwKHJ7/rGMNXq5yA=="], "zipcodes-us": ["zipcodes-us@1.1.3", "", {}, "sha512-gOz8WAO6iWBU4aUc0lljpa+TKZckRKmgoHKcc1jWnn4eTbdc9XO5cXEaGccYn7GAjykueO0Wn+N7zdmzG0Uf5w=="],
"@blade-and-brawn/portal/@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
"@sveltejs/kit/cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], "@sveltejs/kit/cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="],
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="],
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"svelte/devalue": ["devalue@5.6.3", "", {}, "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg=="],
"@blade-and-brawn/portal/@types/bun/bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="],
} }
} }
+19 -18
View File
@@ -6,7 +6,7 @@ function playAudio(newAudio) {
// HELPERS // HELPERS
// -------------- // --------------
const TIME_STEP = 500; const TIME_STEP = 500;
const VOL_STEP = .05; const VOL_STEP = 0.05;
function fadeOut(audio) { function fadeOut(audio) {
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
@@ -14,7 +14,7 @@ function playAudio(newAudio) {
if (audio.volume <= 0) { if (audio.volume <= 0) {
clearInterval(intervalId); clearInterval(intervalId);
} }
}, TIME_STEP) }, TIME_STEP);
} }
function fadeIn(audio) { function fadeIn(audio) {
@@ -25,7 +25,7 @@ function playAudio(newAudio) {
if (audio.volume >= 1) { if (audio.volume >= 1) {
clearInterval(intervalId); clearInterval(intervalId);
} }
}, TIME_STEP) }, TIME_STEP);
} }
// -------------- // --------------
@@ -35,8 +35,7 @@ function playAudio(newAudio) {
const prevAudio = currentAudio; const prevAudio = currentAudio;
if (prevAudio === newAudio) if (prevAudio === newAudio) return;
return;
if (prevAudio) { if (prevAudio) {
fadeOut(prevAudio); fadeOut(prevAudio);
@@ -48,7 +47,7 @@ function playAudio(newAudio) {
// -------------- // --------------
} }
document.addEventListener("DOMContentLoaded", async function() { document.addEventListener("DOMContentLoaded", async function () {
const $ = (id) => document.getElementById(id); const $ = (id) => document.getElementById(id);
const classNames = ["rogue", "knight", "warrior"]; const classNames = ["rogue", "knight", "warrior"];
@@ -64,26 +63,28 @@ document.addEventListener("DOMContentLoaded", async function() {
audios[className] = audio; audios[className] = audio;
} }
await Promise.all(classNames.map(async (className) => { await Promise.all(
const audio = audios[className]; classNames.map(async (className) => {
try { const audio = audios[className];
await audio.play(); try {
audio.pause(); await audio.play();
audio.currentTime = 0; audio.pause();
} catch (e) { audio.currentTime = 0;
console.warn(`Autoplay failed for ${className}:`, e); } catch (e) {
} console.warn(`Autoplay failed for ${className}:`, e);
})); }
}),
);
// Start all in perfect sync // Start all in perfect sync
classNames.forEach(className => { classNames.forEach((className) => {
const audio = audios[className]; const audio = audios[className];
audio.currentTime = 0; audio.currentTime = 0;
audio.play(); audio.play();
}); });
// Hook up buttons // Hook up buttons
classNames.forEach(className => { classNames.forEach((className) => {
$(`btn-${className}`).onclick = () => { $(`btn-${className}`).onclick = () => {
$("currentClass").textContent = className; $("currentClass").textContent = className;
playAudio(audios[className]); playAudio(audios[className]);
+2 -2
View File
@@ -6,9 +6,9 @@
"packages/*" "packages/*"
], ],
"peerDependencies": { "peerDependencies": {
"typescript": "^5" "typescript": "^5.9.3"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.9" "@types/bun": "^1.3.14"
} }
} }
+1 -1
View File
@@ -7,6 +7,6 @@
"ml-levenberg-marquardt": "^5.0.0" "ml-levenberg-marquardt": "^5.0.0"
}, },
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
} }
} }
File diff suppressed because it is too large Load Diff
+46 -46
View File
@@ -6,34 +6,34 @@ import avgWeightDataRaw from "./data/avg-weights.json";
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
export type Player = { export type Player = {
name?: string; name?: string;
metrics: Metrics; metrics: Metrics;
}; };
export enum Attribute { export enum Attribute {
Strength = "Strength", Strength = "Strength",
Power = "Power", Power = "Power",
Endurance = "Endurance", Endurance = "Endurance",
Agility = "Agility", Agility = "Agility",
} }
export enum Activity { export enum Activity {
BackSquat = "BackSquat", BackSquat = "BackSquat",
Deadlift = "Deadlift", Deadlift = "Deadlift",
BenchPress = "BenchPress", BenchPress = "BenchPress",
Run = "Run", Run = "Run",
BroadJump = "BroadJump", BroadJump = "BroadJump",
ConeDrill = "ConeDrill", ConeDrill = "ConeDrill",
} }
export interface ActivityPerformance { export interface ActivityPerformance {
activity: Activity; activity: Activity;
performance: number; performance: number;
} }
export enum Gender { export enum Gender {
Male = "Male", Male = "Male",
Female = "Female", Female = "Female",
} }
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
@@ -54,47 +54,47 @@ export const inToCm = (inches: number) => inches * 2.54;
export const cmToIn = (cm: number) => cm / 2.54; export const cmToIn = (cm: number) => cm / 2.54;
export const msToTime = (ms: number, includeMs = false): string => { export const msToTime = (ms: number, includeMs = false): string => {
const minutes = Math.floor(ms / 60000); const minutes = Math.floor(ms / 60000);
const seconds = Math.floor((ms % 60000) / 1000); const seconds = Math.floor((ms % 60000) / 1000);
const milliseconds = Math.floor(ms % 1000); const milliseconds = Math.floor(ms % 1000);
let formattedTime = `${minutes}:${seconds.toString().padStart(2, "0")}`; let formattedTime = `${minutes}:${seconds.toString().padStart(2, "0")}`;
if (includeMs) { if (includeMs) {
formattedTime += `.${milliseconds.toString().padStart(3, "0")}`; formattedTime += `.${milliseconds.toString().padStart(3, "0")}`;
} }
return formattedTime; return formattedTime;
}; };
export const range = (length: number) => export const range = (length: number) =>
Array.from({ length: length }, (_, i) => i); Array.from({ length: length }, (_, i) => i);
export const clamp = (x: number, lo: number, hi: number) => export const clamp = (x: number, lo: number, hi: number) =>
Math.max(lo, Math.min(hi, x)); Math.max(lo, Math.min(hi, x));
export const getAvgWeight = (gender: Gender, age: number) => { export const getAvgWeight = (gender: Gender, age: number) => {
type AvgWeightData = { type AvgWeightData = {
metadata: { metadata: {
unit: StandardUnit; unit: StandardUnit;
};
weights: Metrics[];
}; };
weights: Metrics[]; let avgWeightData = avgWeightDataRaw as AvgWeightData;
};
let avgWeightData = avgWeightDataRaw as AvgWeightData;
const avgWeights = avgWeightData.weights.filter((a) => a.gender === gender); const avgWeights = avgWeightData.weights.filter((a) => a.gender === gender);
const firstAvgWeight = avgWeights[0]; const firstAvgWeight = avgWeights[0];
if (!firstAvgWeight) throw new Error("No average weights"); if (!firstAvgWeight) throw new Error("No average weights");
const closest = { const closest = {
diff: Math.abs(firstAvgWeight.age - age), diff: Math.abs(firstAvgWeight.age - age),
avg: firstAvgWeight, avg: firstAvgWeight,
}; };
for (const avg of avgWeights) { for (const avg of avgWeights) {
const diff = Math.abs(avg.age - age); const diff = Math.abs(avg.age - age);
if (diff < closest.diff) { if (diff < closest.diff) {
closest.diff = diff; closest.diff = diff;
closest.avg = avg; closest.avg = avg;
}
} }
}
return closest.avg.weight; return closest.avg.weight;
}; };
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"noUncheckedIndexedAccess": false, "noUncheckedIndexedAccess": false
}, }
} }
+1 -1
View File
@@ -5,5 +5,5 @@
"type": "module", "type": "module",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
} }
} }
+5 -6
View File
@@ -1,6 +1,5 @@
export * from "./printful" export * from "./printful";
export * from "./sync" export * from "./sync";
export * from "./webflow" export * from "./webflow";
export * from "./webflow" export * from "./util/misc";
export * from "./util/misc" export * from "./util/types";
export * from "./util/types"
+179 -179
View File
@@ -2,206 +2,206 @@ import type { Printful } from "./util/types";
import { FetchError, type DeepPartial } from "./util/misc"; import { FetchError, type DeepPartial } from "./util/misc";
export class PrintfulService { export class PrintfulService {
static Products = class { static Products = class {
static Variants = class { static Variants = class {
static async get( static async get(
variantId: number | string, variantId: number | string,
): Promise<Printful.Products.SyncVariant | undefined> { ): Promise<Printful.Products.SyncVariant | undefined> {
const res = await fetch( const res = await fetch(
`${env().API_URL}/store/variants/${variantId}`, `${env().API_URL}/store/variants/${variantId}`,
{ {
method: "GET", method: "GET",
headers: { ...env().AUTH_HEADERS }, headers: { ...env().AUTH_HEADERS },
}, },
); );
if (res.status === 404 || res.status === 400) { if (res.status === 404 || res.status === 400) {
return; return;
}
if (!res.ok) {
throw new FetchError("Failed to get Printful variant", res);
}
const payload =
(await res.json()) as Printful.Products.MetaDataSingle<Printful.Products.SyncVariant>;
return payload.result;
}
};
static async getAll(
offset: number = 0,
): Promise<Printful.Products.SyncProduct[]> {
const allSyncProducts: Printful.Products.SyncProduct[] = [];
while (true) {
try {
const res = await fetch(
`${env().API_URL}/store/products?offset=${offset}`,
{
method: "GET",
headers: { ...env().AUTH_HEADERS },
},
);
if (!res.ok) {
throw new FetchError(
"Failed to get all Printful products",
res,
);
}
const payload =
(await res.json()) as Printful.Products.MetaDataMulti<Printful.Products.SyncProduct>;
allSyncProducts.push(...payload.result);
offset = allSyncProducts.length;
if (allSyncProducts.length >= payload.paging.total) break;
} catch (error) {
throw error;
}
}
return allSyncProducts;
} }
if (!res.ok) { static async get(
throw new FetchError("Failed to get Printful variant", res); productId: number | string,
): Promise<Printful.Products.Product | undefined> {
const res = await fetch(
`${env().API_URL}/store/products/${productId}`,
{
method: "GET",
headers: { ...env().AUTH_HEADERS },
},
);
if (res.status === 404 || res.status === 400) {
return;
}
if (!res.ok) {
throw new FetchError("Failed to get Printful product", res);
}
const payload =
(await res.json()) as Printful.Products.MetaDataSingle<Printful.Products.Product>;
return payload.result;
} }
const payload = static async update(
(await res.json()) as Printful.Products.MetaDataSingle<Printful.Products.SyncVariant>; printfulProductId: number,
return payload.result; printfulProduct: DeepPartial<Printful.Products.Product>,
} ) {
const res = await fetch(
`${env().API_URL}/store/products/${printfulProductId}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADERS,
},
body: JSON.stringify(printfulProduct),
},
);
if (!res.ok) {
throw new FetchError("Failed to update Printful product", res);
}
}
}; };
static async getAll( static Orders = class {
offset: number = 0, static async create(printfulOrder: Printful.Orders.Order) {
): Promise<Printful.Products.SyncProduct[]> { const res = await fetch(`${env().API_URL}/orders`, {
const allSyncProducts: Printful.Products.SyncProduct[] = []; method: "POST",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADERS,
},
body: JSON.stringify(printfulOrder),
});
while (true) { if (!res.ok) {
try { throw new FetchError("Failed to create printful order", res);
const res = await fetch( }
`${env().API_URL}/store/products?offset=${offset}`,
{
method: "GET",
headers: { ...env().AUTH_HEADERS },
},
);
if (!res.ok) {
throw new FetchError(
"Failed to get all Printful products",
res,
);
}
const payload =
(await res.json()) as Printful.Products.MetaDataMulti<Printful.Products.SyncProduct>;
allSyncProducts.push(...payload.result);
offset = allSyncProducts.length;
if (allSyncProducts.length >= payload.paging.total) break;
} catch (error) {
throw error;
} }
}
return allSyncProducts; static async getAll(
} offset: number = 0,
): Promise<Printful.Orders.Order[]> {
const allPrintfulOrders: Printful.Orders.Order[] = [];
static async get( while (true) {
productId: number | string, try {
): Promise<Printful.Products.Product | undefined> { const res = await fetch(
const res = await fetch( `${env().API_URL}/orders?offset=${offset}`,
`${env().API_URL}/store/products/${productId}`, {
{ method: "GET",
method: "GET", headers: { ...env().AUTH_HEADERS },
headers: { ...env().AUTH_HEADERS }, },
}, );
);
if (res.status === 404 || res.status === 400) { if (!res.ok) {
return; throw new FetchError(
} "Failed to get all Printful orders",
res,
);
}
if (!res.ok) { const payload =
throw new FetchError("Failed to get Printful product", res); (await res.json()) as Printful.Products.MetaDataMulti<Printful.Orders.Order>;
}
const payload = allPrintfulOrders.push(...payload.result);
(await res.json()) as Printful.Products.MetaDataSingle<Printful.Products.Product>; offset = allPrintfulOrders.length;
return payload.result;
}
static async update( if (allPrintfulOrders.length >= payload.paging.total) break;
printfulProductId: number, } catch (error) {
printfulProduct: DeepPartial<Printful.Products.Product>, throw error;
) { }
const res = await fetch( }
`${env().API_URL}/store/products/${printfulProductId}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADERS,
},
body: JSON.stringify(printfulProduct),
},
);
if (!res.ok) { return allPrintfulOrders;
throw new FetchError("Failed to update Printful product", res);
}
}
};
static Orders = class {
static async create(printfulOrder: Printful.Orders.Order) {
const res = await fetch(`${env().API_URL}/orders`, {
method: "POST",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADERS,
},
body: JSON.stringify(printfulOrder),
});
if (!res.ok) {
throw new FetchError("Failed to create printful order", res);
}
}
static async getAll(
offset: number = 0,
): Promise<Printful.Orders.Order[]> {
const allPrintfulOrders: Printful.Orders.Order[] = [];
while (true) {
try {
const res = await fetch(
`${env().API_URL}/orders?offset=${offset}`,
{
method: "GET",
headers: { ...env().AUTH_HEADERS },
},
);
if (!res.ok) {
throw new FetchError(
"Failed to get all Printful orders",
res,
);
}
const payload =
(await res.json()) as Printful.Products.MetaDataMulti<Printful.Orders.Order>;
allPrintfulOrders.push(...payload.result);
offset = allPrintfulOrders.length;
if (allPrintfulOrders.length >= payload.paging.total) break;
} catch (error) {
throw error;
} }
} };
return allPrintfulOrders; static Util = class {
} static getVariantMainImage(
}; syncVariant: Printful.Products.SyncVariant,
): string {
static Util = class { const previewFile = syncVariant.files.find(
static getVariantMainImage( (f) => f.type === "preview",
syncVariant: Printful.Products.SyncVariant, );
): string { return previewFile?.preview_url ?? syncVariant.product.image;
const previewFile = syncVariant.files.find( }
(f) => f.type === "preview", };
);
return previewFile?.preview_url ?? syncVariant.product.image;
}
};
} }
export const env = () => { export const env = () => {
if (typeof Bun === "undefined") { if (typeof Bun === "undefined") {
throw new Error( throw new Error(
"Must be in a server context. Make sure to run using --bun.", "Must be in a server context. Make sure to run using --bun.",
); );
}
const vars = {
AUTH_TOKEN: Bun.env.PRINTFUL_AUTH,
STORE_ID: Bun.env.PRINTFUL_STORE_ID,
} as Record<string, string>;
for (const varKey in vars) {
if (!vars[varKey]) {
console.log(`Missing ${varKey} environment variable`);
} }
}
return { const vars = {
...vars, AUTH_TOKEN: Bun.env.PRINTFUL_AUTH,
API_URL: "https://api.printful.com", STORE_ID: Bun.env.PRINTFUL_STORE_ID,
AUTH_HEADERS: { } as Record<string, string>;
Authorization: `Bearer ${vars.AUTH_TOKEN}`,
"X-PF-Store-Id": `${vars.STORE_ID}`, for (const varKey in vars) {
}, if (!vars[varKey]) {
}; console.log(`Missing ${varKey} environment variable`);
}
}
return {
...vars,
API_URL: "https://api.printful.com",
AUTH_HEADERS: {
Authorization: `Bearer ${vars.AUTH_TOKEN}`,
"X-PF-Store-Id": `${vars.STORE_ID}`,
},
};
}; };
+331 -331
View File
@@ -9,351 +9,351 @@ export const R2_WORKER_URL = "https://r2-worker.xominus.workers.dev";
export const WEBSITE_MEDIA_URL = "https://website-media.bladeandbrawn.com"; export const WEBSITE_MEDIA_URL = "https://website-media.bladeandbrawn.com";
type MainProduct = { type MainProduct = {
name: string; name: string;
externalId: string; externalId: string;
colors: Set<string>; colors: Set<string>;
variants: { variants: {
color: string; color: string;
product: Printful.Products.Product; product: Printful.Products.Product;
}[]; }[];
}; };
export class SyncService { export class SyncService {
static state = { static state = {
isSyncing: false, isSyncing: false,
syncingIds: [] as number[], syncingIds: [] as number[],
}; };
static async sync(printfulProductId: number | undefined) { static async sync(printfulProductId: number | undefined) {
this.state.isSyncing = true;
const mainPrintfulProducts: MainProduct[] = [];
const webflowProducts: Webflow.Products.ProductAndSkus[] = [];
try {
let printfulProducts = await PrintfulService.Products.getAll();
if (printfulProductId) {
const printfulProduct = printfulProducts.find(
(p) => p.id === printfulProductId,
);
if (printfulProduct) {
const mainProductName = this.getMainProductName(
printfulProduct.name,
);
printfulProducts = printfulProducts.filter((p) =>
p.name.includes(mainProductName),
);
}
}
webflowProducts.push(...(await WebflowService.Products.getAll()));
// Generate main printful products
console.log("Generating main products...");
for (const printfulProduct of printfulProducts) {
const mainProductName = this.getMainProductName(
printfulProduct.name,
);
let mainPrintfulProduct = mainPrintfulProducts.find((mp) =>
mp.name.includes(mainProductName),
);
if (!mainPrintfulProduct) {
mainPrintfulProduct = {
name: mainProductName,
variants: [],
externalId: printfulProduct.external_id,
colors: new Set(),
};
mainPrintfulProducts.push(mainPrintfulProduct);
}
const productColor = this.findColorInProductName(
printfulProduct.name,
);
mainPrintfulProduct.variants.push({
color: productColor,
product: (await PrintfulService.Products.get(
printfulProduct.id,
))!,
});
mainPrintfulProduct.colors.add(productColor);
}
} catch (error) {
throw error;
} finally {
this.state.isSyncing = false;
this.state.syncingIds = [];
}
// TODO: Validate main printful products
// Sync the main printful products
console.log("Syncing main products...");
for (const mainPrintfulProduct of mainPrintfulProducts) {
try {
this.state.isSyncing = true; this.state.isSyncing = true;
this.state.syncingIds = mainPrintfulProduct.variants.map(
(v) => v.product.sync_product.id,
);
const foundColors = mainPrintfulProduct.colors; const mainPrintfulProducts: MainProduct[] = [];
const foundSizes: Set<string> = new Set(); const webflowProducts: Webflow.Products.ProductAndSkus[] = [];
try {
const webflowSkus: DeepPartial<Webflow.Products.Skus.Sku>[] = let printfulProducts = await PrintfulService.Products.getAll();
[]; if (printfulProductId) {
const printfulProduct = printfulProducts.find(
for (const specialVariant of mainPrintfulProduct.variants) { (p) => p.id === printfulProductId,
for (const printfulVariant of specialVariant.product
.sync_variants) {
// check if this variant size is in all other special variants
let sizeIsInAllVariants = true;
for (const specialVariant of mainPrintfulProduct.variants) {
const sizes =
specialVariant.product.sync_variants.map(
(v) => v.size,
); );
if (!sizes.includes(printfulVariant.size)) if (printfulProduct) {
sizeIsInAllVariants = false; const mainProductName = this.getMainProductName(
printfulProduct.name,
);
printfulProducts = printfulProducts.filter((p) =>
p.name.includes(mainProductName),
);
}
} }
webflowProducts.push(...(await WebflowService.Products.getAll()));
if (sizeIsInAllVariants) { // Generate main printful products
foundSizes.add(printfulVariant.size); console.log("Generating main products...");
for (const printfulProduct of printfulProducts) {
webflowSkus.push({ const mainProductName = this.getMainProductName(
id: printfulVariant.external_id, printfulProduct.name,
fieldData: {
name: printfulVariant.name,
slug: formatSlug(printfulVariant.name),
"sku-values": {
color: specialVariant.color,
size: printfulVariant.size,
},
price: {
value: Math.floor(
+printfulVariant.retail_price * 100,
),
unit: printfulVariant.currency,
currency: printfulVariant.currency,
},
"main-image":
PrintfulService.Util.getVariantMainImage(
printfulVariant,
),
},
});
}
}
}
// SYNC PRODUCT DATA
let existingWebflowProduct = webflowProducts.find(
(webflowProduct) =>
webflowProduct.product.id ===
mainPrintfulProduct.externalId.split("-")[0],
);
if (existingWebflowProduct) {
// SYNC PRODUCT UPDATE
// do not update images
for (const webflowSku of webflowSkus) {
delete webflowSku.fieldData?.["main-image"];
}
const webflowProductId =
mainPrintfulProduct.externalId.split("-")[0];
if (!webflowProductId) {
throw new Error("Malformed printful product ID");
}
WebflowService.Products.update(webflowProductId, {
product: {
fieldData: {
name: mainPrintfulProduct.name,
slug: formatSlug(mainPrintfulProduct.name),
shippable: true,
"tax-category": "standard-taxable",
"sku-properties": [
{
id: "color",
name: "Color",
enum: Array.from(foundColors).map(
(color) => ({
id: color,
slug: formatSlug(color),
name: color,
}),
),
},
{
id: "size",
name: "Size",
enum: Array.from(foundSizes).map(
(size) => ({
id: size,
slug: formatSlug(size),
name: size,
}),
),
},
],
},
},
sku: webflowSkus[0],
});
for (const webflowSku of webflowSkus.slice(1)) {
const existingWebflowSku =
existingWebflowProduct.skus.find(
(sku) => sku.id === webflowSku.id,
);
if (webflowSku.id && existingWebflowSku) {
await WebflowService.Products.Skus.update(
webflowProductId,
webflowSku.id,
webflowSku,
);
} else {
await WebflowService.Products.Skus.create(
webflowProductId,
[webflowSku],
);
}
}
} else {
// SYNC PRODUCT CREATE
const webflowProductId =
await WebflowService.Products.create({
product: {
fieldData: {
name: mainPrintfulProduct.name,
slug: formatSlug(mainPrintfulProduct.name),
shippable: true,
"tax-category": "standard-taxable",
"sku-properties": [
{
id: "color",
name: "Color",
enum: Array.from(foundColors).map(
(color) => ({
id: color,
slug: formatSlug(color),
name: color,
}),
),
},
{
id: "size",
name: "Size",
enum: Array.from(foundSizes).map(
(size) => ({
id: size,
slug: formatSlug(size),
name: size,
}),
),
},
],
},
},
sku: webflowSkus[0],
});
// create webflow product SKUs
await WebflowService.Products.Skus.create(
webflowProductId,
webflowSkus.slice(1),
);
existingWebflowProduct =
await WebflowService.Products.get(webflowProductId);
if (!existingWebflowProduct) {
console.error("Missing webflow product");
throw new Error("Failed to create Webflow product");
}
for (const specialVariant of mainPrintfulProduct.variants) {
const newPrintfulVariants: DeepPartial<Printful.Products.SyncVariant>[] =
[];
for (const printfulVariant of specialVariant.product
.sync_variants) {
const associatedWebflowSku =
existingWebflowProduct.skus.find(
(sku) =>
sku.fieldData["sku-values"]?.[
"color"
] === printfulVariant.color &&
sku.fieldData["sku-values"]?.[
"size"
] === printfulVariant.size,
); );
if (associatedWebflowSku) {
newPrintfulVariants.push({ let mainPrintfulProduct = mainPrintfulProducts.find((mp) =>
id: printfulVariant.id, // printful variant id mp.name.includes(mainProductName),
external_id: String( );
associatedWebflowSku.id, if (!mainPrintfulProduct) {
), // webflow variant id mainPrintfulProduct = {
name: mainProductName,
variants: [],
externalId: printfulProduct.external_id,
colors: new Set(),
};
mainPrintfulProducts.push(mainPrintfulProduct);
}
const productColor = this.findColorInProductName(
printfulProduct.name,
);
mainPrintfulProduct.variants.push({
color: productColor,
product: (await PrintfulService.Products.get(
printfulProduct.id,
))!,
}); });
} mainPrintfulProduct.colors.add(productColor);
} }
} catch (error) {
throw error;
} finally {
this.state.isSyncing = false;
this.state.syncingIds = [];
}
await sleep(10000); // TODO: Validate main printful products
await PrintfulService.Products.update(
specialVariant.product.sync_product.id, // Sync the main printful products
{ console.log("Syncing main products...");
sync_product: { for (const mainPrintfulProduct of mainPrintfulProducts) {
id: specialVariant.product.sync_product.id, try {
external_id: `${webflowProductId}-${specialVariant.color}`, this.state.isSyncing = true;
}, this.state.syncingIds = mainPrintfulProduct.variants.map(
sync_variants: newPrintfulVariants, (v) => v.product.sync_product.id,
}, );
const foundColors = mainPrintfulProduct.colors;
const foundSizes: Set<string> = new Set();
const webflowSkus: DeepPartial<Webflow.Products.Skus.Sku>[] =
[];
for (const specialVariant of mainPrintfulProduct.variants) {
for (const printfulVariant of specialVariant.product
.sync_variants) {
// check if this variant size is in all other special variants
let sizeIsInAllVariants = true;
for (const specialVariant of mainPrintfulProduct.variants) {
const sizes =
specialVariant.product.sync_variants.map(
(v) => v.size,
);
if (!sizes.includes(printfulVariant.size))
sizeIsInAllVariants = false;
}
if (sizeIsInAllVariants) {
foundSizes.add(printfulVariant.size);
webflowSkus.push({
id: printfulVariant.external_id,
fieldData: {
name: printfulVariant.name,
slug: formatSlug(printfulVariant.name),
"sku-values": {
color: specialVariant.color,
size: printfulVariant.size,
},
price: {
value: Math.floor(
+printfulVariant.retail_price * 100,
),
unit: printfulVariant.currency,
currency: printfulVariant.currency,
},
"main-image":
PrintfulService.Util.getVariantMainImage(
printfulVariant,
),
},
});
}
}
}
// SYNC PRODUCT DATA
let existingWebflowProduct = webflowProducts.find(
(webflowProduct) =>
webflowProduct.product.id ===
mainPrintfulProduct.externalId.split("-")[0],
);
if (existingWebflowProduct) {
// SYNC PRODUCT UPDATE
// do not update images
for (const webflowSku of webflowSkus) {
delete webflowSku.fieldData?.["main-image"];
}
const webflowProductId =
mainPrintfulProduct.externalId.split("-")[0];
if (!webflowProductId) {
throw new Error("Malformed printful product ID");
}
await WebflowService.Products.update(webflowProductId, {
product: {
fieldData: {
name: mainPrintfulProduct.name,
slug: formatSlug(mainPrintfulProduct.name),
shippable: true,
"tax-category": "standard-taxable",
"sku-properties": [
{
id: "color",
name: "Color",
enum: Array.from(foundColors).map(
(color) => ({
id: color,
slug: formatSlug(color),
name: color,
}),
),
},
{
id: "size",
name: "Size",
enum: Array.from(foundSizes).map(
(size) => ({
id: size,
slug: formatSlug(size),
name: size,
}),
),
},
],
},
},
sku: webflowSkus[0],
});
for (const webflowSku of webflowSkus.slice(1)) {
const existingWebflowSku =
existingWebflowProduct.skus.find(
(sku) => sku.id === webflowSku.id,
);
if (webflowSku.id && existingWebflowSku) {
await WebflowService.Products.Skus.update(
webflowProductId,
webflowSku.id,
webflowSku,
);
} else {
await WebflowService.Products.Skus.create(
webflowProductId,
[webflowSku],
);
}
}
} else {
// SYNC PRODUCT CREATE
const webflowProductId =
await WebflowService.Products.create({
product: {
fieldData: {
name: mainPrintfulProduct.name,
slug: formatSlug(mainPrintfulProduct.name),
shippable: true,
"tax-category": "standard-taxable",
"sku-properties": [
{
id: "color",
name: "Color",
enum: Array.from(foundColors).map(
(color) => ({
id: color,
slug: formatSlug(color),
name: color,
}),
),
},
{
id: "size",
name: "Size",
enum: Array.from(foundSizes).map(
(size) => ({
id: size,
slug: formatSlug(size),
name: size,
}),
),
},
],
},
},
sku: webflowSkus[0],
});
// create webflow product SKUs
await WebflowService.Products.Skus.create(
webflowProductId,
webflowSkus.slice(1),
);
existingWebflowProduct =
await WebflowService.Products.get(webflowProductId);
if (!existingWebflowProduct) {
console.error("Missing webflow product");
throw new Error("Failed to create Webflow product");
}
for (const specialVariant of mainPrintfulProduct.variants) {
const newPrintfulVariants: DeepPartial<Printful.Products.SyncVariant>[] =
[];
for (const printfulVariant of specialVariant.product
.sync_variants) {
const associatedWebflowSku =
existingWebflowProduct.skus.find(
(sku) =>
sku.fieldData["sku-values"]?.[
"color"
] === printfulVariant.color &&
sku.fieldData["sku-values"]?.[
"size"
] === printfulVariant.size,
);
if (associatedWebflowSku) {
newPrintfulVariants.push({
id: printfulVariant.id, // printful variant id
external_id: String(
associatedWebflowSku.id,
), // webflow variant id
});
}
}
await sleep(10000);
await PrintfulService.Products.update(
specialVariant.product.sync_product.id,
{
sync_product: {
id: specialVariant.product.sync_product.id,
external_id: `${webflowProductId}-${specialVariant.color}`,
},
sync_variants: newPrintfulVariants,
},
);
}
}
} catch (err) {
// SYNC IMAGES
// for (const sku of existingWebflowProduct.skus) {
// const skuColor = sku.fieldData["sku-values"]?.["color"]?.toLowerCase() ?? "None";
// const skuSlug = `${existingWebflowProduct.product.fieldData.slug}-${skuColor}`;
// const skuImageUrls = await this.getProductImageUrls(skuSlug);
//
// sku.fieldData["main-image"] = skuImageUrls[0] ?? sku.fieldData["main-image"];
// sku.fieldData["more-images"] = skuImageUrls.slice(1).map(url => ({ url }));
//
// await WebflowService.Products.Skus.update(existingWebflowProduct.product.id, sku.id, sku);
// }
//
if (err instanceof FetchError) {
console.error(err.message, err.payload);
}
}
}
this.state.isSyncing = false;
this.state.syncingIds = [];
console.log("Done");
}
private static getProductImageUrls = async (slug: string) => {
const res = await fetch(`${R2_WORKER_URL}/product-images/${slug}`);
if (!res.ok) {
console.error(
"Failed to get product image keys:",
await res.json(),
); );
} throw new Error("Failed to get product image keys");
} }
} catch (err) { const productImageKeys: string[] = (await res.json()) as string[];
// SYNC IMAGES return productImageKeys.map((key) => `${WEBSITE_MEDIA_URL}/${key}`);
// for (const sku of existingWebflowProduct.skus) { };
// const skuColor = sku.fieldData["sku-values"]?.["color"]?.toLowerCase() ?? "None";
// const skuSlug = `${existingWebflowProduct.product.fieldData.slug}-${skuColor}`; public static findColorInProductName = (productName: string): string => {
// const skuImageUrls = await this.getProductImageUrls(skuSlug); const m = productName.match(/\[([^\]]+)\]/);
// return m?.[1] ? m[1] : "N/A";
// sku.fieldData["main-image"] = skuImageUrls[0] ?? sku.fieldData["main-image"]; };
// sku.fieldData["more-images"] = skuImageUrls.slice(1).map(url => ({ url }));
// public static getMainProductName = (productName: string) => {
// await WebflowService.Products.Skus.update(existingWebflowProduct.product.id, sku.id, sku); const colorInName = this.findColorInProductName(productName);
// } if (colorInName) {
// return productName.replace(`[${colorInName}]`, "").trimEnd();
if (err instanceof FetchError) { } else {
console.error(err.message, err.payload); return productName;
} }
} };
}
this.state.isSyncing = false;
this.state.syncingIds = [];
console.log("Done");
}
private static getProductImageUrls = async (slug: string) => {
const res = await fetch(`${R2_WORKER_URL}/product-images/${slug}`);
if (!res.ok) {
console.error(
"Failed to get product image keys:",
await res.json(),
);
throw new Error("Failed to get product image keys");
}
const productImageKeys: string[] = (await res.json()) as string[];
return productImageKeys.map((key) => `${WEBSITE_MEDIA_URL}/${key}`);
};
public static findColorInProductName = (productName: string): string => {
const m = productName.match(/\[([^\]]+)\]/);
return m?.[1] ? m[1] : "N/A";
};
public static getMainProductName = (productName: string) => {
const colorInName = this.findColorInProductName(productName);
if (colorInName) {
return productName.replace(`[${colorInName}]`, "").trimEnd();
} else {
return productName;
}
};
} }
+301 -301
View File
@@ -3,328 +3,328 @@ import { FetchError, type DeepPartial } from "./util/misc";
import crypto from "node:crypto"; import crypto from "node:crypto";
export class WebflowService { export class WebflowService {
static Products = class { static Products = class {
static Skus = class { static Skus = class {
static async create( static async create(
webflowProductId: string, webflowProductId: string,
skus: DeepPartial<Webflow.Products.Skus.Sku>[], skus: DeepPartial<Webflow.Products.Skus.Sku>[],
): Promise<string[]> { ): Promise<string[]> {
const res = await fetch( const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}/skus`, `${env().API_SITES_URL}/products/${webflowProductId}/skus`,
{ {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
...env().AUTH_HEADER, ...env().AUTH_HEADER,
}, },
body: JSON.stringify({ body: JSON.stringify({
skus: skus, skus: skus,
}), }),
}, },
); );
if (!res.ok) { if (!res.ok) {
throw new FetchError( throw new FetchError(
"Failed to create Webflow product SKU", "Failed to create Webflow product SKU",
res, res,
); );
} }
const payload = (await res.json()) as { const payload = (await res.json()) as {
skus: { id: string }[]; skus: { id: string }[];
};
return payload.skus.map((sku) => sku.id);
}
static async update(
webflowProductId: string,
webflowSkuId: string,
webflowSku: DeepPartial<Webflow.Products.Skus.Sku>,
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}/skus/${webflowSkuId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify({
sku: webflowSku,
}),
},
);
if (!res.ok) {
throw new FetchError(
"Failed to update Webflow product SKU",
res,
);
}
}
}; };
return payload.skus.map((sku) => sku.id);
}
static async update( static async create(
webflowProductId: string, webflowProductAndSku: DeepPartial<Webflow.Products.ProductAndSku>,
webflowSkuId: string, ): Promise<string> {
webflowSku: DeepPartial<Webflow.Products.Skus.Sku>, const res = await fetch(`${env().API_SITES_URL}/products`, {
): Promise<void> { method: "POST",
const res = await fetch( headers: {
`${env().API_SITES_URL}/products/${webflowProductId}/skus/${webflowSkuId}`, "Content-Type": "application/json",
{ ...env().AUTH_HEADER,
method: "PATCH", },
headers: { body: JSON.stringify(webflowProductAndSku),
"Content-Type": "application/json", });
...env().AUTH_HEADER,
}, if (!res.ok) {
body: JSON.stringify({ throw new FetchError("Failed to create Webflow product", res);
sku: webflowSku, }
}),
}, const createdWebflowProduct = (await res.json()) as {
); product: { id: string };
if (!res.ok) { };
throw new FetchError( return createdWebflowProduct.product.id;
"Failed to update Webflow product SKU", }
res,
); static async getAll(): Promise<Webflow.Products.ProductAndSkus[]> {
const res = await fetch(`${env().API_SITES_URL}/products`, {
method: "GET",
headers: {
...env().AUTH_HEADER,
},
});
if (!res.ok) {
throw new FetchError("Failed to get all Webflow products", res);
}
const payload = (await res.json()) as {
items: Webflow.Products.ProductAndSkus[];
};
return payload.items;
}
static async get(
webflowProductId: string,
): Promise<Webflow.Products.ProductAndSkus | undefined> {
const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}`,
{
method: "GET",
headers: {
...env().AUTH_HEADER,
},
},
);
if (res.status === 404 || res.status === 400) {
return;
}
if (!res.ok) {
throw new FetchError("Failed to get Webflow product", res);
}
const payload =
(await res.json()) as Webflow.Products.ProductAndSkus;
return payload;
}
static async update(
webflowProductId: string,
webflowProduct: DeepPartial<Webflow.Products.ProductAndSku>,
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(webflowProduct),
},
);
if (!res.ok) {
throw new FetchError("Failed to update Webflow product", res);
}
}
static async remove(webflowProductId: string): Promise<void> {
const res = await fetch(
`${env().API_COLLECTIONS_URL}/items/${webflowProductId}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify({}),
},
);
if (!res.ok) {
throw new FetchError("Failed to remove Webflow product", res);
}
} }
}
}; };
static async create( static Orders = class {
webflowProductAndSku: DeepPartial<Webflow.Products.ProductAndSku>, static async getAll(
): Promise<string> { opt: { status?: Webflow.Orders.Order["status"] } = {},
const res = await fetch(`${env().API_SITES_URL}/products`, { ): Promise<Webflow.Orders.Order[]> {
method: "POST", // TODO: pagination
headers: { const params = new URLSearchParams();
"Content-Type": "application/json", if (opt.status !== undefined) {
...env().AUTH_HEADER, params.set("status", opt.status);
}, }
body: JSON.stringify(webflowProductAndSku),
});
if (!res.ok) { const res = await fetch(
throw new FetchError("Failed to create Webflow product", res); `${env().API_SITES_URL}/orders?${params.toString()}`,
} {
method: "GET",
headers: { ...env().AUTH_HEADER },
},
);
const createdWebflowProduct = (await res.json()) as { if (!res.ok) {
product: { id: string }; throw new FetchError("Failed to get all Webflow orders", res);
}; }
return createdWebflowProduct.product.id;
}
static async getAll(): Promise<Webflow.Products.ProductAndSkus[]> { const payload = (await res.json()) as {
const res = await fetch(`${env().API_SITES_URL}/products`, { orders: Webflow.Orders.Order[];
method: "GET", };
headers: { return payload.orders;
...env().AUTH_HEADER,
},
});
if (!res.ok) {
throw new FetchError("Failed to get all Webflow products", res);
}
const payload = (await res.json()) as {
items: Webflow.Products.ProductAndSkus[];
};
return payload.items;
}
static async get(
webflowProductId: string,
): Promise<Webflow.Products.ProductAndSkus | undefined> {
const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}`,
{
method: "GET",
headers: {
...env().AUTH_HEADER,
},
},
);
if (res.status === 404 || res.status === 400) {
return;
}
if (!res.ok) {
throw new FetchError("Failed to get Webflow product", res);
}
const payload =
(await res.json()) as Webflow.Products.ProductAndSkus;
return payload;
}
static async update(
webflowProductId: string,
webflowProduct: DeepPartial<Webflow.Products.ProductAndSku>,
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/products/${webflowProductId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(webflowProduct),
},
);
if (!res.ok) {
throw new FetchError("Failed to update Webflow product", res);
}
}
static async remove(webflowProductId: string): Promise<void> {
const res = await fetch(
`${env().API_COLLECTIONS_URL}/items/${webflowProductId}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify({}),
},
);
if (!res.ok) {
throw new FetchError("Failed to remove Webflow product", res);
}
}
};
static Orders = class {
static async getAll(
opt: { status?: Webflow.Orders.Order["status"] } = {},
): Promise<Webflow.Orders.Order[]> {
// TODO: pagination
const params = new URLSearchParams();
if (opt.status !== undefined) {
params.set("status", opt.status);
}
const res = await fetch(
`${env().API_SITES_URL}/orders?${params.toString()}`,
{
method: "GET",
headers: { ...env().AUTH_HEADER },
},
);
if (!res.ok) {
throw new FetchError("Failed to get all Webflow orders", res);
}
const payload = (await res.json()) as {
orders: Webflow.Orders.Order[];
};
return payload.orders;
}
static async update(
webflowOrderId: string,
webflowOrderUpdate: {
comment?: string;
shippingProvider?: string;
shippingTracking?: string;
shippingTrackingURL: string;
},
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/orders/${webflowOrderId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(webflowOrderUpdate),
},
);
if (!res.ok) {
throw new FetchError("Failed to update Webflow order", res);
}
}
static async fulfill(
webflowOrderId: string,
opt: { sendOrderFulfilledEmail?: boolean } = {},
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/orders/${webflowOrderId}/fulfill`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(opt),
},
);
if (!res.ok) {
throw new FetchError("Failed to fulfill Webflow order", res);
}
}
};
static Util = class {
static verifyWebflowSignature(
request: Request,
body: unknown,
): Boolean {
try {
const timestamp = request.headers.get("x-webflow-timestamp");
if (!timestamp) {
throw new Error("No timestamp provided");
}
const providedSignature = request.headers.get(
"x-webflow-signature",
);
if (!providedSignature) {
throw new Error("No signature provided");
} }
const secret = env().WEBHOOK_SECRET; static async update(
if (!secret) { webflowOrderId: string,
throw new Error("No secret provided"); webflowOrderUpdate: {
comment?: string;
shippingProvider?: string;
shippingTracking?: string;
shippingTrackingURL: string;
},
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/orders/${webflowOrderId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(webflowOrderUpdate),
},
);
if (!res.ok) {
throw new FetchError("Failed to update Webflow order", res);
}
} }
if (!body) { static async fulfill(
throw new Error("Body is empty"); webflowOrderId: string,
opt: { sendOrderFulfilledEmail?: boolean } = {},
): Promise<void> {
const res = await fetch(
`${env().API_SITES_URL}/orders/${webflowOrderId}/fulfill`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
...env().AUTH_HEADER,
},
body: JSON.stringify(opt),
},
);
if (!res.ok) {
throw new FetchError("Failed to fulfill Webflow order", res);
}
} }
};
const requestTimestamp = parseInt(timestamp, 10); static Util = class {
const data = `${requestTimestamp}:${JSON.stringify(body)}`; static verifyWebflowSignature(
const hash = crypto request: Request,
.createHmac("sha256", secret) body: unknown,
.update(data) ): Boolean {
.digest("hex"); try {
const timestamp = request.headers.get("x-webflow-timestamp");
if (!timestamp) {
throw new Error("No timestamp provided");
}
const providedSignature = request.headers.get(
"x-webflow-signature",
);
if (!providedSignature) {
throw new Error("No signature provided");
}
if ( const secret = env().WEBHOOK_SECRET;
!crypto.timingSafeEqual( if (!secret) {
Buffer.from(hash, "hex"), throw new Error("No secret provided");
Buffer.from(providedSignature, "hex"), }
)
) { if (!body) {
throw new Error("Invalid signature"); throw new Error("Body is empty");
}
const requestTimestamp = parseInt(timestamp, 10);
const data = `${requestTimestamp}:${JSON.stringify(body)}`;
const hash = crypto
.createHmac("sha256", secret)
.update(data)
.digest("hex");
if (
!crypto.timingSafeEqual(
Buffer.from(hash, "hex"),
Buffer.from(providedSignature, "hex"),
)
) {
throw new Error("Invalid signature");
}
const currentTime = Date.now();
if (currentTime - requestTimestamp > 300000) {
throw new Error("Request is older than 5 minutes");
}
return true;
} catch (err) {
console.error(`Error verifying signature: ${err}`);
return false;
}
} }
};
const currentTime = Date.now();
if (currentTime - requestTimestamp > 300000) {
throw new Error("Request is older than 5 minutes");
}
return true;
} catch (err) {
console.error(`Error verifying signature: ${err}`);
return false;
}
}
};
} }
const env = () => { const env = () => {
if (typeof Bun === "undefined") { if (typeof Bun === "undefined") {
throw new Error( throw new Error(
"Must be in a server context. Make sure to run using --bun.", "Must be in a server context. Make sure to run using --bun.",
); );
}
const vars = {
SITE_ID: Bun.env.WEBFLOW_SITE_ID,
COLLECTIONS_ID: Bun.env.WEBFLOW_COLLECTION_ID,
AUTH_TOKEN: Bun.env.WEBFLOW_AUTH,
WEBHOOK_SECRET: Bun.env.WEBFLOW_WEBHOOK_SECRET,
} as Record<string, string>;
for (const varKey in vars) {
if (!vars[varKey]) {
console.log(`Missing ${varKey} environment variable`);
} }
}
return { const vars = {
...vars, SITE_ID: Bun.env.WEBFLOW_SITE_ID,
API_SITES_URL: `https://api.webflow.com/v2/sites/${vars.SITE_ID}`, COLLECTIONS_ID: Bun.env.WEBFLOW_COLLECTION_ID,
API_COLLECTIONS_URL: `https://api.webflow.com/v2/collections/${vars.COLLECTIONS_ID}`, AUTH_TOKEN: Bun.env.WEBFLOW_AUTH,
AUTH_HEADER: { Authorization: `bearer ${vars.AUTH_TOKEN}` }, WEBHOOK_SECRET: Bun.env.WEBFLOW_WEBHOOK_SECRET,
}; } as Record<string, string>;
for (const varKey in vars) {
if (!vars[varKey]) {
console.log(`Missing ${varKey} environment variable`);
}
}
return {
...vars,
API_SITES_URL: `https://api.webflow.com/v2/sites/${vars.SITE_ID}`,
API_COLLECTIONS_URL: `https://api.webflow.com/v2/collections/${vars.COLLECTIONS_ID}`,
AUTH_HEADER: { Authorization: `bearer ${vars.AUTH_TOKEN}` },
};
}; };
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json"
} }
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json"
} }
+2 -2
View File
@@ -25,6 +25,6 @@
// Some stricter flags (disabled by default) // Some stricter flags (disabled by default)
"noUnusedLocals": false, "noUnusedLocals": false,
"noUnusedParameters": false, "noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false, "noPropertyAccessFromIndexSignature": false
}, }
} }
+4 -2
View File
@@ -1,5 +1,7 @@
fetch("https://kv-logger.xominus.workers.dev", { fetch("https://kv-logger.xominus.workers.dev", {
method: "POST", method: "POST",
headers: { "content-type": "application/json" }, headers: { "content-type": "application/json" },
body: JSON.stringify({ "test": 1 }) body: JSON.stringify({ test: 1 }),
}).catch((e) => { console.error(e) }); }).catch((e) => {
console.error(e);
});
+1 -2
View File
@@ -6,7 +6,7 @@ export default {
switch (request.method) { switch (request.method) {
case 'GET': case 'GET':
const listResponse = await env.media.list({ prefix, limit: 1000 }); const listResponse = await env.media.list({ prefix, limit: 1000 });
const keys = listResponse.objects.map(o => o.key); const keys = listResponse.objects.map((o) => o.key);
const headers = new Headers(); const headers = new Headers();
headers.set('Content-Type', 'application/json'); headers.set('Content-Type', 'application/json');
@@ -24,6 +24,5 @@ export default {
}, },
}); });
} }
}, },
} satisfies ExportedHandler<Env>; } satisfies ExportedHandler<Env>;
+1 -3
View File
@@ -36,9 +36,7 @@
/* Skip type checking all .d.ts files. */ /* Skip type checking all .d.ts files. */
"skipLibCheck": true, "skipLibCheck": true,
"types": [ "types": ["./worker-configuration.d.ts"]
"./worker-configuration.d.ts"
]
}, },
"exclude": ["test"], "exclude": ["test"],
"include": ["worker-configuration.d.ts", "src/**/*.ts"] "include": ["worker-configuration.d.ts", "src/**/*.ts"]
+6984 -6364
View File
File diff suppressed because it is too large Load Diff