@puzzmo/sdk 1.0.19 → 1.0.21
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.
package/dist/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./asyncToGenerator-BlxRHn40.cjs`),l=require(`./objectSpread2-B6tAAMuy.cjs`);let u=require(`vite`),d=require(`path`);d=s(d);let f=require(`fs`);f=s(f);function p(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function m(e,t){if(e==null)return{};var n,r,i=p(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var h=[`fixturesGlob`],g=`/@puzzmo-simulator-init.js`,_=`virtual:puzzmo-simulator`;function v(e){let t=new Map,n=
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./asyncToGenerator-BlxRHn40.cjs`),l=require(`./objectSpread2-B6tAAMuy.cjs`);let u=require(`vite`),d=require(`path`);d=s(d);let f=require(`fs`);f=s(f);function p(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function m(e,t){if(e==null)return{};var n,r,i=p(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var h=[`fixturesGlob`],g=`/@puzzmo-simulator-init.js`,_=`virtual:puzzmo-simulator`;function v(e){let t=new Map,n=D(e,3);f.default.existsSync(d.default.join(e,`puzzmo.json`))&&n.unshift(e);for(let i of n)try{var r;let n=JSON.parse(f.default.readFileSync(d.default.join(i,`puzzmo.json`),`utf-8`));if(!(!(n==null||(r=n.game)==null)&&r.slug))continue;let a=w(i,`src/appBundle`),o=null;a&&(o=`/`+d.default.relative(e,a).split(d.default.sep).join(`/`)),t.set(n.game.slug,{dir:i,slug:n.game.slug,displayName:n.game.displayName,appBundlePath:o})}catch(e){}return t}function y(e,t,n){if(e)try{let r=new URL(e).pathname;for(let e of t.values()){let t=`/`+d.default.relative(n,e.dir).split(d.default.sep).join(`/`);if(r.startsWith(t+`/`)||r===t)return e}}catch(e){}if(t.size===1)return t.values().next().value}function b(e,t){let{fixturesGlob:n}=e,r=m(e,h),i=n===!1?null:n==null?`/fixtures/puzzles/**/*.json`:n,a=[`import { createSimulator } from "@puzzmo/sdk/simulator"`];i&&a.push(`const fixtures = import.meta.glob(${JSON.stringify(i)}, { eager: true })`),t!=null&&t.appBundlePath&&(a.push(`import(${JSON.stringify(t.appBundlePath)}).then(m => {`),a.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`),a.push(`}).catch(() => {})`));let o=l.t(l.t({},r),t!=null&&t.slug?{slug:t.slug}:{}),s=Object.entries(o).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}: ${JSON.stringify(t)}`);return i&&s.push(`fixtures`),a.push(`createSimulator({ ${s.join(`, `)} })`),a.join(`
|
|
2
2
|
`)}function x(e={}){let t=new Map,n;return{name:`puzzmo-simulator`,apply:`serve`,configResolved(e){if(n=e.root,t=v(n),t.size===0)e.logger.info(`\x1B[33m\x1B[1m PUZZMO \x1B[22m\x1B[39m\x1B[2m no puzzmo.json files found\x1B[22m`);else{let n=[...t.values()].map(e=>`\x1b[36m${e.slug}\x1b[39m`),r=t.size===1?`game`:`games`;e.logger.info(`\x1b[33m\x1b[1m PUZZMO \x1b[22m\x1b[39m found ${t.size} ${r}: ${n.join(`\x1B[2m, \x1B[22m`)}`)}},resolveId(e){if(e===_||e.startsWith(_+`?`))return`\0`+e},load(n){if(!n.startsWith(`\0`+_))return;let r=new URLSearchParams(n.split(`?`)[1]||``).get(`game`);return b(e,r?t.get(r):t.size===1?t.values().next().value:void 0)},configureServer(e){e.middlewares.use(`/oauth/callback`,(e,t)=>{t.setHeader(`Content-Type`,`text/html`),t.end(`<!DOCTYPE html>
|
|
3
3
|
<html><head><title>Puzzmo OAuth</title></head>
|
|
4
4
|
<body><script>
|
|
@@ -7,5 +7,5 @@ var returnUrl = sessionStorage.getItem("oauth_return_url") || "/";
|
|
|
7
7
|
var url = new URL(returnUrl);
|
|
8
8
|
params.forEach(function(v, k) { url.searchParams.set(k, v); });
|
|
9
9
|
window.location.href = url.toString();
|
|
10
|
-
<\/script></body></html>`)}),e.middlewares.use(function(){var r=c.t(function*(r,i,a){var o;if(((o=r.url)==null?void 0:o.split(`?`)[0])!==g)return a();let s=y(r.headers.referer,t,n),c=_+(s?`?game=${s.slug}`:``),l=yield e.transformRequest(c);if(!l)return a();i.setHeader(`Content-Type`,`application/javascript`),i.end(l.code)});return function(e,t,n){return r.apply(this,arguments)}}())},transformIndexHtml(){return[{tag:`script`,attrs:{type:`module`,src:g},injectTo:`head`}]}}}function S(e,t){return(n={})=>{let{entry:r,outputFile:i}=l.t(l.t({},t),n);return{name:e,apply:`build`,closeBundle(){return c.t(function*(){try{yield(0,u.build)({configFile:!1,logLevel:`warn`,build:{lib:{entry:
|
|
10
|
+
<\/script></body></html>`)}),e.middlewares.use(function(){var r=c.t(function*(r,i,a){var o;if(((o=r.url)==null?void 0:o.split(`?`)[0])!==g)return a();let s=y(r.headers.referer,t,n),c=_+(s?`?game=${s.slug}`:``),l=yield e.transformRequest(c);if(!l)return a();i.setHeader(`Content-Type`,`application/javascript`),i.end(l.code)});return function(e,t,n){return r.apply(this,arguments)}}())},transformIndexHtml(){return[{tag:`script`,attrs:{type:`module`,src:g},injectTo:`head`}]}}}function S(e,t){return(n={})=>{let{entry:r,outputFile:i}=l.t(l.t({},t),n);return{name:e,apply:`build`,closeBundle(){return c.t(function*(){var t;let a=n.entry?d.default.isAbsolute(r)?r:d.default.resolve(process.cwd(),r):(t=w(process.cwd(),C(r)))==null?d.default.resolve(process.cwd(),r):t;try{yield(0,u.build)({configFile:!1,logLevel:`warn`,build:{lib:{entry:a,formats:[`es`],fileName:()=>i},outDir:`dist`,emptyOutDir:!1}})}catch(t){throw console.error(`[${e}] build failed:`,t),t}})()}}}}var C=e=>e.replace(/\.[jt]sx?$/i,``),w=(e,t)=>{for(let n of[`.js`,`.ts`]){let r=d.default.join(e,t+n);if(f.default.existsSync(r))return r}return null};const T=S(`app-bundle`,{entry:`src/appBundle.js`,outputFile:`app-bundle.js`}),E=S(`editor-bundle`,{entry:`src/editorBundle.js`,outputFile:`editor-bundle.js`}),D=(e,t,n=0)=>{if(n>=t)return[];let r=[],i;try{i=f.default.readdirSync(e,{withFileTypes:!0})}catch(e){return r}for(let a of i){if(!a.isDirectory()||a.name.startsWith(`.`)||a.name===`node_modules`)continue;let i=d.default.join(e,a.name);f.default.existsSync(d.default.join(i,`puzzmo.json`))&&r.push(i),r.push(...D(i,t,n+1))}return r};exports.appBundlePlugin=T,exports.discoverGames=v,exports.editorBundlePlugin=E,exports.findPuzzmoJsonDirs=D,exports.generateSimulatorCode=b,exports.puzzmoSimulator=x,exports.resolveGameFromReferer=y,exports.t=s;
|
|
11
11
|
//# sourceMappingURL=vite.cjs.map
|
package/dist/vite.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.cjs","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\nimport fs from \"fs\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /**\n * Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to\n * `\"/fixtures/puzzles/**\\/*.json\"`. Pass false to disable.\n */\n fixturesGlob?: string | false\n}\n\nconst simulatorURL = \"/@puzzmo-simulator-init.js\"\nconst virtualID = \"virtual:puzzmo-simulator\"\n\n/** @internal */\nexport type GameInfo = {\n /** Directory containing the puzzmo.json */\n dir: string\n slug: string\n displayName: string\n /** Vite-root-relative path to app bundle entry, if it exists */\n appBundlePath: string | null\n}\n\n/**\n * Discover all games from puzzmo.json files under a root directory.\n *\n * @internal\n */\nexport function discoverGames(viteRoot: string): Map<string, GameInfo> {\n const games = new Map<string, GameInfo>()\n const candidates = findPuzzmoJsonDirs(viteRoot, 3)\n if (fs.existsSync(path.join(viteRoot, \"puzzmo.json\"))) {\n candidates.unshift(viteRoot)\n }\n for (const dir of candidates) {\n try {\n const data = JSON.parse(fs.readFileSync(path.join(dir, \"puzzmo.json\"), \"utf-8\"))\n if (!data?.game?.slug) continue\n const bundleEntry = path.join(dir, \"src\", \"appBundle.js\")\n let appBundle: string | null = null\n if (fs.existsSync(bundleEntry)) {\n const relative = path.relative(viteRoot, bundleEntry)\n appBundle = \"/\" + relative.split(path.sep).join(\"/\")\n }\n games.set(data.game.slug, { dir, slug: data.game.slug, displayName: data.game.displayName, appBundlePath: appBundle })\n } catch {\n // skip invalid files\n }\n }\n return games\n}\n\n/**\n * Resolve which game a request belongs to using the referer URL.\n *\n * @internal\n */\nexport function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined {\n if (referer) {\n try {\n const refPath = new URL(referer).pathname\n for (const g of games.values()) {\n const relDir = \"/\" + path.relative(viteRoot, g.dir).split(path.sep).join(\"/\")\n if (refPath.startsWith(relDir + \"/\") || refPath === relDir) return g\n }\n } catch {\n // ignore malformed referer\n }\n }\n if (games.size === 1) return games.values().next().value\n return undefined\n}\n\n/**\n * Generate the virtual module code for the simulator.\n *\n * @internal\n */\nexport function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string {\n const { fixturesGlob: fixturesOpt, ...config } = options\n const fixturesGlob = fixturesOpt === false ? null : (fixturesOpt ?? \"/fixtures/puzzles/**/*.json\")\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n if (game?.appBundlePath) {\n lines.push(`import(${JSON.stringify(game.appBundlePath)}).then(m => {`)\n lines.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`)\n lines.push(`}).catch(() => {})`)\n }\n\n const simConfig = { ...config, ...(game?.slug ? { slug: game.slug } : {}) }\n const configEntries = Object.entries(simConfig).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n let games = new Map<string, GameInfo>()\n let viteRoot: string\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configResolved(config: ResolvedConfig) {\n viteRoot = config.root\n games = discoverGames(viteRoot)\n\n if (games.size === 0) {\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m\\x1b[2m no puzzmo.json files found\\x1b[22m`)\n } else {\n const names = [...games.values()].map((g) => `\\x1b[36m${g.slug}\\x1b[39m`)\n const label = games.size === 1 ? \"game\" : \"games\"\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m found ${games.size} ${label}: ${names.join(\"\\x1b[2m, \\x1b[22m\")}`)\n }\n },\n\n resolveId(id) {\n if (id === virtualID || id.startsWith(virtualID + \"?\")) return \"\\0\" + id\n },\n\n load(id) {\n if (!id.startsWith(\"\\0\" + virtualID)) return\n const params = new URLSearchParams(id.split(\"?\")[1] || \"\")\n const gameSlug = params.get(\"game\")\n const game = gameSlug ? games.get(gameSlug) : games.size === 1 ? games.values().next().value : undefined\n return generateSimulatorCode(options, game)\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module, resolving the game from the referer\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== simulatorURL) return next()\n\n const game = resolveGameFromReferer(req.headers.referer, games, viteRoot)\n const moduleID = virtualID + (game ? `?game=${game.slug}` : \"\")\n const result = await server.transformRequest(moduleID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: simulatorURL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: path.isAbsolute(entry) ? entry : path.resolve(process.cwd(), entry),\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n\n/**\n * Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep.\n *\n * @internal\n */\nexport const findPuzzmoJsonDirs = (root: string, maxDepth: number, depth = 0): string[] => {\n if (depth >= maxDepth) return []\n const results: string[] = []\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(root, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue\n const dir = path.join(root, entry.name)\n if (fs.existsSync(path.join(dir, \"puzzmo.json\"))) {\n results.push(dir)\n }\n results.push(...findPuzzmoJsonDirs(dir, maxDepth, depth + 1))\n }\n return results\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vite.cjs","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\nimport fs from \"fs\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /**\n * Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to\n * `\"/fixtures/puzzles/**\\/*.json\"`. Pass false to disable.\n */\n fixturesGlob?: string | false\n}\n\nconst simulatorURL = \"/@puzzmo-simulator-init.js\"\nconst virtualID = \"virtual:puzzmo-simulator\"\n\n/** @internal */\nexport type GameInfo = {\n /** Directory containing the puzzmo.json */\n dir: string\n slug: string\n displayName: string\n /** Vite-root-relative path to app bundle entry, if it exists */\n appBundlePath: string | null\n}\n\n/**\n * Discover all games from puzzmo.json files under a root directory.\n *\n * @internal\n */\nexport function discoverGames(viteRoot: string): Map<string, GameInfo> {\n const games = new Map<string, GameInfo>()\n const candidates = findPuzzmoJsonDirs(viteRoot, 3)\n if (fs.existsSync(path.join(viteRoot, \"puzzmo.json\"))) {\n candidates.unshift(viteRoot)\n }\n for (const dir of candidates) {\n try {\n const data = JSON.parse(fs.readFileSync(path.join(dir, \"puzzmo.json\"), \"utf-8\"))\n if (!data?.game?.slug) continue\n const bundleEntry = resolveBundleEntry(dir, \"src/appBundle\")\n let appBundle: string | null = null\n if (bundleEntry) {\n const relative = path.relative(viteRoot, bundleEntry)\n appBundle = \"/\" + relative.split(path.sep).join(\"/\")\n }\n games.set(data.game.slug, { dir, slug: data.game.slug, displayName: data.game.displayName, appBundlePath: appBundle })\n } catch {\n // skip invalid files\n }\n }\n return games\n}\n\n/**\n * Resolve which game a request belongs to using the referer URL.\n *\n * @internal\n */\nexport function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined {\n if (referer) {\n try {\n const refPath = new URL(referer).pathname\n for (const g of games.values()) {\n const relDir = \"/\" + path.relative(viteRoot, g.dir).split(path.sep).join(\"/\")\n if (refPath.startsWith(relDir + \"/\") || refPath === relDir) return g\n }\n } catch {\n // ignore malformed referer\n }\n }\n if (games.size === 1) return games.values().next().value\n return undefined\n}\n\n/**\n * Generate the virtual module code for the simulator.\n *\n * @internal\n */\nexport function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string {\n const { fixturesGlob: fixturesOpt, ...config } = options\n const fixturesGlob = fixturesOpt === false ? null : (fixturesOpt ?? \"/fixtures/puzzles/**/*.json\")\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n if (game?.appBundlePath) {\n lines.push(`import(${JSON.stringify(game.appBundlePath)}).then(m => {`)\n lines.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`)\n lines.push(`}).catch(() => {})`)\n }\n\n const simConfig = { ...config, ...(game?.slug ? { slug: game.slug } : {}) }\n const configEntries = Object.entries(simConfig).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n let games = new Map<string, GameInfo>()\n let viteRoot: string\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configResolved(config: ResolvedConfig) {\n viteRoot = config.root\n games = discoverGames(viteRoot)\n\n if (games.size === 0) {\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m\\x1b[2m no puzzmo.json files found\\x1b[22m`)\n } else {\n const names = [...games.values()].map((g) => `\\x1b[36m${g.slug}\\x1b[39m`)\n const label = games.size === 1 ? \"game\" : \"games\"\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m found ${games.size} ${label}: ${names.join(\"\\x1b[2m, \\x1b[22m\")}`)\n }\n },\n\n resolveId(id) {\n if (id === virtualID || id.startsWith(virtualID + \"?\")) return \"\\0\" + id\n },\n\n load(id) {\n if (!id.startsWith(\"\\0\" + virtualID)) return\n const params = new URLSearchParams(id.split(\"?\")[1] || \"\")\n const gameSlug = params.get(\"game\")\n const game = gameSlug ? games.get(gameSlug) : games.size === 1 ? games.values().next().value : undefined\n return generateSimulatorCode(options, game)\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module, resolving the game from the referer\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== simulatorURL) return next()\n\n const game = resolveGameFromReferer(req.headers.referer, games, viteRoot)\n const moduleID = virtualID + (game ? `?game=${game.slug}` : \"\")\n const result = await server.transformRequest(moduleID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: simulatorURL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n // If the caller overrode `entry`, honor it as-is. Otherwise try `.js` first, then `.ts`.\n const resolvedEntry = options.entry\n ? path.isAbsolute(entry)\n ? entry\n : path.resolve(process.cwd(), entry)\n : (resolveBundleEntry(process.cwd(), stripBundleExt(entry)) ?? path.resolve(process.cwd(), entry))\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: resolvedEntry,\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\n/** Strip the trailing extension from a default entry path so we can probe siblings. */\nconst stripBundleExt = (p: string) => p.replace(/\\.[jt]sx?$/i, \"\")\n\n/** Returns the absolute path to the first matching extension under `dir`, or null. */\nconst resolveBundleEntry = (dir: string, baseRelative: string): string | null => {\n for (const ext of [\".js\", \".ts\"]) {\n const candidate = path.join(dir, baseRelative + ext)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n\n/**\n * Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep.\n *\n * @internal\n */\nexport const findPuzzmoJsonDirs = (root: string, maxDepth: number, depth = 0): string[] => {\n if (depth >= maxDepth) return []\n const results: string[] = []\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(root, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue\n const dir = path.join(root, entry.name)\n if (fs.existsSync(path.join(dir, \"puzzmo.json\"))) {\n results.push(dir)\n }\n results.push(...findPuzzmoJsonDirs(dir, maxDepth, depth + 1))\n }\n return results\n}\n"],"mappings":"yjCAsFU,eAAA,CArEJ,EAAe,6BACf,EAAY,2BAiBlB,SAAgB,EAAc,EAAyC,CACrE,IAAM,EAAQ,IAAI,IACZ,EAAa,EAAmB,EAAU,EAAE,CAC9C,EAAA,QAAG,WAAW,EAAA,QAAK,KAAK,EAAU,cAAc,CAAC,EACnD,EAAW,QAAQ,EAAS,CAE9B,IAAK,IAAM,KAAO,EAChB,GAAI,OACF,IAAM,EAAO,KAAK,MAAM,EAAA,QAAG,aAAa,EAAA,QAAK,KAAK,EAAK,cAAc,CAAE,QAAQ,CAAC,CAChF,GAAI,EAAA,KAAA,OAAA,EAAC,EAAM,OAAA,OAAA,EAAM,MAAM,SACvB,IAAM,EAAc,EAAmB,EAAK,gBAAgB,CACxD,EAA2B,KAC3B,IAEF,EAAY,IADK,EAAA,QAAK,SAAS,EAAU,EAAY,CAC1B,MAAM,EAAA,QAAK,IAAI,CAAC,KAAK,IAAI,EAEtD,EAAM,IAAI,EAAK,KAAK,KAAM,CAAE,MAAK,KAAM,EAAK,KAAK,KAAM,YAAa,EAAK,KAAK,YAAa,cAAe,EAAW,CAAC,SAChH,EAIV,OAAO,EAQT,SAAgB,EAAuB,EAA6B,EAA8B,EAAwC,CACxI,GAAI,EACF,GAAI,CACF,IAAM,EAAU,IAAI,IAAI,EAAQ,CAAC,SACjC,IAAK,IAAM,KAAK,EAAM,QAAQ,CAAE,CAC9B,IAAM,EAAS,IAAM,EAAA,QAAK,SAAS,EAAU,EAAE,IAAI,CAAC,MAAM,EAAA,QAAK,IAAI,CAAC,KAAK,IAAI,CAC7E,GAAI,EAAQ,WAAW,EAAS,IAAI,EAAI,IAAY,EAAQ,OAAO,WAE/D,EAIV,GAAI,EAAM,OAAS,EAAG,OAAO,EAAM,QAAQ,CAAC,MAAM,CAAC,MASrD,SAAgB,EAAsB,EAAuC,EAAoC,CAC/G,GAAM,CAAE,aAAc,GAAA,EAAgB,EAAA,EAAW,EAAA,EAAA,CAC3C,EAAe,IAAgB,GAAQ,KAAQ,GAAA,KAAe,8BAAf,EAE/C,EAAQ,CAAC,0DAA0D,CAErE,GACF,EAAM,KAAK,qCAAqC,KAAK,UAAU,EAAa,CAAC,oBAAoB,CAGnG,GAAA,MAAI,EAAM,gBACR,EAAM,KAAK,UAAU,KAAK,UAAU,EAAK,cAAc,CAAC,eAAe,CACvE,EAAM,KAAK,0EAA0E,CACrF,EAAM,KAAK,qBAAqB,EAGlC,IAAM,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAiB,EAAA,CAAA,GAAA,MAAY,EAAM,KAAO,CAAE,KAAM,EAAK,KAAM,CAAG,EAAE,CAAG,CAErE,EADgB,OAAO,QAAQ,EAAU,CAAC,QAAQ,EAAG,KAAO,IAAM,IAAA,GAAU,CAChD,KAAK,CAAC,EAAG,KAAO,GAAG,EAAE,IAAI,KAAK,UAAU,EAAE,GAAG,CAK/E,OAJI,GAAc,EAAY,KAAK,WAAW,CAE9C,EAAM,KAAK,qBAAqB,EAAY,KAAK,KAAK,CAAC,KAAK,CAErD,EAAM,KAAK;EAAK,CAIzB,SAAgB,EAAgB,EAAwC,EAAE,CAAU,CAClF,IAAI,EAAQ,IAAI,IACZ,EAEJ,MAAO,CACL,KAAM,mBACN,MAAO,QAEP,eAAe,EAAwB,CAIrC,GAHA,EAAW,EAAO,KAClB,EAAQ,EAAc,EAAS,CAE3B,EAAM,OAAS,EACjB,EAAO,OAAO,KAAK,qFAAqF,KACnG,CACL,IAAM,EAAQ,CAAC,GAAG,EAAM,QAAQ,CAAC,CAAC,IAAK,GAAM,WAAW,EAAE,KAAK,UAAU,CACnE,EAAQ,EAAM,OAAS,EAAI,OAAS,QAC1C,EAAO,OAAO,KAAK,kDAAkD,EAAM,KAAK,GAAG,EAAM,IAAI,EAAM,KAAK,oBAAoB,GAAG,GAInI,UAAU,EAAI,CACZ,GAAI,IAAO,GAAa,EAAG,WAAW,EAAY,IAAI,CAAE,MAAO,KAAO,GAGxE,KAAK,EAAI,CACP,GAAI,CAAC,EAAG,WAAW,KAAO,EAAU,CAAE,OAEtC,IAAM,EADS,IAAI,gBAAgB,EAAG,MAAM,IAAI,CAAC,IAAM,GAAG,CAClC,IAAI,OAAO,CAEnC,OAAO,EAAsB,EADhB,EAAW,EAAM,IAAI,EAAS,CAAG,EAAM,OAAS,EAAI,EAAM,QAAQ,CAAC,MAAM,CAAC,MAAQ,IAAA,GACpD,EAG7C,gBAAgB,EAAQ,CACtB,EAAO,YAAY,IAAI,mBAAoB,EAAM,IAAQ,CACvD,EAAI,UAAU,eAAgB,YAAY,CAC1C,EAAI,IAAI;;;;;;;;0BAQS,EACjB,CAGF,EAAO,YAAY,IAAA,UAAA,qBAAW,EAAK,EAAK,EAAS,OAC/C,KAAA,EAAI,EAAI,MAAA,KAAA,IAAA,GAAA,EAAK,MAAM,IAAI,CAAC,MAAO,EAAc,OAAO,GAAM,CAE1D,IAAM,EAAO,EAAuB,EAAI,QAAQ,QAAS,EAAO,EAAS,CACnE,EAAW,GAAa,EAAO,SAAS,EAAK,OAAS,IACtD,EAAS,MAAM,EAAO,iBAAiB,EAAS,CACtD,GAAI,CAAC,EAAQ,OAAO,GAAM,CAC1B,EAAI,UAAU,eAAgB,yBAAyB,CACvD,EAAI,IAAI,EAAO,KAAK,mBARQ,EAAK,EAAK,EAAA,oCAStC,EAGJ,oBAAqB,CACnB,MAAO,CACL,CACE,IAAK,SACL,MAAO,CAAE,KAAM,SAAU,IAAK,EAAc,CAC5C,SAAU,OACX,CACF,EAEJ,CAUH,SAAS,EAAmB,EAAoB,EAA+B,CAC7E,OAAQ,EAAwC,EAAE,GAAa,CAC7D,GAAM,CAAE,QAAO,cAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAoB,EAAA,CAAa,EAAS,CACzD,MAAO,CACL,KAAM,EACN,MAAO,QACP,aAAM,uBAAc,OAElB,IAAM,EAAgB,EAAQ,MAC1B,EAAA,QAAK,WAAW,EAAM,CACpB,EACA,EAAA,QAAK,QAAQ,QAAQ,KAAK,CAAE,EAAM,EAAA,EACnC,EAAmB,QAAQ,KAAK,CAAE,EAAe,EAAM,CAAC,GAAA,KAAI,EAAA,QAAK,QAAQ,QAAQ,KAAK,CAAE,EAAM,CAAtC,EAC7D,GAAI,CACF,MAAA,EAAA,EAAA,OAAY,CACV,WAAY,GACZ,SAAU,OACV,MAAO,CACL,IAAK,CACH,MAAO,EACP,QAAS,CAAC,KAAK,CACf,aAAgB,EACjB,CACD,OAAQ,OACR,YAAa,GACd,CACF,CAAC,OACK,EAAO,CAEd,MADA,QAAQ,MAAM,IAAI,EAAW,iBAAkB,EAAM,CAC/C,QAGX,EAKL,IAAM,EAAkB,GAAc,EAAE,QAAQ,cAAe,GAAG,CAG5D,GAAsB,EAAa,IAAwC,CAC/E,IAAK,IAAM,IAAO,CAAC,MAAO,MAAM,CAAE,CAChC,IAAM,EAAY,EAAA,QAAK,KAAK,EAAK,EAAe,EAAI,CACpD,GAAI,EAAA,QAAG,WAAW,EAAU,CAAE,OAAO,EAEvC,OAAO,MAWT,MAAa,EAAkB,EAAmB,aAAc,CAAE,MAAO,mBAAoB,WAAY,gBAAiB,CAAC,CAK9G,EAAqB,EAAmB,gBAAiB,CAAE,MAAO,sBAAuB,WAAY,mBAAoB,CAAC,CAO1H,GAAsB,EAAc,EAAkB,EAAQ,IAAgB,CACzF,GAAI,GAAS,EAAU,MAAO,EAAE,CAChC,IAAM,EAAoB,EAAE,CACxB,EACJ,GAAI,CACF,EAAU,EAAA,QAAG,YAAY,EAAM,CAAE,cAAe,GAAM,CAAC,SACjD,CACN,OAAO,EAET,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,EAAI,EAAM,KAAK,WAAW,IAAI,EAAI,EAAM,OAAS,eAAgB,SACzF,IAAM,EAAM,EAAA,QAAK,KAAK,EAAM,EAAM,KAAK,CACnC,EAAA,QAAG,WAAW,EAAA,QAAK,KAAK,EAAK,cAAc,CAAC,EAC9C,EAAQ,KAAK,EAAI,CAEnB,EAAQ,KAAK,GAAG,EAAmB,EAAK,EAAU,EAAQ,EAAE,CAAC,CAE/D,OAAO"}
|
package/dist/vite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAA;AAKlD,MAAM,MAAM,4BAA4B,GAAG;IACzC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC9B,CAAA;AAKD,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG;IACrB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAsBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAcxI;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAwB/G;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,OAAO,GAAE,4BAAiC,GAAG,MAAM,CAsElF;AAED,KAAK,mBAAmB,GAAG;IACzB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAA;AAKlD,MAAM,MAAM,4BAA4B,GAAG;IACzC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC9B,CAAA;AAKD,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG;IACrB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAsBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAcxI;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAwB/G;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,OAAO,GAAE,4BAAiC,GAAG,MAAM,CAsElF;AAED,KAAK,mBAAmB,GAAG;IACzB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAkDD,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,yDAA+F,CAAA;AAE3H,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEpE,0GAA0G;AAC1G,eAAO,MAAM,kBAAkB,yDAAwG,CAAA;AAEvI;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,8DAkB9B,CAAA"}
|
package/dist/vite.js
CHANGED
|
@@ -28,14 +28,14 @@ var s = ["fixturesGlob"], c = "/@puzzmo-simulator-init.js", l = "virtual:puzzmo-
|
|
|
28
28
|
* @internal
|
|
29
29
|
*/
|
|
30
30
|
function u(e) {
|
|
31
|
-
let t = /* @__PURE__ */ new Map(), n =
|
|
31
|
+
let t = /* @__PURE__ */ new Map(), n = y(e, 3);
|
|
32
32
|
i.existsSync(r.join(e, "puzzmo.json")) && n.unshift(e);
|
|
33
33
|
for (let o of n) try {
|
|
34
34
|
var a;
|
|
35
35
|
let n = JSON.parse(i.readFileSync(r.join(o, "puzzmo.json"), "utf-8"));
|
|
36
36
|
if (!(!(n == null || (a = n.game) == null) && a.slug)) continue;
|
|
37
|
-
let s =
|
|
38
|
-
|
|
37
|
+
let s = g(o, "src/appBundle"), c = null;
|
|
38
|
+
s && (c = "/" + r.relative(e, s).split(r.sep).join("/")), t.set(n.game.slug, {
|
|
39
39
|
dir: o,
|
|
40
40
|
slug: n.game.slug,
|
|
41
41
|
displayName: n.game.displayName,
|
|
@@ -127,13 +127,15 @@ function m(i, a) {
|
|
|
127
127
|
apply: "build",
|
|
128
128
|
closeBundle() {
|
|
129
129
|
return e(function* () {
|
|
130
|
+
var e;
|
|
131
|
+
let t = o.entry ? r.isAbsolute(s) ? s : r.resolve(process.cwd(), s) : (e = g(process.cwd(), h(s))) == null ? r.resolve(process.cwd(), s) : e;
|
|
130
132
|
try {
|
|
131
133
|
yield n({
|
|
132
134
|
configFile: !1,
|
|
133
135
|
logLevel: "warn",
|
|
134
136
|
build: {
|
|
135
137
|
lib: {
|
|
136
|
-
entry:
|
|
138
|
+
entry: t,
|
|
137
139
|
formats: ["es"],
|
|
138
140
|
fileName: () => c
|
|
139
141
|
},
|
|
@@ -149,19 +151,27 @@ function m(i, a) {
|
|
|
149
151
|
};
|
|
150
152
|
};
|
|
151
153
|
}
|
|
154
|
+
/** Strip the trailing extension from a default entry path so we can probe siblings. */
|
|
155
|
+
var h = (e) => e.replace(/\.[jt]sx?$/i, ""), g = (e, t) => {
|
|
156
|
+
for (let n of [".js", ".ts"]) {
|
|
157
|
+
let a = r.join(e, t + n);
|
|
158
|
+
if (i.existsSync(a)) return a;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
};
|
|
152
162
|
/**
|
|
153
163
|
* Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.
|
|
154
164
|
*
|
|
155
165
|
* The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure
|
|
156
166
|
* SVG-string renderer used by the Puzzmo platform for puzzle previews.
|
|
157
167
|
*/
|
|
158
|
-
const
|
|
168
|
+
const _ = m("app-bundle", {
|
|
159
169
|
entry: "src/appBundle.js",
|
|
160
170
|
outputFile: "app-bundle.js"
|
|
161
|
-
}),
|
|
171
|
+
}), v = m("editor-bundle", {
|
|
162
172
|
entry: "src/editorBundle.js",
|
|
163
173
|
outputFile: "editor-bundle.js"
|
|
164
|
-
}),
|
|
174
|
+
}), y = (e, t, n = 0) => {
|
|
165
175
|
if (n >= t) return [];
|
|
166
176
|
let a = [], o;
|
|
167
177
|
try {
|
|
@@ -172,10 +182,10 @@ const h = m("app-bundle", {
|
|
|
172
182
|
for (let s of o) {
|
|
173
183
|
if (!s.isDirectory() || s.name.startsWith(".") || s.name === "node_modules") continue;
|
|
174
184
|
let o = r.join(e, s.name);
|
|
175
|
-
i.existsSync(r.join(o, "puzzmo.json")) && a.push(o), a.push(...
|
|
185
|
+
i.existsSync(r.join(o, "puzzmo.json")) && a.push(o), a.push(...y(o, t, n + 1));
|
|
176
186
|
}
|
|
177
187
|
return a;
|
|
178
188
|
};
|
|
179
|
-
export {
|
|
189
|
+
export { _ as appBundlePlugin, u as discoverGames, v as editorBundlePlugin, y as findPuzzmoJsonDirs, f as generateSimulatorCode, p as puzzmoSimulator, d as resolveGameFromReferer };
|
|
180
190
|
|
|
181
191
|
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\nimport fs from \"fs\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /**\n * Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to\n * `\"/fixtures/puzzles/**\\/*.json\"`. Pass false to disable.\n */\n fixturesGlob?: string | false\n}\n\nconst simulatorURL = \"/@puzzmo-simulator-init.js\"\nconst virtualID = \"virtual:puzzmo-simulator\"\n\n/** @internal */\nexport type GameInfo = {\n /** Directory containing the puzzmo.json */\n dir: string\n slug: string\n displayName: string\n /** Vite-root-relative path to app bundle entry, if it exists */\n appBundlePath: string | null\n}\n\n/**\n * Discover all games from puzzmo.json files under a root directory.\n *\n * @internal\n */\nexport function discoverGames(viteRoot: string): Map<string, GameInfo> {\n const games = new Map<string, GameInfo>()\n const candidates = findPuzzmoJsonDirs(viteRoot, 3)\n if (fs.existsSync(path.join(viteRoot, \"puzzmo.json\"))) {\n candidates.unshift(viteRoot)\n }\n for (const dir of candidates) {\n try {\n const data = JSON.parse(fs.readFileSync(path.join(dir, \"puzzmo.json\"), \"utf-8\"))\n if (!data?.game?.slug) continue\n const bundleEntry = path.join(dir, \"src\", \"appBundle.js\")\n let appBundle: string | null = null\n if (fs.existsSync(bundleEntry)) {\n const relative = path.relative(viteRoot, bundleEntry)\n appBundle = \"/\" + relative.split(path.sep).join(\"/\")\n }\n games.set(data.game.slug, { dir, slug: data.game.slug, displayName: data.game.displayName, appBundlePath: appBundle })\n } catch {\n // skip invalid files\n }\n }\n return games\n}\n\n/**\n * Resolve which game a request belongs to using the referer URL.\n *\n * @internal\n */\nexport function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined {\n if (referer) {\n try {\n const refPath = new URL(referer).pathname\n for (const g of games.values()) {\n const relDir = \"/\" + path.relative(viteRoot, g.dir).split(path.sep).join(\"/\")\n if (refPath.startsWith(relDir + \"/\") || refPath === relDir) return g\n }\n } catch {\n // ignore malformed referer\n }\n }\n if (games.size === 1) return games.values().next().value\n return undefined\n}\n\n/**\n * Generate the virtual module code for the simulator.\n *\n * @internal\n */\nexport function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string {\n const { fixturesGlob: fixturesOpt, ...config } = options\n const fixturesGlob = fixturesOpt === false ? null : (fixturesOpt ?? \"/fixtures/puzzles/**/*.json\")\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n if (game?.appBundlePath) {\n lines.push(`import(${JSON.stringify(game.appBundlePath)}).then(m => {`)\n lines.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`)\n lines.push(`}).catch(() => {})`)\n }\n\n const simConfig = { ...config, ...(game?.slug ? { slug: game.slug } : {}) }\n const configEntries = Object.entries(simConfig).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n let games = new Map<string, GameInfo>()\n let viteRoot: string\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configResolved(config: ResolvedConfig) {\n viteRoot = config.root\n games = discoverGames(viteRoot)\n\n if (games.size === 0) {\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m\\x1b[2m no puzzmo.json files found\\x1b[22m`)\n } else {\n const names = [...games.values()].map((g) => `\\x1b[36m${g.slug}\\x1b[39m`)\n const label = games.size === 1 ? \"game\" : \"games\"\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m found ${games.size} ${label}: ${names.join(\"\\x1b[2m, \\x1b[22m\")}`)\n }\n },\n\n resolveId(id) {\n if (id === virtualID || id.startsWith(virtualID + \"?\")) return \"\\0\" + id\n },\n\n load(id) {\n if (!id.startsWith(\"\\0\" + virtualID)) return\n const params = new URLSearchParams(id.split(\"?\")[1] || \"\")\n const gameSlug = params.get(\"game\")\n const game = gameSlug ? games.get(gameSlug) : games.size === 1 ? games.values().next().value : undefined\n return generateSimulatorCode(options, game)\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module, resolving the game from the referer\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== simulatorURL) return next()\n\n const game = resolveGameFromReferer(req.headers.referer, games, viteRoot)\n const moduleID = virtualID + (game ? `?game=${game.slug}` : \"\")\n const result = await server.transformRequest(moduleID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: simulatorURL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: path.isAbsolute(entry) ? entry : path.resolve(process.cwd(), entry),\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n\n/**\n * Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep.\n *\n * @internal\n */\nexport const findPuzzmoJsonDirs = (root: string, maxDepth: number, depth = 0): string[] => {\n if (depth >= maxDepth) return []\n const results: string[] = []\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(root, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue\n const dir = path.join(root, entry.name)\n if (fs.existsSync(path.join(dir, \"puzzmo.json\"))) {\n results.push(dir)\n }\n results.push(...findPuzzmoJsonDirs(dir, maxDepth, depth + 1))\n }\n return results\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\nimport fs from \"fs\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /**\n * Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to\n * `\"/fixtures/puzzles/**\\/*.json\"`. Pass false to disable.\n */\n fixturesGlob?: string | false\n}\n\nconst simulatorURL = \"/@puzzmo-simulator-init.js\"\nconst virtualID = \"virtual:puzzmo-simulator\"\n\n/** @internal */\nexport type GameInfo = {\n /** Directory containing the puzzmo.json */\n dir: string\n slug: string\n displayName: string\n /** Vite-root-relative path to app bundle entry, if it exists */\n appBundlePath: string | null\n}\n\n/**\n * Discover all games from puzzmo.json files under a root directory.\n *\n * @internal\n */\nexport function discoverGames(viteRoot: string): Map<string, GameInfo> {\n const games = new Map<string, GameInfo>()\n const candidates = findPuzzmoJsonDirs(viteRoot, 3)\n if (fs.existsSync(path.join(viteRoot, \"puzzmo.json\"))) {\n candidates.unshift(viteRoot)\n }\n for (const dir of candidates) {\n try {\n const data = JSON.parse(fs.readFileSync(path.join(dir, \"puzzmo.json\"), \"utf-8\"))\n if (!data?.game?.slug) continue\n const bundleEntry = resolveBundleEntry(dir, \"src/appBundle\")\n let appBundle: string | null = null\n if (bundleEntry) {\n const relative = path.relative(viteRoot, bundleEntry)\n appBundle = \"/\" + relative.split(path.sep).join(\"/\")\n }\n games.set(data.game.slug, { dir, slug: data.game.slug, displayName: data.game.displayName, appBundlePath: appBundle })\n } catch {\n // skip invalid files\n }\n }\n return games\n}\n\n/**\n * Resolve which game a request belongs to using the referer URL.\n *\n * @internal\n */\nexport function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined {\n if (referer) {\n try {\n const refPath = new URL(referer).pathname\n for (const g of games.values()) {\n const relDir = \"/\" + path.relative(viteRoot, g.dir).split(path.sep).join(\"/\")\n if (refPath.startsWith(relDir + \"/\") || refPath === relDir) return g\n }\n } catch {\n // ignore malformed referer\n }\n }\n if (games.size === 1) return games.values().next().value\n return undefined\n}\n\n/**\n * Generate the virtual module code for the simulator.\n *\n * @internal\n */\nexport function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string {\n const { fixturesGlob: fixturesOpt, ...config } = options\n const fixturesGlob = fixturesOpt === false ? null : (fixturesOpt ?? \"/fixtures/puzzles/**/*.json\")\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n if (game?.appBundlePath) {\n lines.push(`import(${JSON.stringify(game.appBundlePath)}).then(m => {`)\n lines.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`)\n lines.push(`}).catch(() => {})`)\n }\n\n const simConfig = { ...config, ...(game?.slug ? { slug: game.slug } : {}) }\n const configEntries = Object.entries(simConfig).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n let games = new Map<string, GameInfo>()\n let viteRoot: string\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configResolved(config: ResolvedConfig) {\n viteRoot = config.root\n games = discoverGames(viteRoot)\n\n if (games.size === 0) {\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m\\x1b[2m no puzzmo.json files found\\x1b[22m`)\n } else {\n const names = [...games.values()].map((g) => `\\x1b[36m${g.slug}\\x1b[39m`)\n const label = games.size === 1 ? \"game\" : \"games\"\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m found ${games.size} ${label}: ${names.join(\"\\x1b[2m, \\x1b[22m\")}`)\n }\n },\n\n resolveId(id) {\n if (id === virtualID || id.startsWith(virtualID + \"?\")) return \"\\0\" + id\n },\n\n load(id) {\n if (!id.startsWith(\"\\0\" + virtualID)) return\n const params = new URLSearchParams(id.split(\"?\")[1] || \"\")\n const gameSlug = params.get(\"game\")\n const game = gameSlug ? games.get(gameSlug) : games.size === 1 ? games.values().next().value : undefined\n return generateSimulatorCode(options, game)\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module, resolving the game from the referer\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== simulatorURL) return next()\n\n const game = resolveGameFromReferer(req.headers.referer, games, viteRoot)\n const moduleID = virtualID + (game ? `?game=${game.slug}` : \"\")\n const result = await server.transformRequest(moduleID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: simulatorURL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n // If the caller overrode `entry`, honor it as-is. Otherwise try `.js` first, then `.ts`.\n const resolvedEntry = options.entry\n ? path.isAbsolute(entry)\n ? entry\n : path.resolve(process.cwd(), entry)\n : (resolveBundleEntry(process.cwd(), stripBundleExt(entry)) ?? path.resolve(process.cwd(), entry))\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: resolvedEntry,\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\n/** Strip the trailing extension from a default entry path so we can probe siblings. */\nconst stripBundleExt = (p: string) => p.replace(/\\.[jt]sx?$/i, \"\")\n\n/** Returns the absolute path to the first matching extension under `dir`, or null. */\nconst resolveBundleEntry = (dir: string, baseRelative: string): string | null => {\n for (const ext of [\".js\", \".ts\"]) {\n const candidate = path.join(dir, baseRelative + ext)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n\n/**\n * Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep.\n *\n * @internal\n */\nexport const findPuzzmoJsonDirs = (root: string, maxDepth: number, depth = 0): string[] => {\n if (depth >= maxDepth) return []\n const results: string[] = []\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(root, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue\n const dir = path.join(root, entry.name)\n if (fs.existsSync(path.join(dir, \"puzzmo.json\"))) {\n results.push(dir)\n }\n results.push(...findPuzzmoJsonDirs(dir, maxDepth, depth + 1))\n }\n return results\n}\n"],"mappings":"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"}
|