@alwith/module-auth 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +21 -1
  2. package/THIRD_PARTY_NOTICES.md +3 -2
  3. package/dist/oauth.js +1 -1
  4. package/dist/pets/assets.d.ts +34 -3
  5. package/dist/pets/assets.js +1 -1
  6. package/dist/pets/client.d.ts +1 -0
  7. package/dist/pets/client.js +1 -1
  8. package/dist/pets/core/engine.js +1 -1
  9. package/dist/pets/core/host.d.ts +26 -25
  10. package/dist/pets/core/lib/account-state.js +1 -1
  11. package/dist/pets/core/lib/draw-result.js +1 -1
  12. package/dist/pets/core/lib/endpoints.d.ts +28 -1
  13. package/dist/pets/core/lib/gacha-pools.js +1 -1
  14. package/dist/pets/core/lib/loading-progress.d.ts +0 -1
  15. package/dist/pets/core/lib/loading-progress.js +1 -1
  16. package/dist/pets/core/lib/pet-animation-sync.d.ts +1 -1
  17. package/dist/pets/core/lib/pet-drag.d.ts +1 -1
  18. package/dist/pets/core/lib/pet-presentation.d.ts +1 -1
  19. package/dist/pets/core/lib/preload-images.js +1 -1
  20. package/dist/pets/core/lib/presentation-readiness.js +1 -1
  21. package/dist/pets/core/lib/rarity.js +1 -1
  22. package/dist/pets/core/lib/resource-sync.js +1 -1
  23. package/dist/pets/core/lib/settings.js +1 -1
  24. package/dist/pets/core/lib/sprite-config.js +1 -1
  25. package/dist/pets/core/lib/vibemon-resources.js +1 -1
  26. package/dist/pets/core/types.d.ts +2 -4
  27. package/dist/pets/host.d.ts +13 -10
  28. package/dist/pets/react/assets.js +1 -1
  29. package/dist/pets/react/components/album-view.js +1 -1
  30. package/dist/pets/react/components/back-to-home.js +1 -1
  31. package/dist/pets/react/components/equip-view.js +1 -1
  32. package/dist/pets/react/components/gem-balance.js +1 -1
  33. package/dist/pets/react/components/home-view.js +1 -1
  34. package/dist/pets/react/components/insufficient-points-dialog.js +1 -1
  35. package/dist/pets/react/components/loading-view.js +1 -1
  36. package/dist/pets/react/components/lounge-burst.css +0 -2
  37. package/dist/pets/react/components/onboarding-guide.js +1 -1
  38. package/dist/pets/react/components/pet-bubble-background.js +1 -1
  39. package/dist/pets/react/components/pet-window.js +1 -1
  40. package/dist/pets/react/components/pull-overlay.js +1 -1
  41. package/dist/pets/react/components/pull-view.js +1 -1
  42. package/dist/pets/react/components/quick-reply.js +2 -2
  43. package/dist/pets/react/components/single-pet-toast.js +1 -1
  44. package/dist/pets/react/components/sprite-renderer.d.ts +2 -1
  45. package/dist/pets/react/components/sprite-renderer.js +1 -1
  46. package/dist/pets/react/components/vibemon-header.js +1 -1
  47. package/dist/pets/react/components/vibemon-page.js +1 -1
  48. package/dist/pets/react/components/video-fader.d.ts +1 -4
  49. package/dist/pets/react/components/video-fader.js +1 -1
  50. package/dist/pets/react/components/wish-button.js +1 -1
  51. package/dist/pets/react/ui/button.d.ts +1 -1
  52. package/dist/pets/react/ui/button.js +1 -1
  53. package/dist/pets/react/ui/card.d.ts +1 -1
  54. package/dist/pets/react/ui/card.js +1 -1
  55. package/dist/pets/react/ui/input-group.d.ts +1 -1
  56. package/dist/pets/react/ui/input-group.js +1 -1
  57. package/dist/pets/resource-package.d.ts +27 -0
  58. package/dist/pets/resource-package.js +1 -0
  59. package/dist/pets/resources.d.ts +16 -16
  60. package/dist/pets/resources.js +1 -1
  61. package/dist/pets/selection.d.ts +1 -1
  62. package/dist/pets/selection.js +1 -1
  63. package/dist/pets/sheet-layout.d.ts +10 -0
  64. package/dist/pets/sheet-layout.js +1 -0
  65. package/dist/pets/types.d.ts +21 -9
  66. package/dist/state.d.ts +1 -1
  67. package/dist/state.js +1 -1
  68. package/dist/token-storage.d.ts +9 -9
  69. package/dist/token-storage.js +1 -1
  70. package/licenses/fflate-MIT.txt +21 -0
  71. package/package.json +5 -4
