From 78de3744f2995c4f1f927d2c891fac8dfa945ba7 Mon Sep 17 00:00:00 2001 From: Brian Luerssen Date: Sun, 5 Jul 2026 08:54:04 -0400 Subject: [PATCH] Add compact short share links served by a Worker script Share buttons now emit personas.draftbit.com/ where the code is a bit-packed base64url encoding of the avatar config (12 chars for palette colors, 31 max with custom hex). No storage: the code is the config. The address bar keeps the readable query-param form. - shareUrl.js: v1 codec (4-bit version, per-category style indices, flagged palette-index-or-raw-hex colors); config arrays are now append-only, documented in the file header - worker/index.js (new): serves the SPA shell for code paths, exposes GET /api/options (config JSON, CORS *), falls through to assets; run_worker_first with asset-dir exclusions so browser navigations reach the worker instead of the asset layer's own 404 handling - Modal gets the short URL via prop for Copy Link and the tweet intent Verified: 127-case codec round-trip suite in Node; wrangler dev in a real browser (code decodes, URL normalizes, share buttons emit short form, assets and 404s unaffected). Co-Authored-By: Claude Fable 5 --- .../miniflare-CacheObject/metadata.sqlite | Bin 0 -> 4096 bytes .../miniflare-CacheObject/metadata.sqlite-shm | Bin 0 -> 32768 bytes .../miniflare-CacheObject/metadata.sqlite-wal | Bin 0 -> 8272 bytes .../middleware-insertion-facade.js | 11 + .../bundle-hfhVdy/middleware-loader.entry.ts | 134 ++++++ .../middleware-insertion-facade.js | 11 + .../bundle-uax8ND/middleware-loader.entry.ts | 134 ++++++ .wrangler/tmp/dev-7xEpV1/index.js | 382 ++++++++++++++++++ .wrangler/tmp/dev-7xEpV1/index.js.map | 8 + .wrangler/tmp/dev-NwJonP/index.js | 382 ++++++++++++++++++ .wrangler/tmp/dev-NwJonP/index.js.map | 8 + src/components/App.res | 3 +- src/components/Modal.res | 9 +- src/helpers/shareUrl.js | 138 ++++++- src/pages/Index.res | 4 + worker/index.js | 43 ++ wrangler.jsonc | 7 +- 17 files changed, 1259 insertions(+), 15 deletions(-) create mode 100644 .wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite create mode 100644 .wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm create mode 100644 .wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal create mode 100644 .wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js create mode 100644 .wrangler/tmp/bundle-hfhVdy/middleware-loader.entry.ts create mode 100644 .wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js create mode 100644 .wrangler/tmp/bundle-uax8ND/middleware-loader.entry.ts create mode 100644 .wrangler/tmp/dev-7xEpV1/index.js create mode 100644 .wrangler/tmp/dev-7xEpV1/index.js.map create mode 100644 .wrangler/tmp/dev-NwJonP/index.js create mode 100644 .wrangler/tmp/dev-NwJonP/index.js.map create mode 100644 worker/index.js diff --git a/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite b/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..0b58f0dca7d6ce95907cb0b322dc4802f04688c0 GIT binary patch literal 4096 zcmWFz^vNtqRY=P(%1ta$FlG>7U}9o$P*7lCU|@t|AVoG{WYDXN;00+HAlr;ljiVtj n8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*O6ovo**AfQj literal 0 HcmV?d00001 diff --git a/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm b/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm new file mode 100644 index 0000000000000000000000000000000000000000..4831e6c41eb24a80653044dbe91bdab5daf4ec42 GIT binary patch literal 32768 zcmeI)p$)=76b9e}SBI=6=#GG65)1-^L@)sp)RiSLH4MNCCh?R&RuHs|%d-LD?)@o+8b?p6NzKKG8EpFxK8IQO%E zb93EJfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAJ1%dc=LI_M#ApT?#0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=DU348%8 Cl_<3U literal 0 HcmV?d00001 diff --git a/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal b/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal new file mode 100644 index 0000000000000000000000000000000000000000..cdff34ba4db8ec46536a192f622bed36c88d8822 GIT binary patch literal 8272 zcmXr7XKP~6eI&uaAiw|uE?u^#cV#QzS)kGzZlZr-8&HT5S$x`?0-LF!p$x%+KA9z{ z3TgR8xrrqT#z5UnObiYR3P80?Pz=%r0wDb?U>1Y`n}@{5#$;m9tBc?T$}sYmFaXgg z7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fe{k|jhu|^;_~v0jfo|RNja(U z$!YP9K8``Ya0ZiekgH>et3rsQlaH$cTv$PaO92cLlS}f8;xkheLR=$46as=geI0`$ z6}(*|b)X80lQU9NN^??E;!84fQx!b@LR{TlgTRuS3gMn19{!;r3PJwio-V*Z2lw+~ z;{{1I`xnetOn=7(iVet6!ib5NQIC#>z-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeD KjE2BS3jqMP{zzQ_ literal 0 HcmV?d00001 diff --git a/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js b/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js new file mode 100644 index 0000000..f4d3f63 --- /dev/null +++ b/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js @@ -0,0 +1,11 @@ + import worker, * as OTHER_EXPORTS from "/Users/brian/Code/personas/worker/index.js"; + import * as __MIDDLEWARE_0__ from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts"; +import * as __MIDDLEWARE_1__ from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts"; + + export * from "/Users/brian/Code/personas/worker/index.js"; + const MIDDLEWARE_TEST_INJECT = "__INJECT_FOR_TESTING_WRANGLER_MIDDLEWARE__"; + export const __INTERNAL_WRANGLER_MIDDLEWARE__ = [ + + __MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default + ] + export default worker; \ No newline at end of file diff --git a/.wrangler/tmp/bundle-hfhVdy/middleware-loader.entry.ts b/.wrangler/tmp/bundle-hfhVdy/middleware-loader.entry.ts new file mode 100644 index 0000000..bea83fd --- /dev/null +++ b/.wrangler/tmp/bundle-hfhVdy/middleware-loader.entry.ts @@ -0,0 +1,134 @@ +// This loads all middlewares exposed on the middleware object and then starts +// the invocation chain. The big idea is that we can add these to the middleware +// export dynamically through wrangler, or we can potentially let users directly +// add them as a sort of "plugin" system. + +import ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from "/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js"; +import { __facade_invoke__, __facade_register__, Dispatcher } from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/common.ts"; +import type { WorkerEntrypointConstructor } from "/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js"; + +// Preserve all the exports from the worker +export * from "/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js"; + +class __Facade_ScheduledController__ implements ScheduledController { + readonly #noRetry: ScheduledController["noRetry"]; + + constructor( + readonly scheduledTime: number, + readonly cron: string, + noRetry: ScheduledController["noRetry"] + ) { + this.#noRetry = noRetry; + } + + noRetry() { + if (!(this instanceof __Facade_ScheduledController__)) { + throw new TypeError("Illegal invocation"); + } + // Need to call native method immediately in case uncaught error thrown + this.#noRetry(); + } +} + +function wrapExportedHandler(worker: ExportedHandler): ExportedHandler { + // If we don't have any middleware defined, just return the handler as is + if ( + __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || + __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 + ) { + return worker; + } + // Otherwise, register all middleware once + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + + const fetchDispatcher: ExportedHandlerFetchHandler = function ( + request, + env, + ctx + ) { + if (worker.fetch === undefined) { + throw new Error("Handler does not export a fetch() function."); + } + return worker.fetch(request, env, ctx); + }; + + return { + ...worker, + fetch(request, env, ctx) { + const dispatcher: Dispatcher = function (type, init) { + if (type === "scheduled" && worker.scheduled !== undefined) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => {} + ); + return worker.scheduled(controller, env, ctx); + } + }; + return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); + }, + }; +} + +function wrapWorkerEntrypoint( + klass: WorkerEntrypointConstructor +): WorkerEntrypointConstructor { + // If we don't have any middleware defined, just return the handler as is + if ( + __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || + __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 + ) { + return klass; + } + // Otherwise, register all middleware once + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + + // `extend`ing `klass` here so other RPC methods remain callable + return class extends klass { + #fetchDispatcher: ExportedHandlerFetchHandler> = ( + request, + env, + ctx + ) => { + this.env = env; + this.ctx = ctx; + if (super.fetch === undefined) { + throw new Error("Entrypoint class does not define a fetch() function."); + } + return super.fetch(request); + }; + + #dispatcher: Dispatcher = (type, init) => { + if (type === "scheduled" && super.scheduled !== undefined) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => {} + ); + return super.scheduled(controller); + } + }; + + fetch(request: Request) { + return __facade_invoke__( + request, + this.env, + this.ctx, + this.#dispatcher, + this.#fetchDispatcher + ); + } + }; +} + +let WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined; +if (typeof ENTRY === "object") { + WRAPPED_ENTRY = wrapExportedHandler(ENTRY); +} else if (typeof ENTRY === "function") { + WRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY); +} +export default WRAPPED_ENTRY; diff --git a/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js b/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js new file mode 100644 index 0000000..f4d3f63 --- /dev/null +++ b/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js @@ -0,0 +1,11 @@ + import worker, * as OTHER_EXPORTS from "/Users/brian/Code/personas/worker/index.js"; + import * as __MIDDLEWARE_0__ from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts"; +import * as __MIDDLEWARE_1__ from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts"; + + export * from "/Users/brian/Code/personas/worker/index.js"; + const MIDDLEWARE_TEST_INJECT = "__INJECT_FOR_TESTING_WRANGLER_MIDDLEWARE__"; + export const __INTERNAL_WRANGLER_MIDDLEWARE__ = [ + + __MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default + ] + export default worker; \ No newline at end of file diff --git a/.wrangler/tmp/bundle-uax8ND/middleware-loader.entry.ts b/.wrangler/tmp/bundle-uax8ND/middleware-loader.entry.ts new file mode 100644 index 0000000..0d30ae4 --- /dev/null +++ b/.wrangler/tmp/bundle-uax8ND/middleware-loader.entry.ts @@ -0,0 +1,134 @@ +// This loads all middlewares exposed on the middleware object and then starts +// the invocation chain. The big idea is that we can add these to the middleware +// export dynamically through wrangler, or we can potentially let users directly +// add them as a sort of "plugin" system. + +import ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from "/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js"; +import { __facade_invoke__, __facade_register__, Dispatcher } from "/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/common.ts"; +import type { WorkerEntrypointConstructor } from "/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js"; + +// Preserve all the exports from the worker +export * from "/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js"; + +class __Facade_ScheduledController__ implements ScheduledController { + readonly #noRetry: ScheduledController["noRetry"]; + + constructor( + readonly scheduledTime: number, + readonly cron: string, + noRetry: ScheduledController["noRetry"] + ) { + this.#noRetry = noRetry; + } + + noRetry() { + if (!(this instanceof __Facade_ScheduledController__)) { + throw new TypeError("Illegal invocation"); + } + // Need to call native method immediately in case uncaught error thrown + this.#noRetry(); + } +} + +function wrapExportedHandler(worker: ExportedHandler): ExportedHandler { + // If we don't have any middleware defined, just return the handler as is + if ( + __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || + __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 + ) { + return worker; + } + // Otherwise, register all middleware once + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + + const fetchDispatcher: ExportedHandlerFetchHandler = function ( + request, + env, + ctx + ) { + if (worker.fetch === undefined) { + throw new Error("Handler does not export a fetch() function."); + } + return worker.fetch(request, env, ctx); + }; + + return { + ...worker, + fetch(request, env, ctx) { + const dispatcher: Dispatcher = function (type, init) { + if (type === "scheduled" && worker.scheduled !== undefined) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => {} + ); + return worker.scheduled(controller, env, ctx); + } + }; + return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); + }, + }; +} + +function wrapWorkerEntrypoint( + klass: WorkerEntrypointConstructor +): WorkerEntrypointConstructor { + // If we don't have any middleware defined, just return the handler as is + if ( + __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || + __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 + ) { + return klass; + } + // Otherwise, register all middleware once + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + + // `extend`ing `klass` here so other RPC methods remain callable + return class extends klass { + #fetchDispatcher: ExportedHandlerFetchHandler> = ( + request, + env, + ctx + ) => { + this.env = env; + this.ctx = ctx; + if (super.fetch === undefined) { + throw new Error("Entrypoint class does not define a fetch() function."); + } + return super.fetch(request); + }; + + #dispatcher: Dispatcher = (type, init) => { + if (type === "scheduled" && super.scheduled !== undefined) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => {} + ); + return super.scheduled(controller); + } + }; + + fetch(request: Request) { + return __facade_invoke__( + request, + this.env, + this.ctx, + this.#dispatcher, + this.#fetchDispatcher + ); + } + }; +} + +let WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined; +if (typeof ENTRY === "object") { + WRAPPED_ENTRY = wrapExportedHandler(ENTRY); +} else if (typeof ENTRY === "function") { + WRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY); +} +export default WRAPPED_ENTRY; diff --git a/.wrangler/tmp/dev-7xEpV1/index.js b/.wrangler/tmp/dev-7xEpV1/index.js new file mode 100644 index 0000000..962a246 --- /dev/null +++ b/.wrangler/tmp/dev-7xEpV1/index.js @@ -0,0 +1,382 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); + +// src/data/config.json +var config_default = { + skinStyles: [ + "Skin" + ], + hairStyles: [ + "Bald", + "Hat", + "Balding", + "Bigcurls", + "Bobbangs", + "Bobcut", + "Buncurls", + "Buzzcut", + "Curlybun", + "Hightopcurly", + "Long", + "Pigtails", + "Shortcombover", + "Beanie", + "Bunundercut", + "Extralong", + "Fade", + "Mohawk", + "Shortcomboverchops", + "Sidebuzz", + "Straightbun" + ], + facialHairStyles: [ + "BeardMustache", + "Mustache", + "None", + "Goatee", + "Shadow", + "Soulpatch", + "Walrus" + ], + bodyStyles: [ + "Oval", + "Round", + "Square", + "Checkered", + "Hoodie", + "Stripes" + ], + eyeStyles: [ + "Glasses", + "Happy", + "Open", + "Sleepy", + "Sunglasses", + "Wink", + "Closed", + "Hearts", + "Dizzy", + "Sideeye" + ], + mouthStyles: [ + "Bigsmile", + "Frown", + "Lips", + "Pacifier", + "Smile", + "Smirk", + "Surprise", + "Grin", + "Tongue", + "Whistle", + "Laugh" + ], + noseStyles: [ + "Mediumround", + "Smallround", + "Wrinkles", + "Pointed", + "Button" + ], + accessoryStyles: [ + "None", + "Earring", + "Earrings" + ], + bgStyles: [ + "Background" + ], + skinColors: [ + "FFCC22", + "FFDFC4", + "FBD2C7", + "F2AD9B", + "E58F7B", + "E4A070", + "B16A5B", + "92594B", + "7A4536", + "623D36", + "C9E6DC", + "C4B5F2" + ], + hairColors: [ + "362C47", + "675E97", + "4E7DE0", + "5AC4D4", + "58B368", + "DEE1F5", + "6C4545", + "F29C65", + "F2C94C", + "E16381", + "E15C66", + "979FB0" + ], + facialHairColors: [ + "362C47", + "675E97", + "4E7DE0", + "5AC4D4", + "58B368", + "DEE1F5", + "6C4545", + "F29C65", + "F2C94C", + "E16381", + "E15C66", + "979FB0" + ], + bodyColors: [ + "456DFF", + "5A45FF", + "6DBB58", + "F55D81", + "7555CA", + "E24553", + "54D7C7", + "F3B63A", + "FF8A5C", + "3E4E7C", + "C866D9", + "68C9F2" + ], + accessoryColors: [ + "F3B63A", + "C9CFDB", + "C98850", + "362C47", + "F55D81", + "54D7C7", + "456DFF", + "5A45FF" + ], + bgColors: [ + "93A7FF", + "A9E775", + "FF7A9A", + "B379F7", + "FF6674", + "89E6E4", + "FFCC65", + "FFB27A", + "B8EBC5", + "D9CCFF", + "6C7BC4", + "F8FBFF" + ], + disabledColors: [ + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5" + ] +}; + +// worker/index.js +var CODE_PATH = /^\/[A-Za-z0-9_-]{8,64}$/; +var CORS = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type" +}; +var worker_default = { + async fetch(request, env) { + const url = new URL(request.url); + if (request.method === "OPTIONS") { + return new Response(null, { headers: CORS }); + } + if (url.pathname === "/api/options") { + return Response.json(config_default, { + headers: { ...CORS, "Cache-Control": "public, max-age=3600" } + }); + } + if (request.method === "GET" && CODE_PATH.test(url.pathname)) { + const shell = new URL("/", url); + return env.ASSETS.fetch(new Request(shell, request)); + } + return env.ASSETS.fetch(request); + } +}; + +// node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts +var drainBody = /* @__PURE__ */ __name(async (request, env, _ctx, middlewareCtx) => { + try { + return await middlewareCtx.next(request, env); + } finally { + try { + if (request.body !== null && !request.bodyUsed) { + const reader = request.body.getReader(); + while (!(await reader.read()).done) { + } + } + } catch (e) { + console.error("Failed to drain the unused request body.", e); + } + } +}, "drainBody"); +var middleware_ensure_req_body_drained_default = drainBody; + +// node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts +function reduceError(e) { + return { + name: e?.name, + message: e?.message ?? String(e), + stack: e?.stack, + cause: e?.cause === void 0 ? void 0 : reduceError(e.cause) + }; +} +__name(reduceError, "reduceError"); +var jsonError = /* @__PURE__ */ __name(async (request, env, _ctx, middlewareCtx) => { + try { + return await middlewareCtx.next(request, env); + } catch (e) { + const error = reduceError(e); + return Response.json(error, { + status: 500, + headers: { "MF-Experimental-Error-Stack": "true" } + }); + } +}, "jsonError"); +var middleware_miniflare3_json_error_default = jsonError; + +// .wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js +var __INTERNAL_WRANGLER_MIDDLEWARE__ = [ + middleware_ensure_req_body_drained_default, + middleware_miniflare3_json_error_default +]; +var middleware_insertion_facade_default = worker_default; + +// node_modules/wrangler/templates/middleware/common.ts +var __facade_middleware__ = []; +function __facade_register__(...args) { + __facade_middleware__.push(...args.flat()); +} +__name(__facade_register__, "__facade_register__"); +function __facade_invokeChain__(request, env, ctx, dispatch, middlewareChain) { + const [head, ...tail] = middlewareChain; + const middlewareCtx = { + dispatch, + next(newRequest, newEnv) { + return __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail); + } + }; + return head(request, env, ctx, middlewareCtx); +} +__name(__facade_invokeChain__, "__facade_invokeChain__"); +function __facade_invoke__(request, env, ctx, dispatch, finalMiddleware) { + return __facade_invokeChain__(request, env, ctx, dispatch, [ + ...__facade_middleware__, + finalMiddleware + ]); +} +__name(__facade_invoke__, "__facade_invoke__"); + +// .wrangler/tmp/bundle-hfhVdy/middleware-loader.entry.ts +var __Facade_ScheduledController__ = class ___Facade_ScheduledController__ { + constructor(scheduledTime, cron, noRetry) { + this.scheduledTime = scheduledTime; + this.cron = cron; + this.#noRetry = noRetry; + } + scheduledTime; + cron; + static { + __name(this, "__Facade_ScheduledController__"); + } + #noRetry; + noRetry() { + if (!(this instanceof ___Facade_ScheduledController__)) { + throw new TypeError("Illegal invocation"); + } + this.#noRetry(); + } +}; +function wrapExportedHandler(worker) { + if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { + return worker; + } + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + const fetchDispatcher = /* @__PURE__ */ __name(function(request, env, ctx) { + if (worker.fetch === void 0) { + throw new Error("Handler does not export a fetch() function."); + } + return worker.fetch(request, env, ctx); + }, "fetchDispatcher"); + return { + ...worker, + fetch(request, env, ctx) { + const dispatcher = /* @__PURE__ */ __name(function(type, init) { + if (type === "scheduled" && worker.scheduled !== void 0) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => { + } + ); + return worker.scheduled(controller, env, ctx); + } + }, "dispatcher"); + return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); + } + }; +} +__name(wrapExportedHandler, "wrapExportedHandler"); +function wrapWorkerEntrypoint(klass) { + if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { + return klass; + } + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + return class extends klass { + #fetchDispatcher = /* @__PURE__ */ __name((request, env, ctx) => { + this.env = env; + this.ctx = ctx; + if (super.fetch === void 0) { + throw new Error("Entrypoint class does not define a fetch() function."); + } + return super.fetch(request); + }, "#fetchDispatcher"); + #dispatcher = /* @__PURE__ */ __name((type, init) => { + if (type === "scheduled" && super.scheduled !== void 0) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => { + } + ); + return super.scheduled(controller); + } + }, "#dispatcher"); + fetch(request) { + return __facade_invoke__( + request, + this.env, + this.ctx, + this.#dispatcher, + this.#fetchDispatcher + ); + } + }; +} +__name(wrapWorkerEntrypoint, "wrapWorkerEntrypoint"); +var WRAPPED_ENTRY; +if (typeof middleware_insertion_facade_default === "object") { + WRAPPED_ENTRY = wrapExportedHandler(middleware_insertion_facade_default); +} else if (typeof middleware_insertion_facade_default === "function") { + WRAPPED_ENTRY = wrapWorkerEntrypoint(middleware_insertion_facade_default); +} +var middleware_loader_entry_default = WRAPPED_ENTRY; +export { + __INTERNAL_WRANGLER_MIDDLEWARE__, + middleware_loader_entry_default as default +}; +//# sourceMappingURL=index.js.map diff --git a/.wrangler/tmp/dev-7xEpV1/index.js.map b/.wrangler/tmp/dev-7xEpV1/index.js.map new file mode 100644 index 0000000..3c1ea00 --- /dev/null +++ b/.wrangler/tmp/dev-7xEpV1/index.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": ["../../../src/data/config.json", "../../../worker/index.js", "../../../node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts", "../../../node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts", "../bundle-hfhVdy/middleware-insertion-facade.js", "../../../node_modules/wrangler/templates/middleware/common.ts", "../bundle-hfhVdy/middleware-loader.entry.ts"], + "sourceRoot": "/Users/brian/Code/personas/.wrangler/tmp/dev-7xEpV1", + "sourcesContent": ["{\n \"skinStyles\": [\n \"Skin\"\n ],\n \"hairStyles\": [\n \"Bald\",\n \"Hat\",\n \"Balding\",\n \"Bigcurls\",\n \"Bobbangs\",\n \"Bobcut\",\n \"Buncurls\",\n \"Buzzcut\",\n \"Curlybun\",\n \"Hightopcurly\",\n \"Long\",\n \"Pigtails\",\n \"Shortcombover\",\n \"Beanie\",\n \"Bunundercut\",\n \"Extralong\",\n \"Fade\",\n \"Mohawk\",\n \"Shortcomboverchops\",\n \"Sidebuzz\",\n \"Straightbun\"\n ],\n \"facialHairStyles\": [\n \"BeardMustache\",\n \"Mustache\",\n \"None\",\n \"Goatee\",\n \"Shadow\",\n \"Soulpatch\",\n \"Walrus\"\n ],\n \"bodyStyles\": [\n \"Oval\",\n \"Round\",\n \"Square\",\n \"Checkered\",\n \"Hoodie\",\n \"Stripes\"\n ],\n \"eyeStyles\": [\n \"Glasses\",\n \"Happy\",\n \"Open\",\n \"Sleepy\",\n \"Sunglasses\",\n \"Wink\",\n \"Closed\",\n \"Hearts\",\n \"Dizzy\",\n \"Sideeye\"\n ],\n \"mouthStyles\": [\n \"Bigsmile\",\n \"Frown\",\n \"Lips\",\n \"Pacifier\",\n \"Smile\",\n \"Smirk\",\n \"Surprise\",\n \"Grin\",\n \"Tongue\",\n \"Whistle\",\n \"Laugh\"\n ],\n \"noseStyles\": [\n \"Mediumround\",\n \"Smallround\",\n \"Wrinkles\",\n \"Pointed\",\n \"Button\"\n ],\n \"accessoryStyles\": [\n \"None\",\n \"Earring\",\n \"Earrings\"\n ],\n \"bgStyles\": [\n \"Background\"\n ],\n \"skinColors\": [\n \"FFCC22\",\n \"FFDFC4\",\n \"FBD2C7\",\n \"F2AD9B\",\n \"E58F7B\",\n \"E4A070\",\n \"B16A5B\",\n \"92594B\",\n \"7A4536\",\n \"623D36\",\n \"C9E6DC\",\n \"C4B5F2\"\n ],\n \"hairColors\": [\n \"362C47\",\n \"675E97\",\n \"4E7DE0\",\n \"5AC4D4\",\n \"58B368\",\n \"DEE1F5\",\n \"6C4545\",\n \"F29C65\",\n \"F2C94C\",\n \"E16381\",\n \"E15C66\",\n \"979FB0\"\n ],\n \"facialHairColors\": [\n \"362C47\",\n \"675E97\",\n \"4E7DE0\",\n \"5AC4D4\",\n \"58B368\",\n \"DEE1F5\",\n \"6C4545\",\n \"F29C65\",\n \"F2C94C\",\n \"E16381\",\n \"E15C66\",\n \"979FB0\"\n ],\n \"bodyColors\": [\n \"456DFF\",\n \"5A45FF\",\n \"6DBB58\",\n \"F55D81\",\n \"7555CA\",\n \"E24553\",\n \"54D7C7\",\n \"F3B63A\",\n \"FF8A5C\",\n \"3E4E7C\",\n \"C866D9\",\n \"68C9F2\"\n ],\n \"accessoryColors\": [\n \"F3B63A\",\n \"C9CFDB\",\n \"C98850\",\n \"362C47\",\n \"F55D81\",\n \"54D7C7\",\n \"456DFF\",\n \"5A45FF\"\n ],\n \"bgColors\": [\n \"93A7FF\",\n \"A9E775\",\n \"FF7A9A\",\n \"B379F7\",\n \"FF6674\",\n \"89E6E4\",\n \"FFCC65\",\n \"FFB27A\",\n \"B8EBC5\",\n \"D9CCFF\",\n \"6C7BC4\",\n \"F8FBFF\"\n ],\n \"disabledColors\": [\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\"\n ]\n}\n", "// Personas Worker: serves the static site plus a small API surface.\n//\n// Routes:\n// GET /api/options \u2014 valid style names and color palettes (JSON, CORS *)\n// GET / \u2014 short share link (base64url avatar code); serves the\n// SPA shell, which decodes the code client-side\n// everything else \u2014 static assets (with 404.html for misses)\n\nimport config from \"../src/data/config.json\";\n\n// Mirrors CODE_PATH in src/helpers/shareUrl.js. Real asset paths never\n// match: they contain \".\" or \"/\" (e.g. /favicon.png, /fonts/...).\nconst CODE_PATH = /^\\/[A-Za-z0-9_-]{8,64}$/;\n\nconst CORS = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n};\n\nexport default {\n async fetch(request, env) {\n const url = new URL(request.url);\n\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: CORS });\n }\n\n if (url.pathname === \"/api/options\") {\n return Response.json(config, {\n headers: { ...CORS, \"Cache-Control\": \"public, max-age=3600\" },\n });\n }\n\n if (request.method === \"GET\" && CODE_PATH.test(url.pathname)) {\n // Serve the app shell; the client decodes the code from the path.\n const shell = new URL(\"/\", url);\n return env.ASSETS.fetch(new Request(shell, request));\n }\n\n return env.ASSETS.fetch(request);\n },\n};\n", "import type { Middleware } from \"./common\";\n\nconst drainBody: Middleware = async (request, env, _ctx, middlewareCtx) => {\n\ttry {\n\t\treturn await middlewareCtx.next(request, env);\n\t} finally {\n\t\ttry {\n\t\t\tif (request.body !== null && !request.bodyUsed) {\n\t\t\t\tconst reader = request.body.getReader();\n\t\t\t\twhile (!(await reader.read()).done) {}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error(\"Failed to drain the unused request body.\", e);\n\t\t}\n\t}\n};\n\nexport default drainBody;\n", "import type { Middleware } from \"./common\";\n\ninterface JsonError {\n\tmessage?: string;\n\tname?: string;\n\tstack?: string;\n\tcause?: JsonError;\n}\n\nfunction reduceError(e: any): JsonError {\n\treturn {\n\t\tname: e?.name,\n\t\tmessage: e?.message ?? String(e),\n\t\tstack: e?.stack,\n\t\tcause: e?.cause === undefined ? undefined : reduceError(e.cause),\n\t};\n}\n\n// See comment in `bundle.ts` for details on why this is needed\nconst jsonError: Middleware = async (request, env, _ctx, middlewareCtx) => {\n\ttry {\n\t\treturn await middlewareCtx.next(request, env);\n\t} catch (e: any) {\n\t\tconst error = reduceError(e);\n\t\treturn Response.json(error, {\n\t\t\tstatus: 500,\n\t\t\theaders: { \"MF-Experimental-Error-Stack\": \"true\" },\n\t\t});\n\t}\n};\n\nexport default jsonError;\n", "\t\t\t\timport worker, * as OTHER_EXPORTS from \"/Users/brian/Code/personas/worker/index.js\";\n\t\t\t\timport * as __MIDDLEWARE_0__ from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts\";\nimport * as __MIDDLEWARE_1__ from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts\";\n\n\t\t\t\texport * from \"/Users/brian/Code/personas/worker/index.js\";\n\t\t\t\tconst MIDDLEWARE_TEST_INJECT = \"__INJECT_FOR_TESTING_WRANGLER_MIDDLEWARE__\";\n\t\t\t\texport const __INTERNAL_WRANGLER_MIDDLEWARE__ = [\n\t\t\t\t\t\n\t\t\t\t\t__MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default\n\t\t\t\t]\n\t\t\t\texport default worker;", "export type Awaitable = T | Promise;\n// TODO: allow dispatching more events?\nexport type Dispatcher = (\n\ttype: \"scheduled\",\n\tinit: { cron?: string }\n) => Awaitable;\n\nexport type IncomingRequest = Request<\n\tunknown,\n\tIncomingRequestCfProperties\n>;\n\nexport interface MiddlewareContext {\n\tdispatch: Dispatcher;\n\tnext(request: IncomingRequest, env: any): Awaitable;\n}\n\nexport type Middleware = (\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tmiddlewareCtx: MiddlewareContext\n) => Awaitable;\n\nconst __facade_middleware__: Middleware[] = [];\n\n// The register functions allow for the insertion of one or many middleware,\n// We register internal middleware first in the stack, but have no way of controlling\n// the order that addMiddleware is run in service workers so need an internal function.\nexport function __facade_register__(...args: (Middleware | Middleware[])[]) {\n\t__facade_middleware__.push(...args.flat());\n}\nexport function __facade_registerInternal__(\n\t...args: (Middleware | Middleware[])[]\n) {\n\t__facade_middleware__.unshift(...args.flat());\n}\n\nfunction __facade_invokeChain__(\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tdispatch: Dispatcher,\n\tmiddlewareChain: Middleware[]\n): Awaitable {\n\tconst [head, ...tail] = middlewareChain;\n\tconst middlewareCtx: MiddlewareContext = {\n\t\tdispatch,\n\t\tnext(newRequest, newEnv) {\n\t\t\treturn __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail);\n\t\t},\n\t};\n\treturn head(request, env, ctx, middlewareCtx);\n}\n\nexport function __facade_invoke__(\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tdispatch: Dispatcher,\n\tfinalMiddleware: Middleware\n): Awaitable {\n\treturn __facade_invokeChain__(request, env, ctx, dispatch, [\n\t\t...__facade_middleware__,\n\t\tfinalMiddleware,\n\t]);\n}\n", "// This loads all middlewares exposed on the middleware object and then starts\n// the invocation chain. The big idea is that we can add these to the middleware\n// export dynamically through wrangler, or we can potentially let users directly\n// add them as a sort of \"plugin\" system.\n\nimport ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js\";\nimport { __facade_invoke__, __facade_register__, Dispatcher } from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/common.ts\";\nimport type { WorkerEntrypointConstructor } from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js\";\n\n// Preserve all the exports from the worker\nexport * from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-hfhVdy/middleware-insertion-facade.js\";\n\nclass __Facade_ScheduledController__ implements ScheduledController {\n\treadonly #noRetry: ScheduledController[\"noRetry\"];\n\n\tconstructor(\n\t\treadonly scheduledTime: number,\n\t\treadonly cron: string,\n\t\tnoRetry: ScheduledController[\"noRetry\"]\n\t) {\n\t\tthis.#noRetry = noRetry;\n\t}\n\n\tnoRetry() {\n\t\tif (!(this instanceof __Facade_ScheduledController__)) {\n\t\t\tthrow new TypeError(\"Illegal invocation\");\n\t\t}\n\t\t// Need to call native method immediately in case uncaught error thrown\n\t\tthis.#noRetry();\n\t}\n}\n\nfunction wrapExportedHandler(worker: ExportedHandler): ExportedHandler {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn worker;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\tconst fetchDispatcher: ExportedHandlerFetchHandler = function (\n\t\trequest,\n\t\tenv,\n\t\tctx\n\t) {\n\t\tif (worker.fetch === undefined) {\n\t\t\tthrow new Error(\"Handler does not export a fetch() function.\");\n\t\t}\n\t\treturn worker.fetch(request, env, ctx);\n\t};\n\n\treturn {\n\t\t...worker,\n\t\tfetch(request, env, ctx) {\n\t\t\tconst dispatcher: Dispatcher = function (type, init) {\n\t\t\t\tif (type === \"scheduled\" && worker.scheduled !== undefined) {\n\t\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\t\tDate.now(),\n\t\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t\t() => {}\n\t\t\t\t\t);\n\t\t\t\t\treturn worker.scheduled(controller, env, ctx);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher);\n\t\t},\n\t};\n}\n\nfunction wrapWorkerEntrypoint(\n\tklass: WorkerEntrypointConstructor\n): WorkerEntrypointConstructor {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn klass;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\t// `extend`ing `klass` here so other RPC methods remain callable\n\treturn class extends klass {\n\t\t#fetchDispatcher: ExportedHandlerFetchHandler> = (\n\t\t\trequest,\n\t\t\tenv,\n\t\t\tctx\n\t\t) => {\n\t\t\tthis.env = env;\n\t\t\tthis.ctx = ctx;\n\t\t\tif (super.fetch === undefined) {\n\t\t\t\tthrow new Error(\"Entrypoint class does not define a fetch() function.\");\n\t\t\t}\n\t\t\treturn super.fetch(request);\n\t\t};\n\n\t\t#dispatcher: Dispatcher = (type, init) => {\n\t\t\tif (type === \"scheduled\" && super.scheduled !== undefined) {\n\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\tDate.now(),\n\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t() => {}\n\t\t\t\t);\n\t\t\t\treturn super.scheduled(controller);\n\t\t\t}\n\t\t};\n\n\t\tfetch(request: Request) {\n\t\t\treturn __facade_invoke__(\n\t\t\t\trequest,\n\t\t\t\tthis.env,\n\t\t\t\tthis.ctx,\n\t\t\t\tthis.#dispatcher,\n\t\t\t\tthis.#fetchDispatcher\n\t\t\t);\n\t\t}\n\t};\n}\n\nlet WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined;\nif (typeof ENTRY === \"object\") {\n\tWRAPPED_ENTRY = wrapExportedHandler(ENTRY);\n} else if (typeof ENTRY === \"function\") {\n\tWRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY);\n}\nexport default WRAPPED_ENTRY;\n"], + "mappings": "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", + "names": [] +} diff --git a/.wrangler/tmp/dev-NwJonP/index.js b/.wrangler/tmp/dev-NwJonP/index.js new file mode 100644 index 0000000..8e37500 --- /dev/null +++ b/.wrangler/tmp/dev-NwJonP/index.js @@ -0,0 +1,382 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); + +// src/data/config.json +var config_default = { + skinStyles: [ + "Skin" + ], + hairStyles: [ + "Bald", + "Hat", + "Balding", + "Bigcurls", + "Bobbangs", + "Bobcut", + "Buncurls", + "Buzzcut", + "Curlybun", + "Hightopcurly", + "Long", + "Pigtails", + "Shortcombover", + "Beanie", + "Bunundercut", + "Extralong", + "Fade", + "Mohawk", + "Shortcomboverchops", + "Sidebuzz", + "Straightbun" + ], + facialHairStyles: [ + "BeardMustache", + "Mustache", + "None", + "Goatee", + "Shadow", + "Soulpatch", + "Walrus" + ], + bodyStyles: [ + "Oval", + "Round", + "Square", + "Checkered", + "Hoodie", + "Stripes" + ], + eyeStyles: [ + "Glasses", + "Happy", + "Open", + "Sleepy", + "Sunglasses", + "Wink", + "Closed", + "Hearts", + "Dizzy", + "Sideeye" + ], + mouthStyles: [ + "Bigsmile", + "Frown", + "Lips", + "Pacifier", + "Smile", + "Smirk", + "Surprise", + "Grin", + "Tongue", + "Whistle", + "Laugh" + ], + noseStyles: [ + "Mediumround", + "Smallround", + "Wrinkles", + "Pointed", + "Button" + ], + accessoryStyles: [ + "None", + "Earring", + "Earrings" + ], + bgStyles: [ + "Background" + ], + skinColors: [ + "FFCC22", + "FFDFC4", + "FBD2C7", + "F2AD9B", + "E58F7B", + "E4A070", + "B16A5B", + "92594B", + "7A4536", + "623D36", + "C9E6DC", + "C4B5F2" + ], + hairColors: [ + "362C47", + "675E97", + "4E7DE0", + "5AC4D4", + "58B368", + "DEE1F5", + "6C4545", + "F29C65", + "F2C94C", + "E16381", + "E15C66", + "979FB0" + ], + facialHairColors: [ + "362C47", + "675E97", + "4E7DE0", + "5AC4D4", + "58B368", + "DEE1F5", + "6C4545", + "F29C65", + "F2C94C", + "E16381", + "E15C66", + "979FB0" + ], + bodyColors: [ + "456DFF", + "5A45FF", + "6DBB58", + "F55D81", + "7555CA", + "E24553", + "54D7C7", + "F3B63A", + "FF8A5C", + "3E4E7C", + "C866D9", + "68C9F2" + ], + accessoryColors: [ + "F3B63A", + "C9CFDB", + "C98850", + "362C47", + "F55D81", + "54D7C7", + "456DFF", + "5A45FF" + ], + bgColors: [ + "93A7FF", + "A9E775", + "FF7A9A", + "B379F7", + "FF6674", + "89E6E4", + "FFCC65", + "FFB27A", + "B8EBC5", + "D9CCFF", + "6C7BC4", + "F8FBFF" + ], + disabledColors: [ + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5", + "EEEFF5" + ] +}; + +// worker/index.js +var CODE_PATH = /^\/[A-Za-z0-9_-]{8,64}$/; +var CORS = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type" +}; +var worker_default = { + async fetch(request, env) { + const url = new URL(request.url); + if (request.method === "OPTIONS") { + return new Response(null, { headers: CORS }); + } + if (url.pathname === "/api/options") { + return Response.json(config_default, { + headers: { ...CORS, "Cache-Control": "public, max-age=3600" } + }); + } + if (request.method === "GET" && CODE_PATH.test(url.pathname)) { + const shell = new URL("/", url); + return env.ASSETS.fetch(new Request(shell, request)); + } + return env.ASSETS.fetch(request); + } +}; + +// node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts +var drainBody = /* @__PURE__ */ __name(async (request, env, _ctx, middlewareCtx) => { + try { + return await middlewareCtx.next(request, env); + } finally { + try { + if (request.body !== null && !request.bodyUsed) { + const reader = request.body.getReader(); + while (!(await reader.read()).done) { + } + } + } catch (e) { + console.error("Failed to drain the unused request body.", e); + } + } +}, "drainBody"); +var middleware_ensure_req_body_drained_default = drainBody; + +// node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts +function reduceError(e) { + return { + name: e?.name, + message: e?.message ?? String(e), + stack: e?.stack, + cause: e?.cause === void 0 ? void 0 : reduceError(e.cause) + }; +} +__name(reduceError, "reduceError"); +var jsonError = /* @__PURE__ */ __name(async (request, env, _ctx, middlewareCtx) => { + try { + return await middlewareCtx.next(request, env); + } catch (e) { + const error = reduceError(e); + return Response.json(error, { + status: 500, + headers: { "MF-Experimental-Error-Stack": "true" } + }); + } +}, "jsonError"); +var middleware_miniflare3_json_error_default = jsonError; + +// .wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js +var __INTERNAL_WRANGLER_MIDDLEWARE__ = [ + middleware_ensure_req_body_drained_default, + middleware_miniflare3_json_error_default +]; +var middleware_insertion_facade_default = worker_default; + +// node_modules/wrangler/templates/middleware/common.ts +var __facade_middleware__ = []; +function __facade_register__(...args) { + __facade_middleware__.push(...args.flat()); +} +__name(__facade_register__, "__facade_register__"); +function __facade_invokeChain__(request, env, ctx, dispatch, middlewareChain) { + const [head, ...tail] = middlewareChain; + const middlewareCtx = { + dispatch, + next(newRequest, newEnv) { + return __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail); + } + }; + return head(request, env, ctx, middlewareCtx); +} +__name(__facade_invokeChain__, "__facade_invokeChain__"); +function __facade_invoke__(request, env, ctx, dispatch, finalMiddleware) { + return __facade_invokeChain__(request, env, ctx, dispatch, [ + ...__facade_middleware__, + finalMiddleware + ]); +} +__name(__facade_invoke__, "__facade_invoke__"); + +// .wrangler/tmp/bundle-uax8ND/middleware-loader.entry.ts +var __Facade_ScheduledController__ = class ___Facade_ScheduledController__ { + constructor(scheduledTime, cron, noRetry) { + this.scheduledTime = scheduledTime; + this.cron = cron; + this.#noRetry = noRetry; + } + scheduledTime; + cron; + static { + __name(this, "__Facade_ScheduledController__"); + } + #noRetry; + noRetry() { + if (!(this instanceof ___Facade_ScheduledController__)) { + throw new TypeError("Illegal invocation"); + } + this.#noRetry(); + } +}; +function wrapExportedHandler(worker) { + if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { + return worker; + } + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + const fetchDispatcher = /* @__PURE__ */ __name(function(request, env, ctx) { + if (worker.fetch === void 0) { + throw new Error("Handler does not export a fetch() function."); + } + return worker.fetch(request, env, ctx); + }, "fetchDispatcher"); + return { + ...worker, + fetch(request, env, ctx) { + const dispatcher = /* @__PURE__ */ __name(function(type, init) { + if (type === "scheduled" && worker.scheduled !== void 0) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => { + } + ); + return worker.scheduled(controller, env, ctx); + } + }, "dispatcher"); + return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); + } + }; +} +__name(wrapExportedHandler, "wrapExportedHandler"); +function wrapWorkerEntrypoint(klass) { + if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { + return klass; + } + for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { + __facade_register__(middleware); + } + return class extends klass { + #fetchDispatcher = /* @__PURE__ */ __name((request, env, ctx) => { + this.env = env; + this.ctx = ctx; + if (super.fetch === void 0) { + throw new Error("Entrypoint class does not define a fetch() function."); + } + return super.fetch(request); + }, "#fetchDispatcher"); + #dispatcher = /* @__PURE__ */ __name((type, init) => { + if (type === "scheduled" && super.scheduled !== void 0) { + const controller = new __Facade_ScheduledController__( + Date.now(), + init.cron ?? "", + () => { + } + ); + return super.scheduled(controller); + } + }, "#dispatcher"); + fetch(request) { + return __facade_invoke__( + request, + this.env, + this.ctx, + this.#dispatcher, + this.#fetchDispatcher + ); + } + }; +} +__name(wrapWorkerEntrypoint, "wrapWorkerEntrypoint"); +var WRAPPED_ENTRY; +if (typeof middleware_insertion_facade_default === "object") { + WRAPPED_ENTRY = wrapExportedHandler(middleware_insertion_facade_default); +} else if (typeof middleware_insertion_facade_default === "function") { + WRAPPED_ENTRY = wrapWorkerEntrypoint(middleware_insertion_facade_default); +} +var middleware_loader_entry_default = WRAPPED_ENTRY; +export { + __INTERNAL_WRANGLER_MIDDLEWARE__, + middleware_loader_entry_default as default +}; +//# sourceMappingURL=index.js.map diff --git a/.wrangler/tmp/dev-NwJonP/index.js.map b/.wrangler/tmp/dev-NwJonP/index.js.map new file mode 100644 index 0000000..496dcca --- /dev/null +++ b/.wrangler/tmp/dev-NwJonP/index.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": ["../../../src/data/config.json", "../../../worker/index.js", "../../../node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts", "../../../node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts", "../bundle-uax8ND/middleware-insertion-facade.js", "../../../node_modules/wrangler/templates/middleware/common.ts", "../bundle-uax8ND/middleware-loader.entry.ts"], + "sourceRoot": "/Users/brian/Code/personas/.wrangler/tmp/dev-NwJonP", + "sourcesContent": ["{\n \"skinStyles\": [\n \"Skin\"\n ],\n \"hairStyles\": [\n \"Bald\",\n \"Hat\",\n \"Balding\",\n \"Bigcurls\",\n \"Bobbangs\",\n \"Bobcut\",\n \"Buncurls\",\n \"Buzzcut\",\n \"Curlybun\",\n \"Hightopcurly\",\n \"Long\",\n \"Pigtails\",\n \"Shortcombover\",\n \"Beanie\",\n \"Bunundercut\",\n \"Extralong\",\n \"Fade\",\n \"Mohawk\",\n \"Shortcomboverchops\",\n \"Sidebuzz\",\n \"Straightbun\"\n ],\n \"facialHairStyles\": [\n \"BeardMustache\",\n \"Mustache\",\n \"None\",\n \"Goatee\",\n \"Shadow\",\n \"Soulpatch\",\n \"Walrus\"\n ],\n \"bodyStyles\": [\n \"Oval\",\n \"Round\",\n \"Square\",\n \"Checkered\",\n \"Hoodie\",\n \"Stripes\"\n ],\n \"eyeStyles\": [\n \"Glasses\",\n \"Happy\",\n \"Open\",\n \"Sleepy\",\n \"Sunglasses\",\n \"Wink\",\n \"Closed\",\n \"Hearts\",\n \"Dizzy\",\n \"Sideeye\"\n ],\n \"mouthStyles\": [\n \"Bigsmile\",\n \"Frown\",\n \"Lips\",\n \"Pacifier\",\n \"Smile\",\n \"Smirk\",\n \"Surprise\",\n \"Grin\",\n \"Tongue\",\n \"Whistle\",\n \"Laugh\"\n ],\n \"noseStyles\": [\n \"Mediumround\",\n \"Smallround\",\n \"Wrinkles\",\n \"Pointed\",\n \"Button\"\n ],\n \"accessoryStyles\": [\n \"None\",\n \"Earring\",\n \"Earrings\"\n ],\n \"bgStyles\": [\n \"Background\"\n ],\n \"skinColors\": [\n \"FFCC22\",\n \"FFDFC4\",\n \"FBD2C7\",\n \"F2AD9B\",\n \"E58F7B\",\n \"E4A070\",\n \"B16A5B\",\n \"92594B\",\n \"7A4536\",\n \"623D36\",\n \"C9E6DC\",\n \"C4B5F2\"\n ],\n \"hairColors\": [\n \"362C47\",\n \"675E97\",\n \"4E7DE0\",\n \"5AC4D4\",\n \"58B368\",\n \"DEE1F5\",\n \"6C4545\",\n \"F29C65\",\n \"F2C94C\",\n \"E16381\",\n \"E15C66\",\n \"979FB0\"\n ],\n \"facialHairColors\": [\n \"362C47\",\n \"675E97\",\n \"4E7DE0\",\n \"5AC4D4\",\n \"58B368\",\n \"DEE1F5\",\n \"6C4545\",\n \"F29C65\",\n \"F2C94C\",\n \"E16381\",\n \"E15C66\",\n \"979FB0\"\n ],\n \"bodyColors\": [\n \"456DFF\",\n \"5A45FF\",\n \"6DBB58\",\n \"F55D81\",\n \"7555CA\",\n \"E24553\",\n \"54D7C7\",\n \"F3B63A\",\n \"FF8A5C\",\n \"3E4E7C\",\n \"C866D9\",\n \"68C9F2\"\n ],\n \"accessoryColors\": [\n \"F3B63A\",\n \"C9CFDB\",\n \"C98850\",\n \"362C47\",\n \"F55D81\",\n \"54D7C7\",\n \"456DFF\",\n \"5A45FF\"\n ],\n \"bgColors\": [\n \"93A7FF\",\n \"A9E775\",\n \"FF7A9A\",\n \"B379F7\",\n \"FF6674\",\n \"89E6E4\",\n \"FFCC65\",\n \"FFB27A\",\n \"B8EBC5\",\n \"D9CCFF\",\n \"6C7BC4\",\n \"F8FBFF\"\n ],\n \"disabledColors\": [\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\",\n \"EEEFF5\"\n ]\n}\n", "// Personas Worker: serves the static site plus a small API surface.\n//\n// Routes:\n// GET /api/options \u2014 valid style names and color palettes (JSON, CORS *)\n// GET / \u2014 short share link (base64url avatar code); serves the\n// SPA shell, which decodes the code client-side\n// everything else \u2014 static assets (with 404.html for misses)\n\nimport config from \"../src/data/config.json\";\n\n// Mirrors CODE_PATH in src/helpers/shareUrl.js. Real asset paths never\n// match: they contain \".\" or \"/\" (e.g. /favicon.png, /fonts/...).\nconst CODE_PATH = /^\\/[A-Za-z0-9_-]{8,64}$/;\n\nconst CORS = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n};\n\nexport default {\n async fetch(request, env) {\n const url = new URL(request.url);\n\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: CORS });\n }\n\n if (url.pathname === \"/api/options\") {\n return Response.json(config, {\n headers: { ...CORS, \"Cache-Control\": \"public, max-age=3600\" },\n });\n }\n\n if (request.method === \"GET\" && CODE_PATH.test(url.pathname)) {\n // Serve the app shell; the client decodes the code from the path.\n const shell = new URL(\"/\", url);\n return env.ASSETS.fetch(new Request(shell, request));\n }\n\n return env.ASSETS.fetch(request);\n },\n};\n", "import type { Middleware } from \"./common\";\n\nconst drainBody: Middleware = async (request, env, _ctx, middlewareCtx) => {\n\ttry {\n\t\treturn await middlewareCtx.next(request, env);\n\t} finally {\n\t\ttry {\n\t\t\tif (request.body !== null && !request.bodyUsed) {\n\t\t\t\tconst reader = request.body.getReader();\n\t\t\t\twhile (!(await reader.read()).done) {}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error(\"Failed to drain the unused request body.\", e);\n\t\t}\n\t}\n};\n\nexport default drainBody;\n", "import type { Middleware } from \"./common\";\n\ninterface JsonError {\n\tmessage?: string;\n\tname?: string;\n\tstack?: string;\n\tcause?: JsonError;\n}\n\nfunction reduceError(e: any): JsonError {\n\treturn {\n\t\tname: e?.name,\n\t\tmessage: e?.message ?? String(e),\n\t\tstack: e?.stack,\n\t\tcause: e?.cause === undefined ? undefined : reduceError(e.cause),\n\t};\n}\n\n// See comment in `bundle.ts` for details on why this is needed\nconst jsonError: Middleware = async (request, env, _ctx, middlewareCtx) => {\n\ttry {\n\t\treturn await middlewareCtx.next(request, env);\n\t} catch (e: any) {\n\t\tconst error = reduceError(e);\n\t\treturn Response.json(error, {\n\t\t\tstatus: 500,\n\t\t\theaders: { \"MF-Experimental-Error-Stack\": \"true\" },\n\t\t});\n\t}\n};\n\nexport default jsonError;\n", "\t\t\t\timport worker, * as OTHER_EXPORTS from \"/Users/brian/Code/personas/worker/index.js\";\n\t\t\t\timport * as __MIDDLEWARE_0__ from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts\";\nimport * as __MIDDLEWARE_1__ from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts\";\n\n\t\t\t\texport * from \"/Users/brian/Code/personas/worker/index.js\";\n\t\t\t\tconst MIDDLEWARE_TEST_INJECT = \"__INJECT_FOR_TESTING_WRANGLER_MIDDLEWARE__\";\n\t\t\t\texport const __INTERNAL_WRANGLER_MIDDLEWARE__ = [\n\t\t\t\t\t\n\t\t\t\t\t__MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default\n\t\t\t\t]\n\t\t\t\texport default worker;", "export type Awaitable = T | Promise;\n// TODO: allow dispatching more events?\nexport type Dispatcher = (\n\ttype: \"scheduled\",\n\tinit: { cron?: string }\n) => Awaitable;\n\nexport type IncomingRequest = Request<\n\tunknown,\n\tIncomingRequestCfProperties\n>;\n\nexport interface MiddlewareContext {\n\tdispatch: Dispatcher;\n\tnext(request: IncomingRequest, env: any): Awaitable;\n}\n\nexport type Middleware = (\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tmiddlewareCtx: MiddlewareContext\n) => Awaitable;\n\nconst __facade_middleware__: Middleware[] = [];\n\n// The register functions allow for the insertion of one or many middleware,\n// We register internal middleware first in the stack, but have no way of controlling\n// the order that addMiddleware is run in service workers so need an internal function.\nexport function __facade_register__(...args: (Middleware | Middleware[])[]) {\n\t__facade_middleware__.push(...args.flat());\n}\nexport function __facade_registerInternal__(\n\t...args: (Middleware | Middleware[])[]\n) {\n\t__facade_middleware__.unshift(...args.flat());\n}\n\nfunction __facade_invokeChain__(\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tdispatch: Dispatcher,\n\tmiddlewareChain: Middleware[]\n): Awaitable {\n\tconst [head, ...tail] = middlewareChain;\n\tconst middlewareCtx: MiddlewareContext = {\n\t\tdispatch,\n\t\tnext(newRequest, newEnv) {\n\t\t\treturn __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail);\n\t\t},\n\t};\n\treturn head(request, env, ctx, middlewareCtx);\n}\n\nexport function __facade_invoke__(\n\trequest: IncomingRequest,\n\tenv: any,\n\tctx: ExecutionContext,\n\tdispatch: Dispatcher,\n\tfinalMiddleware: Middleware\n): Awaitable {\n\treturn __facade_invokeChain__(request, env, ctx, dispatch, [\n\t\t...__facade_middleware__,\n\t\tfinalMiddleware,\n\t]);\n}\n", "// This loads all middlewares exposed on the middleware object and then starts\n// the invocation chain. The big idea is that we can add these to the middleware\n// export dynamically through wrangler, or we can potentially let users directly\n// add them as a sort of \"plugin\" system.\n\nimport ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js\";\nimport { __facade_invoke__, __facade_register__, Dispatcher } from \"/Users/brian/Code/personas/node_modules/wrangler/templates/middleware/common.ts\";\nimport type { WorkerEntrypointConstructor } from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js\";\n\n// Preserve all the exports from the worker\nexport * from \"/Users/brian/Code/personas/.wrangler/tmp/bundle-uax8ND/middleware-insertion-facade.js\";\n\nclass __Facade_ScheduledController__ implements ScheduledController {\n\treadonly #noRetry: ScheduledController[\"noRetry\"];\n\n\tconstructor(\n\t\treadonly scheduledTime: number,\n\t\treadonly cron: string,\n\t\tnoRetry: ScheduledController[\"noRetry\"]\n\t) {\n\t\tthis.#noRetry = noRetry;\n\t}\n\n\tnoRetry() {\n\t\tif (!(this instanceof __Facade_ScheduledController__)) {\n\t\t\tthrow new TypeError(\"Illegal invocation\");\n\t\t}\n\t\t// Need to call native method immediately in case uncaught error thrown\n\t\tthis.#noRetry();\n\t}\n}\n\nfunction wrapExportedHandler(worker: ExportedHandler): ExportedHandler {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn worker;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\tconst fetchDispatcher: ExportedHandlerFetchHandler = function (\n\t\trequest,\n\t\tenv,\n\t\tctx\n\t) {\n\t\tif (worker.fetch === undefined) {\n\t\t\tthrow new Error(\"Handler does not export a fetch() function.\");\n\t\t}\n\t\treturn worker.fetch(request, env, ctx);\n\t};\n\n\treturn {\n\t\t...worker,\n\t\tfetch(request, env, ctx) {\n\t\t\tconst dispatcher: Dispatcher = function (type, init) {\n\t\t\t\tif (type === \"scheduled\" && worker.scheduled !== undefined) {\n\t\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\t\tDate.now(),\n\t\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t\t() => {}\n\t\t\t\t\t);\n\t\t\t\t\treturn worker.scheduled(controller, env, ctx);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher);\n\t\t},\n\t};\n}\n\nfunction wrapWorkerEntrypoint(\n\tklass: WorkerEntrypointConstructor\n): WorkerEntrypointConstructor {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn klass;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\t// `extend`ing `klass` here so other RPC methods remain callable\n\treturn class extends klass {\n\t\t#fetchDispatcher: ExportedHandlerFetchHandler> = (\n\t\t\trequest,\n\t\t\tenv,\n\t\t\tctx\n\t\t) => {\n\t\t\tthis.env = env;\n\t\t\tthis.ctx = ctx;\n\t\t\tif (super.fetch === undefined) {\n\t\t\t\tthrow new Error(\"Entrypoint class does not define a fetch() function.\");\n\t\t\t}\n\t\t\treturn super.fetch(request);\n\t\t};\n\n\t\t#dispatcher: Dispatcher = (type, init) => {\n\t\t\tif (type === \"scheduled\" && super.scheduled !== undefined) {\n\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\tDate.now(),\n\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t() => {}\n\t\t\t\t);\n\t\t\t\treturn super.scheduled(controller);\n\t\t\t}\n\t\t};\n\n\t\tfetch(request: Request) {\n\t\t\treturn __facade_invoke__(\n\t\t\t\trequest,\n\t\t\t\tthis.env,\n\t\t\t\tthis.ctx,\n\t\t\t\tthis.#dispatcher,\n\t\t\t\tthis.#fetchDispatcher\n\t\t\t);\n\t\t}\n\t};\n}\n\nlet WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined;\nif (typeof ENTRY === \"object\") {\n\tWRAPPED_ENTRY = wrapExportedHandler(ENTRY);\n} else if (typeof ENTRY === \"function\") {\n\tWRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY);\n}\nexport default WRAPPED_ENTRY;\n"], + "mappings": "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", + "names": [] +} diff --git a/src/components/App.res b/src/components/App.res index 9f7bf35..6442d8b 100644 --- a/src/components/App.res +++ b/src/components/App.res @@ -5,6 +5,7 @@ let make = ( ~onExport, ~onChange, ~randomize, + ~shareUrl: string, ~styles: Types.styles, ~config: Types.config, ) => { @@ -122,6 +123,6 @@ let make = (
- + } diff --git a/src/components/Modal.res b/src/components/Modal.res index ed34292..481ed4c 100644 --- a/src/components/Modal.res +++ b/src/components/Modal.res @@ -1,17 +1,14 @@ %%raw(`import "./Modal.css"`) -@val @scope(("window", "location")) -external locationHref: string = "href" - @val @scope(("navigator", "clipboard")) external writeText: string => promise = "writeText" @react.component -let make = (~visible, ~onToggle) => { +let make = (~visible, ~onToggle, ~shareUrl: string) => { let (copied, setCopied) = React.useState(_ => false) let copyLink = _ => { - writeText(locationHref)->ignore + writeText(shareUrl)->ignore setCopied(_ => true) let _ = Js.Global.setTimeout(() => setCopied(_ => false), 2000) } @@ -35,7 +32,7 @@ let make = (~visible, ~onToggle) => { target="_blank" rel="no-follow" href={"https://twitter.com/intent/tweet?text=I+made+this+avatar+with+Personas+by+@Draftbit&url=" ++ - Js.Global.encodeURIComponent(locationHref) ++ "&related=draftbit"} + Js.Global.encodeURIComponent(shareUrl) ++ "&related=draftbit"} className="Modal-button Modal-button--twitter"> {React.string("Twitter")} diff --git a/src/helpers/shareUrl.js b/src/helpers/shareUrl.js index 2c7aa6d..30120b3 100644 --- a/src/helpers/shareUrl.js +++ b/src/helpers/shareUrl.js @@ -1,8 +1,19 @@ // Serialize avatar styles to/from the URL so avatars are shareable links. // +// Two forms: +// - Readable query params (?hair=Mohawk&hairColor=F2C94C...) — what the +// address bar shows; self-documenting and constructable by hand. +// - Compact short code (personas.draftbit.com/) — a bit-packed, +// base64url encoding of the same config, used by the share buttons. +// // Values are validated on read: style names must exist in config, colors // must be 6-digit hex (they get interpolated into inline SVG markup, so // nothing else may pass). +// +// IMPORTANT: the short code stores *indices* into the config.json arrays, +// so those arrays are append-only. Never remove or reorder entries once +// shipped — only append. If a breaking change is ever unavoidable, bump +// CODE_VERSION and add a migration path for old codes. const HEX = /^[0-9A-Fa-f]{6}$/; @@ -25,10 +36,125 @@ const COLOR_KEYS = [ "bgColor", ]; -// Overlay any valid params from the current URL onto `base` (a full -// styles record, e.g. a random one). Colors are validated by shape, not -// against the palette, so custom-picked colors stay shareable. +// --------------------------------------------------------------------------- +// Compact code v1 +// +// Bit layout, in order: +// 4 version (currently 1) +// style indices into config arrays: +// 5 hair · 4 facialHair · 4 body · 4 eyes · 4 mouth · 4 nose · 3 accessories +// 6 colors in COLOR_KEYS order, each: +// 1 flag · (0 → 5-bit palette index | 1 → 24-bit raw hex) +// +// Palette-only avatars encode to 12 chars; 6 custom colors max out at 31. +// --------------------------------------------------------------------------- + +const CODE_VERSION = 1; +const B64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +export const CODE_PATH = /^\/([A-Za-z0-9_-]{8,64})$/; + +const STYLE_FIELDS = [ + ["hair", "hairStyles", 5], + ["facialHair", "facialHairStyles", 4], + ["body", "bodyStyles", 4], + ["eyes", "eyeStyles", 4], + ["mouth", "mouthStyles", 4], + ["nose", "noseStyles", 4], + ["accessories", "accessoryStyles", 3], +]; + +const COLOR_FIELDS = [ + ["skinColor", "skinColors"], + ["hairColor", "hairColors"], + ["facialHairColor", "facialHairColors"], + ["bodyColor", "bodyColors"], + ["accessoriesColor", "accessoryColors"], + ["bgColor", "bgColors"], +]; + +export function encodeStylesToCode(config, styles) { + let bits = CODE_VERSION.toString(2).padStart(4, "0"); + for (const [key, listKey, width] of STYLE_FIELDS) { + const idx = config[listKey].indexOf(styles[key]); + if (idx < 0 || idx >= 1 << width) return null; + bits += idx.toString(2).padStart(width, "0"); + } + for (const [key, listKey] of COLOR_FIELDS) { + const color = styles[key]; + if (!HEX.test(color)) return null; + const idx = config[listKey].indexOf(color.toUpperCase()); + if (idx >= 0 && idx < 32) { + bits += "0" + idx.toString(2).padStart(5, "0"); + } else { + bits += "1" + parseInt(color, 16).toString(2).padStart(24, "0"); + } + } + let code = ""; + for (let i = 0; i < bits.length; i += 6) { + code += B64URL[parseInt(bits.slice(i, i + 6).padEnd(6, "0"), 2)]; + } + return code; +} + +export function decodeCodeToStyles(config, code) { + if (!/^[A-Za-z0-9_-]{8,64}$/.test(code)) return null; + let bits = ""; + for (const ch of code) { + bits += B64URL.indexOf(ch).toString(2).padStart(6, "0"); + } + let pos = 0; + const read = (width) => { + if (pos + width > bits.length) return null; + const v = parseInt(bits.slice(pos, pos + width), 2); + pos += width; + return v; + }; + if (read(4) !== CODE_VERSION) return null; + const styles = { skin: "Skin", head: "Head" }; + for (const [key, listKey, width] of STYLE_FIELDS) { + const idx = read(width); + if (idx === null || idx >= config[listKey].length) return null; + styles[key] = config[listKey][idx]; + } + for (const [key, listKey] of COLOR_FIELDS) { + const flag = read(1); + if (flag === null) return null; + if (flag === 0) { + const idx = read(5); + if (idx === null || idx >= config[listKey].length) return null; + styles[key] = config[listKey][idx]; + } else { + const raw = read(24); + if (raw === null) return null; + styles[key] = raw.toString(16).toUpperCase().padStart(6, "0"); + } + } + return styles; +} + +// The short share URL for the current avatar; falls back to the readable +// query-param form if the config ever outgrows the code's index widths. +export function shortShareUrl(config, styles) { + const code = encodeStylesToCode(config, styles); + if (code) return window.location.origin + "/" + code; + return window.location.origin + "/?" + stylesToParams(styles).toString(); +} + +function stylesToParams(styles) { + const params = new URLSearchParams(); + for (const [key] of STYLE_KEYS) params.set(key, styles[key]); + for (const key of COLOR_KEYS) params.set(key, styles[key]); + return params; +} + +// Resolve the initial styles: a short code in the path wins, then query +// params overlay onto `base` (a full random styles record). export function readStylesFromUrl(config, base) { + const m = window.location.pathname.match(CODE_PATH); + if (m) { + const decoded = decodeCodeToStyles(config, m[1]); + if (decoded) return { ...base, ...decoded }; + } const params = new URLSearchParams(window.location.search); const styles = { ...base }; for (const [key, listKey] of STYLE_KEYS) { @@ -43,8 +169,6 @@ export function readStylesFromUrl(config, base) { } export function writeStylesToUrl(styles) { - const params = new URLSearchParams(); - for (const [key] of STYLE_KEYS) params.set(key, styles[key]); - for (const key of COLOR_KEYS) params.set(key, styles[key]); - window.history.replaceState(null, "", "?" + params.toString()); + // Absolute path: also normalizes away a short-code pathname after boot. + window.history.replaceState(null, "", "/?" + stylesToParams(styles).toString()); } diff --git a/src/pages/Index.res b/src/pages/Index.res index 3137cb3..41feaa0 100644 --- a/src/pages/Index.res +++ b/src/pages/Index.res @@ -10,6 +10,9 @@ external readStylesFromUrl: (Types.config, Types.styles) => Types.styles = "read @module("../helpers/shareUrl.js") external writeStylesToUrl: Types.styles => unit = "writeStylesToUrl" +@module("../helpers/shareUrl.js") +external shortShareUrl: (Types.config, Types.styles) => string = "shortShareUrl" + let randomizeStyles = (config: Types.config): Types.styles => { let getRandom = _list => { let len = Array.length(_list) @@ -79,6 +82,7 @@ let make = () => { config onChange randomize + shareUrl={shortShareUrl(config, styles)} onToggleModal={_ => setShowModal(_ => false)} onExport={_ => exportImage()} /> diff --git a/worker/index.js b/worker/index.js new file mode 100644 index 0000000..b1d0aff --- /dev/null +++ b/worker/index.js @@ -0,0 +1,43 @@ +// Personas Worker: serves the static site plus a small API surface. +// +// Routes: +// GET /api/options — valid style names and color palettes (JSON, CORS *) +// GET / — short share link (base64url avatar code); serves the +// SPA shell, which decodes the code client-side +// everything else — static assets (with 404.html for misses) + +import config from "../src/data/config.json"; + +// Mirrors CODE_PATH in src/helpers/shareUrl.js. Real asset paths never +// match: they contain "." or "/" (e.g. /favicon.png, /fonts/...). +const CODE_PATH = /^\/[A-Za-z0-9_-]{8,64}$/; + +const CORS = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type", +}; + +export default { + async fetch(request, env) { + const url = new URL(request.url); + + if (request.method === "OPTIONS") { + return new Response(null, { headers: CORS }); + } + + if (url.pathname === "/api/options") { + return Response.json(config, { + headers: { ...CORS, "Cache-Control": "public, max-age=3600" }, + }); + } + + if (request.method === "GET" && CODE_PATH.test(url.pathname)) { + // Serve the app shell; the client decodes the code from the path. + const shell = new URL("/", url); + return env.ASSETS.fetch(new Request(shell, request)); + } + + return env.ASSETS.fetch(request); + }, +}; diff --git a/wrangler.jsonc b/wrangler.jsonc index b457d8a..ecf5938 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -1,6 +1,7 @@ { "$schema": "node_modules/wrangler/config-schema.json", "name": "personas", + "main": "worker/index.js", "compatibility_date": "2026-07-03", "routes": [ { @@ -10,6 +11,10 @@ ], "assets": { "directory": "./dist", - "not_found_handling": "404-page" + "binding": "ASSETS", + "not_found_handling": "404-page", + // Asset requests would otherwise be answered (and 404'd) before the + // worker runs, breaking short-code paths for browser navigations. + "run_worker_first": ["/*", "!/assets/*", "!/fonts/*", "!/images/*", "!/avatars/*"] } }