digital-boardgame-framework 0.4.0 → 0.5.0

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.
@@ -1,3 +1,7 @@
1
1
  export { useGame } from './use-game.js';
2
2
  export type { UseGameOpts, UseGameResult, GameClientApi } from './use-game.js';
3
+ export { useVersionCheck } from './use-version-check.js';
4
+ export type { UseVersionCheckOpts, UseVersionCheckResult } from './use-version-check.js';
5
+ export { UpdateBanner } from './update-banner.js';
6
+ export type { UpdateBannerProps } from './update-banner.js';
3
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,2 +1,4 @@
1
1
  export { useGame } from './use-game.js';
2
+ export { useVersionCheck } from './use-version-check.js';
3
+ export { UpdateBanner } from './update-banner.js';
2
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { CSSProperties } from 'react';
2
+ import { type UseVersionCheckOpts } from './use-version-check.js';
3
+ /**
4
+ * Drop-in "a new version is available — Reload" banner. Renders nothing until a
5
+ * newer build is deployed, then shows a dismissible bar. Built on
6
+ * `useVersionCheck`; pass the same options. Restyle via `className`/`style`, or
7
+ * skip this component entirely and build your own UI on the hook.
8
+ *
9
+ * <UpdateBanner currentBuild={__DBF_BUILD_ID__} />
10
+ */
11
+ export interface UpdateBannerProps extends UseVersionCheckOpts {
12
+ message?: string;
13
+ reloadLabel?: string;
14
+ /** Hide the default styling (so `className` fully controls appearance). */
15
+ unstyled?: boolean;
16
+ className?: string;
17
+ style?: CSSProperties;
18
+ }
19
+ export declare function UpdateBanner({ message, reloadLabel, unstyled, className, style, ...opts }: UpdateBannerProps): import("react/jsx-runtime").JSX.Element | null;
20
+ //# sourceMappingURL=update-banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-banner.d.ts","sourceRoot":"","sources":["../../src/client/update-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAiBD,wBAAgB,YAAY,CAAC,EAC3B,OAAuC,EACvC,WAAsB,EACtB,QAAgB,EAChB,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,iBAAiB,kDAcnB"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useVersionCheck } from './use-version-check.js';
3
+ const barStyle = {
4
+ position: 'fixed', left: 0, right: 0, bottom: 0, zIndex: 9999,
5
+ display: 'flex', gap: 12, alignItems: 'center', justifyContent: 'center',
6
+ padding: '10px 14px', background: '#1d1830', color: '#e8e6f2',
7
+ borderTop: '1px solid #ffffff22', fontFamily: 'system-ui, sans-serif', fontSize: 14,
8
+ };
9
+ const reloadBtn = {
10
+ background: '#5a3380', color: 'white', border: 'none', borderRadius: 6,
11
+ padding: '6px 14px', fontSize: 14, cursor: 'pointer',
12
+ };
13
+ const closeBtn = {
14
+ background: 'transparent', color: '#aab', border: 'none', fontSize: 18,
15
+ cursor: 'pointer', lineHeight: 1,
16
+ };
17
+ export function UpdateBanner({ message = 'A new version is available.', reloadLabel = 'Reload', unstyled = false, className, style, ...opts }) {
18
+ const { updateAvailable, reload, dismiss } = useVersionCheck(opts);
19
+ if (!updateAvailable)
20
+ return null;
21
+ return (_jsxs("div", { role: "status", className: className, style: unstyled ? style : { ...barStyle, ...style }, children: [_jsx("span", { children: message }), _jsx("button", { type: "button", onClick: reload, style: unstyled ? undefined : reloadBtn, children: reloadLabel }), _jsx("button", { type: "button", onClick: dismiss, "aria-label": "Dismiss", style: unstyled ? undefined : closeBtn, children: "\u00D7" })] }));
22
+ }
23
+ //# sourceMappingURL=update-banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-banner.js","sourceRoot":"","sources":["../../src/client/update-banner.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAA4B,MAAM,wBAAwB,CAAC;AAmBnF,MAAM,QAAQ,GAAkB;IAC9B,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI;IAC7D,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ;IACxE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS;IAC7D,SAAS,EAAE,qBAAqB,EAAE,UAAU,EAAE,uBAAuB,EAAE,QAAQ,EAAE,EAAE;CACpF,CAAC;AACF,MAAM,SAAS,GAAkB;IAC/B,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACtE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS;CACrD,CAAC;AACF,MAAM,QAAQ,GAAkB;IAC9B,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IACtE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,EAC3B,OAAO,GAAG,6BAA6B,EACvC,WAAW,GAAG,QAAQ,EACtB,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACW;IAClB,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACnE,IAAI,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,CACL,eAAK,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,aAC1F,yBAAO,OAAO,GAAQ,EACtB,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAC3E,WAAW,GACL,EACT,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,gBAAa,SAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,uBAE1F,IACL,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Detects when a newer build of the app has been deployed while a tab is still
3
+ * running an old one, so the app can prompt the user to reload. Pairs with the
4
+ * `versionStamp` Vite plugin (digital-boardgame-framework/vite), which injects
5
+ * the running build id and emits the `version.json` this hook polls.
6
+ *
7
+ * Why: a long-lived open tab never re-requests the page, so it keeps running
8
+ * stale JS after a deploy — users then report already-fixed bugs. This polls a
9
+ * small uncached `version.json` on tab-refocus (the high-value trigger) and on
10
+ * an interval, and flips `updateAvailable` when the deployed build differs from
11
+ * the one this tab is running.
12
+ */
13
+ export interface UseVersionCheckOpts {
14
+ /** The build id this running bundle was built with — pass the value the
15
+ * `versionStamp` plugin injected (default global `__DBF_BUILD_ID__`). */
16
+ currentBuild: string;
17
+ /** URL of the published version manifest. Default `/version.json`. */
18
+ url?: string;
19
+ /** Poll interval in ms. Default 5 min. `<= 0` disables interval polling
20
+ * (refocus checks still run). */
21
+ intervalMs?: number;
22
+ /** Also check whenever the tab becomes visible again. Default true. */
23
+ checkOnFocus?: boolean;
24
+ /** Auto-reload on Vite's `vite:preloadError` — a lazy import() hitting a
25
+ * now-404'd old chunk after a deploy. Default true. */
26
+ reloadOnChunkError?: boolean;
27
+ }
28
+ export interface UseVersionCheckResult {
29
+ /** True when a different build is live and the user hasn't dismissed it. */
30
+ updateAvailable: boolean;
31
+ currentBuild: string;
32
+ /** The latest deployed build id seen, or null before the first successful check. */
33
+ latestBuild: string | null;
34
+ /** Hard-reload the page onto the new build. */
35
+ reload: () => void;
36
+ /** Hide the prompt for the current `latestBuild` (re-appears if a newer one ships). */
37
+ dismiss: () => void;
38
+ }
39
+ export declare function useVersionCheck(opts: UseVersionCheckOpts): UseVersionCheckResult;
40
+ //# sourceMappingURL=use-version-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-version-check.d.ts","sourceRoot":"","sources":["../../src/client/use-version-check.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,mBAAmB;IAClC;8EAC0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;sCACkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;4DACwD;IACxD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,uFAAuF;IACvF,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,qBAAqB,CAiEhF"}
@@ -0,0 +1,63 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ export function useVersionCheck(opts) {
3
+ const { currentBuild, url = '/version.json', intervalMs = 5 * 60 * 1000, checkOnFocus = true, reloadOnChunkError = true, } = opts;
4
+ const [latestBuild, setLatestBuild] = useState(null);
5
+ const [dismissed, setDismissed] = useState(null);
6
+ const currentRef = useRef(currentBuild);
7
+ currentRef.current = currentBuild;
8
+ useEffect(() => {
9
+ if (typeof document === 'undefined')
10
+ return;
11
+ let cancelled = false;
12
+ async function check() {
13
+ try {
14
+ // Cache-bust the query AND request no-store so neither the browser nor
15
+ // an edge CDN serves a stale manifest.
16
+ const r = await fetch(`${url}?_=${Date.now()}`, { cache: 'no-store' });
17
+ if (!r.ok)
18
+ return;
19
+ const data = (await r.json().catch(() => null));
20
+ if (!cancelled && data && typeof data.build === 'string')
21
+ setLatestBuild(data.build);
22
+ }
23
+ catch {
24
+ // offline / transient — ignore; we'll try again next tick.
25
+ }
26
+ }
27
+ check();
28
+ let id;
29
+ if (intervalMs > 0)
30
+ id = setInterval(check, intervalMs);
31
+ const onVisible = () => { if (document.visibilityState === 'visible')
32
+ check(); };
33
+ if (checkOnFocus)
34
+ document.addEventListener('visibilitychange', onVisible);
35
+ const onPreloadError = () => { if (typeof location !== 'undefined')
36
+ location.reload(); };
37
+ if (reloadOnChunkError && typeof window !== 'undefined') {
38
+ window.addEventListener('vite:preloadError', onPreloadError);
39
+ }
40
+ return () => {
41
+ cancelled = true;
42
+ if (id)
43
+ clearInterval(id);
44
+ if (checkOnFocus)
45
+ document.removeEventListener('visibilitychange', onVisible);
46
+ if (reloadOnChunkError && typeof window !== 'undefined') {
47
+ window.removeEventListener('vite:preloadError', onPreloadError);
48
+ }
49
+ };
50
+ }, [url, intervalMs, checkOnFocus, reloadOnChunkError]);
51
+ const updateAvailable = latestBuild !== null &&
52
+ latestBuild !== currentRef.current &&
53
+ latestBuild !== dismissed;
54
+ return {
55
+ updateAvailable,
56
+ currentBuild,
57
+ latestBuild,
58
+ reload: () => { if (typeof location !== 'undefined')
59
+ location.reload(); },
60
+ dismiss: () => setDismissed(latestBuild),
61
+ };
62
+ }
63
+ //# sourceMappingURL=use-version-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-version-check.js","sourceRoot":"","sources":["../../src/client/use-version-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { versionStamp } from './version-stamp.js';
2
+ export type { VersionStampOpts, VersionStampPlugin } from './version-stamp.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { versionStamp } from './version-stamp.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /** Minimal structural subset of Vite's `Plugin` — avoids a `vite` dependency.
2
+ * The returned object is structurally a valid Vite plugin. */
3
+ export interface VersionStampPlugin {
4
+ name: string;
5
+ config(): {
6
+ define: Record<string, string>;
7
+ };
8
+ configResolved(resolved: {
9
+ build?: {
10
+ outDir?: string;
11
+ };
12
+ }): void;
13
+ closeBundle(): void;
14
+ }
15
+ export interface VersionStampOpts {
16
+ /** Build id to stamp. Default: `git rev-parse --short HEAD`, or `dev-<rand>`. */
17
+ buildId?: string;
18
+ /** Global name to define the build id under. Default `__DBF_BUILD_ID__`. */
19
+ define?: string;
20
+ /** Manifest filename written into the build output dir. Default `version.json`. */
21
+ fileName?: string;
22
+ /** Override the output dir (otherwise taken from Vite's resolved config). */
23
+ outDir?: string;
24
+ }
25
+ export declare function versionStamp(opts?: VersionStampOpts): VersionStampPlugin;
26
+ //# sourceMappingURL=version-stamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-stamp.d.ts","sourceRoot":"","sources":["../../src/vite/version-stamp.ts"],"names":[],"mappings":"AAaA;+DAC+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAC7C,cAAc,CAAC,QAAQ,EAAE;QAAE,KAAK,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAChE,WAAW,IAAI,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,YAAY,CAAC,IAAI,GAAE,gBAAqB,GAAG,kBAAkB,CAwB5E"}
@@ -0,0 +1,46 @@
1
+ // Build-time half of the update-banner feature. Node-only (used in
2
+ // vite.config); never imported by app/runtime code.
3
+ //
4
+ // `versionStamp()` does two things:
5
+ // 1. injects a build id as a global define (default `__DBF_BUILD_ID__`) so the
6
+ // running bundle knows which build it is, and
7
+ // 2. writes `<outDir>/version.json` = { build, time } at the end of the build,
8
+ // which `useVersionCheck` polls to detect that a newer build is live.
9
+ import { execSync } from 'node:child_process';
10
+ import { writeFileSync, mkdirSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ function defaultBuildId() {
13
+ try {
14
+ return execSync('git rev-parse --short HEAD', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
15
+ }
16
+ catch {
17
+ return 'dev-' + Math.random().toString(36).slice(2, 9);
18
+ }
19
+ }
20
+ export function versionStamp(opts = {}) {
21
+ const buildId = opts.buildId ?? defaultBuildId();
22
+ const defineName = opts.define ?? '__DBF_BUILD_ID__';
23
+ const fileName = opts.fileName ?? 'version.json';
24
+ let outDir = opts.outDir ?? 'dist';
25
+ const builtAt = new Date().toISOString();
26
+ return {
27
+ name: 'dbf:version-stamp',
28
+ config() {
29
+ return { define: { [defineName]: JSON.stringify(buildId) } };
30
+ },
31
+ configResolved(resolved) {
32
+ if (!opts.outDir && resolved.build?.outDir)
33
+ outDir = resolved.build.outDir;
34
+ },
35
+ closeBundle() {
36
+ try {
37
+ mkdirSync(outDir, { recursive: true });
38
+ writeFileSync(join(outDir, fileName), JSON.stringify({ build: buildId, time: builtAt }));
39
+ }
40
+ catch {
41
+ // best-effort — a failed stamp shouldn't fail the build
42
+ }
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=version-stamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-stamp.js","sourceRoot":"","sources":["../../src/vite/version-stamp.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,oDAAoD;AACpD,EAAE;AACF,oCAAoC;AACpC,iFAAiF;AACjF,mDAAmD;AACnD,iFAAiF;AACjF,2EAA2E;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,4BAA4B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAyB,EAAE;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,kBAAkB,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,cAAc,CAAC;IACjD,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,MAAM;YACJ,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAC/D,CAAC;QACD,cAAc,CAAC,QAAQ;YACrB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;QAC7E,CAAC;QACD,WAAW;YACT,IAAI,CAAC;gBACH,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAC3F,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;YAC1D,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "digital-boardgame-framework",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Foundation library for turn-based digital boardgames: deterministic engine plumbing, async multiplayer, agent-friendly bug triage.",
5
5
  "keywords": ["boardgame", "board-game", "multiplayer", "async-multiplayer", "turn-based", "game-framework", "supabase", "cloudflare-pages"],
6
6
  "author": "John Champaign",
@@ -27,6 +27,10 @@
27
27
  "./client": {
28
28
  "types": "./dist/client/index.d.ts",
29
29
  "import": "./dist/client/index.js"
30
+ },
31
+ "./vite": {
32
+ "types": "./dist/vite/index.d.ts",
33
+ "import": "./dist/vite/index.js"
30
34
  }
31
35
  },
32
36
  "files": ["dist", "supabase/schema.sql"],