@@ -1 +1 @@
1
- import{jsx as t}from"react/jsx-runtime";import{cn as d}from"cn";function c({className:a,size:r="default",...e}){return t("div",{"data-slot":"card","data-size":r,className:d("group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 [--card-spacing:--spacing(6)] has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",a),...e})}function n({className:a,...r}){return t("div",{"data-slot":"card-header",className:d("group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",a),...r})}function i({className:a,...r}){return t("div",{"data-slot":"card-title",className:d("font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm",a),...r})}function l({className:a,...r}){return t("div",{"data-slot":"card-description",className:d("text-sm text-muted-foreground",a),...r})}function u({className:a,...r}){return t("div",{"data-slot":"card-action",className:d("col-start-2 row-span-2 row-start-1 self-start justify-self-end",a),...r})}function g({className:a,...r}){return t("div",{"data-slot":"card-content",className:d("flex flex-col gap-3 px-(--card-spacing)",a),...r})}function p({className:a,...r}){return t("div",{"data-slot":"card-footer",className:d("flex items-center rounded-b-xl px-(--card-spacing) [.border-t]:pt-(--card-spacing)",a),...r})}export{c as Card,u as CardAction,g as CardContent,l as CardDescription,p as CardFooter,n as CardHeader,i as CardTitle};
1
+ import{jsx as t}from"react/jsx-runtime";import{cn as d}from"cn";function c({className:a,size:r="default",...e}){return t("div",{"data-slot":"card","data-size":r,className:d("group/card bg-card text-card-foreground ring-foreground/10 flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl py-(--card-spacing) text-sm shadow-xs ring-1 [--card-spacing:--spacing(6)] has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",a),...e})}function n({className:a,...r}){return t("div",{"data-slot":"card-header",className:d("group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",a),...r})}function i({className:a,...r}){return t("div",{"data-slot":"card-title",className:d("font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm",a),...r})}function l({className:a,...r}){return t("div",{"data-slot":"card-description",className:d("text-muted-foreground text-sm",a),...r})}function u({className:a,...r}){return t("div",{"data-slot":"card-action",className:d("col-start-2 row-span-2 row-start-1 self-start justify-self-end",a),...r})}function g({className:a,...r}){return t("div",{"data-slot":"card-content",className:d("flex flex-col gap-3 px-(--card-spacing)",a),...r})}function p({className:a,...r}){return t("div",{"data-slot":"card-footer",className:d("flex items-center rounded-b-xl px-(--card-spacing) [.border-t]:pt-(--card-spacing)",a),...r})}export{c as Card,u as CardAction,g as CardContent,l as CardDescription,p as CardFooter,n as CardHeader,i as CardTitle};
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
1
  import { type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
3
  import { Button } from "./button.js";
4
4
  declare function InputGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
5
5
  declare const inputGroupAddonVariants: (props?: ({
@@ -1 +1 @@
1
- import{jsx as n}from"react/jsx-runtime";import{cva as s}from"class-variance-authority";import{cn as o}from"cn";import{Button as u}from"./button.js";import{Textarea as l}from"./textarea.js";function m({className:a,...t}){return n("div",{"data-slot":"input-group",role:"group",className:o("group/input-group border-input has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:bg-input/30 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 relative flex h-9 w-full min-w-0 items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",a),...t})}var d=s("flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",{variants:{align:{"inline-start":"order-first pl-2 has-[>button]:-ml-1 has-[>kbd]:ml-[-0.15rem]","inline-end":"order-last pr-2 has-[>button]:-mr-1 has-[>kbd]:mr-[-0.15rem]","block-start":"order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2","block-end":"order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2"}},defaultVariants:{align:"inline-start"}});function x({className:a,align:t="inline-start",...i}){return n("div",{role:"group","data-slot":"input-group-addon","data-align":t,className:o(d({align:t}),a),onClick:(r)=>{if(r.target.closest("button"))return;r.currentTarget.parentElement?.querySelector("input")?.focus()},...i})}var p=s("flex items-center gap-2 text-sm shadow-none",{variants:{size:{xs:"h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",sm:"","icon-xs":"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0","icon-sm":"size-8 p-0 has-[>svg]:p-0"}},defaultVariants:{size:"xs"}});function v({className:a,type:t="button",variant:i="ghost",size:r="xs",...e}){return n(u,{type:t,"data-size":r,variant:i,className:o(p({size:r}),a),...e})}function k({className:a,...t}){return n(l,{"data-slot":"input-group-control",className:o("flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent",a),...t})}export{m as InputGroup,x as InputGroupAddon,v as InputGroupButton,k as InputGroupTextarea};
1
+ import{jsx as n}from"react/jsx-runtime";import{cva as s}from"class-variance-authority";import{cn as o}from"cn";import{Button as u}from"./button.js";import{Textarea as l}from"./textarea.js";function m({className:a,...t}){return n("div",{"data-slot":"input-group",role:"group",className:o("group/input-group border-input has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:bg-input/30 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 relative flex h-9 w-full min-w-0 items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",a),...t})}var d=s("text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",{variants:{align:{"inline-start":"order-first pl-2 has-[>button]:-ml-1 has-[>kbd]:ml-[-0.15rem]","inline-end":"order-last pr-2 has-[>button]:-mr-1 has-[>kbd]:mr-[-0.15rem]","block-start":"order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2","block-end":"order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2"}},defaultVariants:{align:"inline-start"}});function x({className:a,align:t="inline-start",...i}){return n("div",{role:"group","data-slot":"input-group-addon","data-align":t,className:o(d({align:t}),a),onClick:(r)=>{if(r.target.closest("button"))return;r.currentTarget.parentElement?.querySelector("input")?.focus()},...i})}var p=s("flex items-center gap-2 text-sm shadow-none",{variants:{size:{xs:"h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",sm:"","icon-xs":"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0","icon-sm":"size-8 p-0 has-[>svg]:p-0"}},defaultVariants:{size:"xs"}});function v({className:a,type:t="button",variant:i="ghost",size:r="xs",...e}){return n(u,{type:t,"data-size":r,variant:i,className:o(p({size:r}),a),...e})}function k({className:a,...t}){return n(l,{"data-slot":"input-group-control",className:o("flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent",a),...t})}export{m as InputGroup,x as InputGroupAddon,v as InputGroupButton,k as InputGroupTextarea};
@@ -0,0 +1,27 @@
1
+ import type { PetAssetsHost } from "./host.js";
2
+ import { type SheetLayout } from "./sheet-layout.js";
3
+ export declare const IMAGE_ASSETS: readonly ["cover", "gacha", "multi_draw", "icon", "background", "pool_card", "sidebar_selected", "sidebar_hover", "sidebar_unselected"];
4
+ export type ImageAsset = (typeof IMAGE_ASSETS)[number];
5
+ export interface PackageAsset {
6
+ path: string;
7
+ sha256: string;
8
+ }
9
+ export interface PackageManifest {
10
+ format_version: 1;
11
+ assets: Record<string, PackageAsset>;
12
+ }
13
+ export declare const PACKAGE_LIMIT: number;
14
+ export declare function resourcePath(path: string): boolean;
15
+ export declare function sha256(bytes: Uint8Array): Promise<string>;
16
+ export declare function parseManifest(bytes: Uint8Array): PackageManifest;
17
+ export declare function imageInfo(bytes: Uint8Array): {
18
+ mime: string;
19
+ width: number;
20
+ height: number;
21
+ };
22
+ export declare function validatePackageFiles(manifest: PackageManifest, read: (path: string) => Promise<Uint8Array | null>, validateImage?: PetAssetsHost["validateImage"]): Promise<SheetLayout | null>;
23
+ export declare function unpackResourcePackage(bytes: Uint8Array, validateImage?: PetAssetsHost["validateImage"]): Promise<{
24
+ files: Map<string, Uint8Array<ArrayBufferLike>>;
25
+ manifest: PackageManifest;
26
+ layout: SheetLayout | null;
27
+ }>;
@@ -0,0 +1 @@
1
+ import{Unzip as j,UnzipInflate as k}from"fflate";import{parseSheetLayout as A}from"./sheet-layout.js";var z=["cover","gacha","multi_draw","icon","background","pool_card","sidebar_selected","sidebar_hover","sidebar_unselected"],g=209715200,d=65536,E=new TextDecoder("utf-8",{fatal:!0});function P(e){return e.length>0&&!/[\\\u0000-\u001f:]/.test(e)&&e.split("/").every((n)=>n!==""&&n!=="."&&n!=="..")}async function Z(e){let n=await crypto.subtle.digest("SHA-256",new Uint8Array(e).buffer);return Array.from(new Uint8Array(n),(a)=>a.toString(16).padStart(2,"0")).join("")}function _(e){if(e.length>d)throw Error("Vibemon manifest exceeds 64 KiB");let n=JSON.parse(E.decode(e));if(n?.format_version!==1||!n.assets||typeof n.assets!=="object"||Array.isArray(n.assets))throw Error("Invalid Vibemon package manifest");let a=Object.entries(n.assets);if(a.length>11)throw Error("Too many Vibemon assets");let o=new Set;for(let[,t]of a){if(!t||typeof t.path!=="string"||!P(t.path)||t.path==="manifest.json"||typeof t.sha256!=="string"||!/^[a-f0-9]{64}$/.test(t.sha256)||o.has(t.path))throw Error("Invalid Vibemon asset reference");o.add(t.path)}if(Boolean(n.assets.sheet)!==Boolean(n.assets.layout))throw Error("Vibemon animation requires both sheet and layout");return n}function M(e){let n=new DataView(e.buffer,e.byteOffset,e.byteLength),a=(r,f)=>String.fromCharCode(...e.subarray(r,r+f)),o="",t=0,s=0;if(e.length>=24&&e[0]===137&&a(1,3)==="PNG")o="image/png",t=n.getUint32(16),s=n.getUint32(20);else if(e.length>=10&&/GIF8[79]a/.test(a(0,6)))o="image/gif",t=n.getUint16(6,!0),s=n.getUint16(8,!0);else if(e.length>=30&&a(0,4)==="RIFF"&&a(8,4)==="WEBP"){o="image/webp";let r=a(12,4);if(r==="VP8X")t=1+(n.getUint32(24,!0)&16777215),s=1+(e[27]|e[28]<<8|e[29]<<16);else if(r==="VP8L"&&e[20]===47){let f=n.getUint32(21,!0);t=1+(f&16383),s=1+(f>>>14&16383)}else if(r==="VP8 "&&e[23]===157&&e[24]===1&&e[25]===42)t=n.getUint16(26,!0)&16383,s=n.getUint16(28,!0)&16383}else if(e.length>4&&e[0]===255&&e[1]===216){o="image/jpeg";for(let r=2;r+8<e.length;){if(e[r++]!==255)break;while(e[r]===255)r++;let f=e[r++];if(f===217||f===218)break;if(f===1||f>=208&&f<=215)continue;let c=n.getUint16(r);if(c<2||r+c>e.length)break;if([192,193,194,195,197,198,199,201,202,203,205,206,207].includes(f)){s=n.getUint16(r+3),t=n.getUint16(r+5);break}r+=c}}if(!t||!s||t>16384||s>16384)throw Error("Invalid or unsupported Vibemon image dimensions");return{mime:o,width:t,height:s}}async function O(e,n,a){let o=0,t=null,s=null;for(let[r,f]of Object.entries(e.assets)){let c=await n(f.path);if(c===null||await Z(c)!==f.sha256)throw Error(`Vibemon asset checksum mismatch: ${r}`);if(o+=c.length,o>g)throw Error("Vibemon resource expansion limit exceeded");if(r==="layout"){if(c.length>d)throw Error("Vibemon layout exceeds 64 KiB");t=A(E.decode(c))}else if(r==="sheet"||z.includes(r)){let h=M(c);if(await a?.(c,h.mime),r==="sheet")s=h}}if(t&&s&&t.states.some((r)=>r.frames*t.frameWidth>s.width||(r.row+1)*t.frameHeight>s.height))throw Error("Vibemon animation exceeds the spritesheet");return t}async function L(e,n){if(e.length>g)throw Error("Vibemon ZIP exceeds 200 MiB");let a=new DataView(e.buffer,e.byteOffset,e.byteLength),o=e.length-22;while(o>=Math.max(0,e.length-65557)&&a.getUint32(o,!0)!==101010256)o--;if(o<0||e.length<22||a.getUint32(o,!0)!==101010256||o+22+a.getUint16(o+20,!0)!==e.length||a.getUint16(o+4,!0)!==0||a.getUint16(o+6,!0)!==0||a.getUint32(o+16,!0)+a.getUint32(o+12,!0)!==o)throw Error("Incomplete or unsupported Vibemon ZIP");let t=new Map,s=new Set,r=0,f=0,c=new j((i)=>{let l=i.name.endsWith("/"),u=l?i.name.slice(0,-1):i.name;if(!P(u)||s.has(u)||s.size>=44)throw Error("Invalid or duplicate Vibemon ZIP path");if((i.originalSize??0)>g)throw Error("Vibemon ZIP expansion limit exceeded");s.add(u);let p=[],m=0;i.ondata=(x,w,S)=>{if(x)throw x;if(r+=w.length,m+=w.length,r>g||(i.name==="manifest.json"||i.name.endsWith(".json"))&&m>d)throw Error("Vibemon ZIP expansion limit exceeded");if(p.push(w),S){let I=new Uint8Array(m),U=0;for(let V of p)I.set(V,U),U+=V.length;if(l){if(m!==0)throw Error("Invalid Vibemon ZIP directory")}else{if(t.size>=12)throw Error("Too many Vibemon ZIP files");t.set(i.name,I)}f++}},i.start()});c.register(k);for(let i=0;i<e.length;i+=65536)if(c.push(e.subarray(i,i+65536),i+65536>=e.length),i>0&&i%1048576===0)await new Promise((l)=>setTimeout(l,0));if(f!==s.size||s.size!==a.getUint16(o+10,!0)||!t.has("manifest.json"))throw Error("Incomplete Vibemon ZIP");let h=_(t.get("manifest.json")),b=new Set(["manifest.json",...Object.values(h.assets).map((i)=>i.path)]);if([...t.keys()].some((i)=>!b.has(i)))throw Error("Unexpected Vibemon ZIP file");let v=await O(h,(i)=>Promise.resolve(t.get(i)??null),n);return{files:t,manifest:h,layout:v}}export{z as IMAGE_ASSETS,g as PACKAGE_LIMIT,M as imageInfo,_ as parseManifest,P as resourcePath,Z as sha256,L as unpackResourcePackage,O as validatePackageFiles};
@@ -1,30 +1,30 @@
1
1
  import { type PetAssetsHost } from "./host.js";
2
- import type { VibemonCatalogItem } from "./types.js";
3
- export interface SheetLayout {
4
- frameWidth: number;
5
- frameHeight: number;
6
- states: {
7
- id: string;
8
- row: number;
9
- frames: number;
10
- }[];
11
- }
2
+ import { type ImageAsset, type PackageManifest } from "./resource-package.js";
3
+ import { type SheetLayout } from "./sheet-layout.js";
4
+ import type { VibemonResourceDescriptor } from "./types.js";
5
+ export { parseSheetLayout, type SheetLayout } from "./sheet-layout.js";
12
6
  export interface CachedPetMetadata {
13
7
  directory: string;
14
- sheetName: string;
8
+ sheetName: string | null;
15
9
  name?: string;
16
- layout: SheetLayout;
17
- version: number;
10
+ layout: SheetLayout | null;
11
+ version: number | null;
12
+ format?: number;
13
+ sourceUrl?: string | null;
14
+ manifest?: PackageManifest;
15
+ archiveSha256?: string;
18
16
  config?: Record<string, unknown>;
19
17
  }
20
18
  export interface CachedPetResource extends CachedPetMetadata {
21
- sheet: Uint8Array;
19
+ sheet: Uint8Array | null;
22
20
  }
23
- export declare function parseSheetLayout(value: string): SheetLayout;
21
+ export declare function matchesResource(cached: CachedPetMetadata, item: VibemonResourceDescriptor): boolean;
24
22
  export declare function createPetResources(host: PetAssetsHost): {
25
23
  inspect: (petId: string) => Promise<CachedPetMetadata | null>;
24
+ visuals: (metadata: CachedPetMetadata) => Promise<Partial<Record<ImageAsset, string | null>>>;
25
+ preview(metadata: CachedPetMetadata): Promise<Uint8Array<ArrayBufferLike> | null>;
26
26
  cached: (petId: string) => Promise<CachedPetResource | null>;
27
- ensure: (item: VibemonCatalogItem) => Promise<CachedPetResource>;
27
+ ensure: (item: VibemonResourceDescriptor) => Promise<CachedPetResource>;
28
28
  cancel: () => void;
29
29
  dispose(): void;
30
30
  };
@@ -1 +1 @@
1
- import{assertAccount as i}from"./host.js";var I=new TextEncoder,b=new TextDecoder;function v(e){let a=JSON.parse(e);if(!Number.isInteger(a.frameWidth)||a.frameWidth<=0||a.frameHeight!==a.frameWidth||!Array.isArray(a.states)||a.states.length===0||a.states.some((o)=>typeof o.id!=="string"||!o.id||!Number.isInteger(o.row)||o.row<0||!Number.isInteger(o.frames)||o.frames<=0))throw Error("Invalid Vibemon sprite layout");return a}function O(e){let a=!1,o=new Map,g=new Set,h=Promise.resolve();function S(n){if(a)throw Error("Vibemon resources disposed");let r=e.account();if(r===null)throw Error("Sign in to load Vibemon resources");if(!/^[a-zA-Z0-9_-]+$/.test(n)||!/^[a-zA-Z0-9.-]+$/.test(r.apiHost))throw Error("Invalid resource identity");return`vibemon/catalog/${r.apiHost}/${n}`}async function N(n){let r=e.account();if(r===null)throw Error("Sign in to load Vibemon resources");let t=S(n),s=await e.resources.read(`${t}/resource.json`);if(s===null){for(let d of[t,`vibemon/${r.apiHost}/${r.userId}/${n}`]){let f=await e.resources.read(`${d}/config.json`);if(f===null)continue;let u=JSON.parse(b.decode(f));if(!/^sprite-sheet\.(webp|png)$/.test(u.spritesheet))throw Error("Invalid legacy sprite filename");let w=v(JSON.stringify({frameWidth:u.frameSize,frameHeight:u.frameSize,states:u.states}));if(await e.resources.exists(`${d}/${u.spritesheet}`)){let p=await e.storage.get("vibemon.resourceVersion");return i(e,r),{directory:d,sheetName:u.spritesheet,layout:w,version:p?.[r.apiHost]?.[n]??0,config:u}}}return null}let c=JSON.parse(b.decode(s));if(v(JSON.stringify(c.layout)),!/^sprite-sheet\.(webp|png)$/.test(c.sheet))throw Error("Invalid sprite filename");let m=await e.resources.exists(`${t}/${c.sheet}`);i(e,r);let l=await e.resources.read(`${t}/config.json`);return i(e,r),!m?null:{directory:t,sheetName:c.sheet,name:c.name,layout:c.layout,version:c.version,config:l===null?void 0:JSON.parse(b.decode(l))}}async function E(n){let r=e.account();if(r===null)throw Error("Sign in to load Vibemon resources");let t=await N(n);if(t===null)return null;let s=await e.resources.read(`${t.directory}/${t.sheetName}`);return i(e,r),s===null?null:{...t,sheet:s}}async function V(n){let r=e.account();if(r===null)throw Error("Sign in to download Vibemon resources");let t=S(n.uuid),s=t,c=o.get(s);if(c){if(await c,o.get(s)===c)o.delete(s);return i(e,r),V(n)}let m=(async()=>{let l=await E(n.uuid);if(i(e,r),l!==null&&l.version===n.resource_version)return l;let d=v(n.layout),f=new URL(n.sheet_url);if(f.protocol!=="https:")throw Error("Vibemon sprites require HTTPS");let u=f.pathname.toLowerCase().endsWith(".png")?"sprite-sheet.png":"sprite-sheet.webp",w=new AbortController;g.add(w);let p=`${t}.${crypto.randomUUID()}.tmp`;try{let y=await e.download(f.href,w.signal);if(i(e,r),y.byteLength===0)throw Error("Empty Vibemon spritesheet");await e.resources.write(`${p}/${u}`,y),await e.resources.write(`${p}/resource.json`,I.encode(JSON.stringify({layout:d,version:n.resource_version,sheet:u,name:n.name}))),i(e,r),w.signal.throwIfAborted(),await e.resources.replace(p,t),i(e,r);let x=h.catch(()=>{}).then(async()=>{i(e,r);let A=await e.storage.get("vibemon.resourceVersion")??{};i(e,r),await e.storage.set("vibemon.resourceVersion",{...A,[r.apiHost]:{...A[r.apiHost],[n.uuid]:n.resource_version}})});return h=x,await x,i(e,r),{directory:t,sheetName:u,sheet:y,name:n.name,layout:d,version:n.resource_version}}finally{g.delete(w),await e.resources.remove(p)}})();o.set(s,m);try{return await m}finally{if(o.get(s)===m)o.delete(s)}}function H(){for(let n of g)n.abort();g.clear()}return{inspect:N,cached:E,ensure:V,cancel:H,dispose(){a=!0,H()}}}export{O as createPetResources,v as parseSheetLayout};
1
+ import{assertAccount as i}from"./host.js";import{IMAGE_ASSETS as W,imageInfo as q,parseManifest as B,resourcePath as D,sha256 as J,unpackResourcePackage as F,validatePackageFiles as Z}from"./resource-package.js";import{parseSheetLayout as I}from"./sheet-layout.js";import{parseSheetLayout as ne}from"./sheet-layout.js";var R=new TextEncoder,N=new TextDecoder;function G(r,w){let p=w.resource_package_format??0;return(r.format??0)===p&&r.version===(w.resource_version??null)&&(r.sourceUrl===void 0?p===0:r.sourceUrl===(p===1?w.resource_url:w.sheet_url))}function Y(r){let w=!1,p=new Map,_=new Map,V=new Map,S=new Map,k=new Set,O=Promise.resolve();function U(e){if(w)throw Error("Vibemon resources disposed");let o=r.account();if(o===null)throw Error("Sign in to load Vibemon resources");if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9.-]+$/.test(o.apiHost))throw Error("Invalid resource identity");return`vibemon/catalog/${o.apiHost}/${e}`}function P(e){let o=r.account();if(o===null)return Promise.reject(Error("Sign in to load Vibemon resources"));let n=`${U(e)}/${o.userId}/${o.revision}`,a=_.get(n);if(a)return a;let s=H(e).finally(()=>{if(_.get(n)===s)_.delete(n)});return _.set(n,s),s}async function H(e){let o=r.account();if(o===null)throw Error("Sign in to load Vibemon resources");let n=U(e),a=await r.resources.read(`${n}/resource.json`);if(a===null){for(let l of[n,`vibemon/${o.apiHost}/${o.userId}/${e}`]){let f=await r.resources.read(`${l}/config.json`);if(f===null)continue;let t=JSON.parse(N.decode(f));if(!/^sprite-sheet\.(webp|png)$/.test(t.spritesheet))throw Error("Invalid legacy sprite filename");let v=I(JSON.stringify({frameWidth:t.frameSize,frameHeight:t.frameSize,states:t.states}));if(await r.resources.exists(`${l}/${t.spritesheet}`)){let y=await r.storage.get("vibemon.resourceVersion");return i(r,o),{directory:l,sheetName:t.spritesheet,layout:v,version:y?.[o.apiHost]?.[e]??0,config:t}}}return null}let s;try{s=JSON.parse(N.decode(a))}catch{return null}if(!s||s.format!==void 0&&s.format!==0&&s.format!==1)return null;if(s.format===1)try{let l=await r.resources.read(`${n}/manifest.json`),f=await r.resources.read(`${n}/resource.zip`);if(!l||!f||await J(f)!==s.archiveSha256)return null;let t=B(l),v=await Z(t,(y)=>r.resources.read(`${n}/${y}`));return i(r,o),{...s,directory:n,manifest:t,layout:v,sheetName:t.assets.sheet?.path??null}}catch{return i(r,o),null}let c=JSON.parse(N.decode(a));if(I(JSON.stringify(c.layout)),!/^sprite-sheet\.(webp|png)$/.test(c.sheet))throw Error("Invalid sprite filename");let u=await r.resources.exists(`${n}/${c.sheet}`);i(r,o);let g=await r.resources.read(`${n}/config.json`);return i(r,o),!u?null:{directory:n,sheetName:c.sheet,name:c.name,layout:c.layout,version:c.version,format:0,sourceUrl:s.sourceUrl,config:g===null?void 0:JSON.parse(N.decode(g))}}async function L(e){let o=r.account();if(o===null)throw Error("Sign in to load Vibemon resources");let n=await P(e);if(n===null)return null;if(n.sheetName===null)return{...n,sheet:null};let a=await r.resources.read(`${n.directory}/${n.sheetName}`);return i(r,o),a===null?null:{...n,sheet:a}}function M(e){let o=r.account();if(o===null)return Promise.reject(Error("Sign in to download Vibemon resources"));if(e.resource_package_format!=null&&(!Number.isInteger(e.resource_package_format)||e.resource_package_format<0))return Promise.reject(Error("Invalid Vibemon resource format"));if(e.resource_version!=null&&(!Number.isInteger(e.resource_version)||e.resource_version<0))return Promise.reject(Error("Invalid Vibemon resource version"));let n=U(e.uuid),a=JSON.stringify([o.revision,e.resource_package_format??0,e.resource_version??null,e.resource_url,e.sheet_url,e.layout]),s=p.get(n);if(s?.key===a)return s.work;let c=(V.get(n)??0)+1;V.set(n,c);let u=()=>{if(i(r,o),w||V.get(n)!==c)throw Error("Vibemon resource request superseded")},l=(async()=>{await s?.work.catch(()=>{}),u();let f=await L(e.uuid);if(i(r,o),f!==null&&G(f,e))return{...f,name:e.name};let t=e.resource_package_format??0;if(t!==0&&t!==1)throw Error(`Unsupported Vibemon resource format: ${t}`);if(t===1&&!e.resource_url)throw Error("Vibemon package URL is missing");if(t===0&&(!e.sheet_url||!e.layout))throw Error("Vibemon animation is unavailable");let v=t===0?I(e.layout):null,y=new URL(t===1?e.resource_url:e.sheet_url);if(y.protocol!=="https:")throw Error("Vibemon sprites require HTTPS");let j=y.pathname.toLowerCase().endsWith(".png")?"sprite-sheet.png":"sprite-sheet.webp",h=new AbortController;k.add(h);let d=`${n}.${crypto.randomUUID()}.tmp`;try{let b=await r.download(y.href,h.signal);if(u(),t===1){let m=await F(b,r.validateImage);u();for(let[T,C]of m.files)await r.resources.write(`${d}/${T}`,C);await r.resources.write(`${d}/resource.zip`,b);let E={directory:n,format:1,sourceUrl:e.resource_url,version:e.resource_version??null,name:e.name,manifest:m.manifest,layout:m.layout,sheetName:m.manifest.assets.sheet?.path??null,archiveSha256:await J(b)};return await r.resources.write(`${d}/resource.json`,R.encode(JSON.stringify(E))),u(),h.signal.throwIfAborted(),await r.resources.replace(d,n),{...E,sheet:E.sheetName?m.files.get(E.sheetName):null}}if(b.byteLength===0)throw Error("Empty Vibemon spritesheet");await r.resources.write(`${d}/${j}`,b),await r.resources.write(`${d}/resource.json`,R.encode(JSON.stringify({layout:v,version:e.resource_version??null,sheet:j,name:e.name,sourceUrl:e.sheet_url}))),i(r,o),h.signal.throwIfAborted(),u(),await r.resources.replace(d,n),i(r,o);let A=O.catch(()=>{}).then(async()=>{i(r,o);let m=await r.storage.get("vibemon.resourceVersion")??{};i(r,o),await r.storage.set("vibemon.resourceVersion",{...m,[o.apiHost]:{...m[o.apiHost],[e.uuid]:e.resource_version??0}})});return O=A,await A,i(r,o),{directory:n,sheetName:j,sheet:b,name:e.name,layout:v,version:e.resource_version??null,format:0,sourceUrl:e.sheet_url}}finally{k.delete(h),await r.resources.remove(d)}})().finally(()=>{if(p.get(n)?.work===l)p.delete(n)});return p.set(n,{key:a,generation:c,work:l}),l}async function z(e){if(e.format!==1||!e.manifest)return{};let o=e.manifest,n={};return await Promise.all(W.map(async(a)=>{let s=o.assets[a];if(!s){n[a]=null;return}if(!D(s.path))throw Error("Invalid cached Vibemon path");if(r.resources.url)n[a]=`${await r.resources.url(`${e.directory}/${s.path}`)}?v=${s.sha256}`;else{let c=`${e.directory}/${s.sha256}`,u=S.get(c);if(!u){let g=await r.resources.read(`${e.directory}/${s.path}`);if(g===null)throw Error("Cached Vibemon image is missing");u=URL.createObjectURL(new Blob([new Uint8Array(g).buffer],{type:q(g).mime})),S.set(c,u)}n[a]=u}})),n}function x(){for(let e of k)e.abort();k.clear()}return{inspect:P,visuals:z,async preview(e){let o=e.manifest?.assets.cover??e.manifest?.assets.icon;return o?r.resources.read(`${e.directory}/${o.path}`):null},cached:L,ensure:M,cancel:x,dispose(){w=!0,x();for(let e of S.values())URL.revokeObjectURL(e);S.clear()}}}export{Y as createPetResources,G as matchesResource,ne as parseSheetLayout};
@@ -2,6 +2,6 @@ import { type PetAssetsHost } from "./host.js";
2
2
  export declare function createPetSelection(host: PetAssetsHost, owned: (petId: string) => Promise<readonly {
3
3
  vibemon_uuid: string;
4
4
  }[]>): {
5
- get(): Promise<string | null>;
5
+ get: () => Promise<string | null>;
6
6
  select(petId: string | null): Promise<void>;
7
7
  };
@@ -1 +1 @@
1
- import{accountKey as u,assertAccount as c}from"./host.js";function w(n,s){let a=Promise.resolve();return{async get(){let e=n.account();if(e===null)return null;let t=await n.storage.get("vibemon.accounts");return c(n,e),t?.[u(e)]?.pet||null},async select(e){let t=n.account();if(t===null)throw Error("Sign in to select a Vibemon");if(e!==null&&!(await s(e)).some((o)=>o.vibemon_uuid===e))throw Error("This account does not own the selected Vibemon");c(n,t);let r=a.catch(()=>{}).then(async()=>{c(n,t);let o=await n.storage.get("vibemon.accounts")??{};c(n,t);let i=u(t);await n.storage.set("vibemon.accounts",{...o,[i]:{...o[i],pet:e??""}}),c(n,t)});a=r,await r}}}export{w as createPetSelection};
1
+ import{accountKey as u,assertAccount as c}from"./host.js";function w(n,s){let a=Promise.resolve();return{get:async()=>{let e=n.account();if(e===null)return null;let t=await n.storage.get("vibemon.accounts");return c(n,e),t?.[u(e)]?.pet||null},async select(e){let t=n.account();if(t===null)throw Error("Sign in to select a Vibemon");if(e!==null&&!(await s(e)).some((o)=>o.vibemon_uuid===e))throw Error("This account does not own the selected Vibemon");c(n,t);let r=a.catch(()=>{}).then(async()=>{c(n,t);let o=await n.storage.get("vibemon.accounts")??{};c(n,t);let i=u(t);await n.storage.set("vibemon.accounts",{...o,[i]:{...o[i],pet:e??""}}),c(n,t)});a=r,await r}}}export{w as createPetSelection};
@@ -0,0 +1,10 @@
1
+ export interface SheetLayout {
2
+ frameWidth: number;
3
+ frameHeight: number;
4
+ states: {
5
+ id: string;
6
+ row: number;
7
+ frames: number;
8
+ }[];
9
+ }
10
+ export declare function parseSheetLayout(value: string): SheetLayout;
@@ -0,0 +1 @@
1
+ function i(t){let e=JSON.parse(t);if(!e||!Number.isInteger(e.frameWidth)||e.frameWidth<1||e.frameWidth>4096||!Number.isInteger(e.frameHeight)||e.frameHeight<1||e.frameHeight>4096||!Array.isArray(e.states)||e.states.length<1||e.states.length>32||e.states.some((r)=>!r||typeof r.id!=="string"||!r.id||!Number.isInteger(r.row)||r.row<0||!Number.isInteger(r.frames)||r.frames<1||r.frames>128)||new Set(e.states.map((r)=>r.id)).size!==e.states.length||e.states.reduce((r,s)=>r+s.frames,0)>512)throw Error("Invalid Vibemon sprite layout");return e}export{i as parseSheetLayout};
@@ -53,10 +53,11 @@ interface GachaPoolItemBase {
53
53
  updated_time: string;
54
54
  }
55
55
  export interface GachaPoolVibemonItem extends GachaPoolItemBase {
56
- reward_type: "VIBEMON";
56
+ reward_type?: "VIBEMON" | null;
57
57
  exchange_points: null;
58
58
  vibemon_uuid: string;
59
59
  vibemon_name: string;
60
+ vibemon_resource_url?: string | null;
60
61
  vibemon_cover_url: string;
61
62
  vibemon_icon_url: string | null;
62
63
  vibemon_background_url: string | null;
@@ -116,7 +117,7 @@ interface DrawResultItemBase {
116
117
  is_pity_hit: boolean;
117
118
  }
118
119
  export interface VibemonDrawResultItem extends DrawResultItemBase {
119
- reward_type: "VIBEMON";
120
+ reward_type?: "VIBEMON" | null;
120
121
  exchange_points: null;
121
122
  vibemon_uuid: string;
122
123
  vibemon_name: string;
@@ -165,7 +166,22 @@ export interface DrawResponse {
165
166
  results: DrawResultItem[];
166
167
  state: UserGachaStateResponse;
167
168
  }
169
+ export interface VibemonResourceDescriptor {
170
+ uuid: string;
171
+ name: string;
172
+ resource_url?: string | null;
173
+ resource_package_format?: number | null;
174
+ resource_version?: number | null;
175
+ sheet_url?: string | null;
176
+ layout?: string | null;
177
+ }
168
178
  export interface MyVibemonItem {
179
+ resource_url?: string | null;
180
+ resource_package_format?: number | null;
181
+ resource_version?: number | null;
182
+ sheet_url?: string | null;
183
+ layout?: string | null;
184
+ multi_draw_url?: string | null;
169
185
  vibemon_uuid: string;
170
186
  name: string;
171
187
  description: string | null;
@@ -187,7 +203,7 @@ export interface MyVibemonItem {
187
203
  obtained_time: string;
188
204
  duplicate_count: number;
189
205
  }
190
- export interface VibemonCatalogItem {
206
+ export interface VibemonCatalogItem extends VibemonResourceDescriptor {
191
207
  uuid: string;
192
208
  name: string;
193
209
  description: string | null;
@@ -205,16 +221,12 @@ export interface VibemonCatalogItem {
205
221
  sidebar_selected_url: string | null;
206
222
  sidebar_hover_url: string | null;
207
223
  sidebar_unselected_url: string | null;
208
- resource_url: string;
209
- sheet_url: string;
210
- layout: string;
211
- resource_version: number;
212
224
  is_limited: number;
213
225
  status: number;
214
226
  }
215
227
  export interface GetMyVibemonsParams {
216
- rarity_uuid?: string;
217
- category_uuid?: string;
228
+ rarityUuid?: string;
229
+ categoryUuid?: string;
218
230
  equipped?: boolean;
219
231
  scene?: string;
220
232
  }
package/dist/state.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { AuthUser, LoginResponse } from "./types.js";
2
1
  import type { createTokenStorage } from "./token-storage.js";
2
+ import type { AuthUser, LoginResponse } from "./types.js";
3
3
  export interface AuthState {
4
4
  user: AuthUser | null;
5
5
  isAuthenticated: boolean;
package/dist/state.js CHANGED
@@ -1 +1 @@
1
- function w(e){let{tokenStorage:l,loadUser:d,saveUser:s,clearAllAuth:f}=e.storage,n=0;return(r,c)=>({user:null,isAuthenticated:!1,isLoading:!0,_initialized:!1,init:()=>{if(c()._initialized)return;r({_initialized:!0}),e.onInit();let a=n;(async()=>{try{let i=await l.getAccess(),t=await l.getRefresh();if(a!==n)return;if(!i||!t){await e.handleUnauthenticated(),r({isLoading:!1});return}let v=e.validateProfile(),o=await d();if(a!==n)return;if(!v){if(o)r({user:o,isAuthenticated:!0}),e.loadProviders();return}if(o)r({user:o,isAuthenticated:!0,isLoading:!1}),e.onSignedIn(o,"restore");e.loadProviders();try{let u=await e.getProfile();if(a!==n)return;let g={user_uuid:u.uuid,nickname:u.nickname,login_email:u.login_email,avatar:u.avatar};r({user:g,isAuthenticated:!0}),await s(g),e.onProfileRestored()}catch{let u=await d();if(a!==n)return;if(u)r({user:u,isAuthenticated:!0});else await f(),e.clearProviders(),r({user:null,isAuthenticated:!1})}if(!o)r({isLoading:!1})}catch(i){console.error("[auth] session restore failed unexpectedly",i)}finally{if(c().isLoading)r({isLoading:!1})}})(),e.subscribeExpired(()=>{n++,e.clearAccountConversation(c().user).then(e.handleUnauthenticated).then((i)=>{if(i)return;r({user:null,isAuthenticated:!1})})}),e.subscribeState((i)=>{if(i.action==="logout")n++,e.clearAccountConversation(c().user).then(e.handleUnauthenticated).then((t)=>{if(t)return;e.clearProviders(),r({user:null,isAuthenticated:!1})});else if(i.action==="login"&&i.user)n++,r({user:i.user,isAuthenticated:!0}),e.loadProviders();else if(i.action==="update"&&i.user)r({user:i.user})})},login:async(a)=>{n++,await l.save(a.access_token,a.refresh_token);let i={user_uuid:a.user_uuid,nickname:a.nickname,login_email:a.login_email};await s(i),r({user:i,isAuthenticated:!0}),e.loadProviders(),await e.broadcast({action:"login",user:i}),e.onSignedIn(i,"login")},logout:async()=>{if(n++,e.clearProviders(),await e.logoutApi(),await e.clearAccountConversation(c().user),await f(),await e.broadcast({action:"logout"}),await e.handleUnauthenticated())return;r({user:null,isAuthenticated:!1})},refreshUser:async()=>{try{let a=await e.getProfile(),i={user_uuid:a.uuid,nickname:a.nickname,login_email:a.login_email,avatar:a.avatar};r({user:i}),await s(i)}catch(a){console.warn("[auth] refreshUser failed",a)}},updateUser:(a)=>{let i=c().user;if(!i)return;let t={...i,...a};r({user:t}),s(t),e.broadcast({action:"update",user:t})}})}export{w as createAuthState};
1
+ function w(e){let{tokenStorage:l,loadUser:d,saveUser:s,clearAllAuth:f}=e.storage,n=0;return(r,o)=>({user:null,isAuthenticated:!1,isLoading:!0,_initialized:!1,init:()=>{if(o()._initialized)return;r({_initialized:!0}),e.onInit();let a=n;(async()=>{try{let i=await l.getAccess(),t=await l.getRefresh();if(a!==n)return;if(!i||!t){await e.handleUnauthenticated(),r({isLoading:!1});return}let v=e.validateProfile(),c=await d();if(a!==n)return;if(!v){if(c)r({user:c,isAuthenticated:!0}),e.loadProviders();return}if(c)r({user:c,isAuthenticated:!0,isLoading:!1}),e.onSignedIn(c,"restore");e.loadProviders();try{let u=await e.getProfile();if(a!==n)return;let g={user_uuid:u.uuid,nickname:u.nickname,login_email:u.login_email,avatar:u.avatar};r({user:g,isAuthenticated:!0}),await s(g),e.onProfileRestored()}catch{let u=await d();if(a!==n)return;if(u)r({user:u,isAuthenticated:!0});else await f(),e.clearProviders(),r({user:null,isAuthenticated:!1})}if(!c)r({isLoading:!1})}catch(i){console.error("[auth] session restore failed unexpectedly",i)}finally{if(o().isLoading)r({isLoading:!1})}})(),e.subscribeExpired(()=>{n++,e.clearAccountConversation(o().user).then(e.handleUnauthenticated).then((i)=>{if(i)return;r({user:null,isAuthenticated:!1})})}),e.subscribeState((i)=>{if(i.action==="logout")n++,e.clearAccountConversation(o().user).then(e.handleUnauthenticated).then((t)=>{if(t)return;e.clearProviders(),r({user:null,isAuthenticated:!1})});else if(i.action==="login"&&i.user)n++,r({user:i.user,isAuthenticated:!0}),e.loadProviders();else if(i.action==="update"&&i.user)r({user:i.user})})},login:async(a)=>{n++,await l.save(a.access_token,a.refresh_token);let i={user_uuid:a.user_uuid,nickname:a.nickname,login_email:a.login_email};await s(i),r({user:i,isAuthenticated:!0}),e.loadProviders(),await e.broadcast({action:"login",user:i}),e.onSignedIn(i,"login")},logout:async()=>{if(n++,e.clearProviders(),await e.logoutApi(),await e.clearAccountConversation(o().user),await f(),await e.broadcast({action:"logout"}),await e.handleUnauthenticated())return;r({user:null,isAuthenticated:!1})},refreshUser:async()=>{try{let a=await e.getProfile(),i={user_uuid:a.uuid,nickname:a.nickname,login_email:a.login_email,avatar:a.avatar};r({user:i}),await s(i)}catch(a){console.warn("[auth] refreshUser failed",a)}},updateUser:(a)=>{let i=o().user;if(!i)return;let t={...i,...a};r({user:t}),s(t),e.broadcast({action:"update",user:t})}})}export{w as createAuthState};
@@ -1,18 +1,18 @@
1
1
  import type { AuthUser } from "./types.js";
2
2
  export interface AuthStore {
3
- get<T>(key: string): Promise<T | undefined>;
4
- set(key: string, value: unknown): Promise<void>;
5
- delete(key: string): Promise<void>;
3
+ get: <T>(key: string) => Promise<T | undefined>;
4
+ set: (key: string, value: unknown) => Promise<void>;
5
+ delete: (key: string) => Promise<void>;
6
6
  }
7
7
  export declare function authStoreName(apiBaseUrl: string): string;
8
8
  export declare function createTokenStorage(store: AuthStore): {
9
9
  tokenStorage: {
10
- save(accessToken: string, refreshToken: string): Promise<void>;
11
- getAccess(): Promise<string>;
12
- getRefresh(): Promise<string>;
13
- updateAccess(token: string): Promise<void>;
14
- clear(): Promise<void>;
15
- getDeviceId(): Promise<string>;
10
+ save: (accessToken: string, refreshToken: string) => Promise<void>;
11
+ getAccess: () => Promise<string>;
12
+ getRefresh: () => Promise<string>;
13
+ updateAccess: (token: string) => Promise<void>;
14
+ clear: () => Promise<void>;
15
+ getDeviceId: () => Promise<string>;
16
16
  };
17
17
  saveUser: (user: AuthUser) => Promise<void>;
18
18
  loadUser: () => Promise<AuthUser | null>;
@@ -1 +1 @@
1
- function r(a){return`auth.${new URL(a).host}`}function u(a){let e={ACCESS:"access_token",REFRESH:"refresh_token",DEVICE_ID:"device_id",USER:"user"},n={async save(t,S){await a.set(e.ACCESS,t),await a.set(e.REFRESH,S)},async getAccess(){return await a.get(e.ACCESS)??""},async getRefresh(){return await a.get(e.REFRESH)??""},async updateAccess(t){await a.set(e.ACCESS,t)},async clear(){await a.delete(e.ACCESS),await a.delete(e.REFRESH)},async getDeviceId(){let t=await a.get(e.DEVICE_ID);if(!t)t=crypto.randomUUID(),await a.set(e.DEVICE_ID,t);return t}};async function i(t){await a.set(e.USER,t)}async function E(){return await a.get(e.USER)??null}async function c(){await a.delete(e.USER)}async function s(){await n.clear(),await c()}return{tokenStorage:n,saveUser:i,loadUser:E,clearUser:c,clearAllAuth:s}}export{r as authStoreName,u as createTokenStorage};
1
+ function r(a){return`auth.${new URL(a).host}`}function u(a){let e={ACCESS:"access_token",REFRESH:"refresh_token",DEVICE_ID:"device_id",USER:"user"},n={save:async(t,S)=>{await a.set(e.ACCESS,t),await a.set(e.REFRESH,S)},getAccess:async()=>await a.get(e.ACCESS)??"",getRefresh:async()=>await a.get(e.REFRESH)??"",updateAccess:async(t)=>{await a.set(e.ACCESS,t)},clear:async()=>{await a.delete(e.ACCESS),await a.delete(e.REFRESH)},getDeviceId:async()=>{let t=await a.get(e.DEVICE_ID);if(!t)t=crypto.randomUUID(),await a.set(e.DEVICE_ID,t);return t}};async function i(t){await a.set(e.USER,t)}async function E(){return await a.get(e.USER)??null}async function c(){await a.delete(e.USER)}async function s(){await n.clear(),await c()}return{tokenStorage:n,saveUser:i,loadUser:E,clearUser:c,clearAllAuth:s}}export{r as authStoreName,u as createTokenStorage};
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arjun Barrett
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwith/module-auth",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -71,7 +71,7 @@
71
71
  ],
72
72
  "devDependencies": {
73
73
  "typescript": "^7.0.2",
74
- "@types/bun": "^1.4.2",
74
+ "@types/bun": "^1.4.3",
75
75
  "@types/react": "^19.3.0",
76
76
  "@types/react-dom": "^19.3.0"
77
77
  },
@@ -94,11 +94,12 @@
94
94
  "dependencies": {
95
95
  "@base-ui/react": "^1.8.0",
96
96
  "class-variance-authority": "^0.7.1",
97
- "cn": "^0.4.0",
97
+ "cn": "^0.5.0",
98
+ "fflate": "0.8.3",
99
+ "i18next": "^26.4.2",
98
100
  "lucide-react": "^1.49.0",
99
101
  "motion": "^13.4.6",
100
102
  "react-i18next": "^17.0.15",
101
- "i18next": "^26.4.2",
102
103
  "sonner": "^2.0.8",
103
104
  "zustand": "^5.0.15"
104
105
  },