gemi 0.119.2 → 0.120.1
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/ai/index.js +2 -2
- package/dist/ai/index.js.map +1 -1
- package/dist/app/index.js +2 -2
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gemi.js +32 -5
- package/dist/bin/gemi.js.map +6 -5
- package/dist/bun/plugin.js +1 -1
- package/dist/bun/preload.js +1 -1
- package/dist/{chunk-x5m12vkw.js → chunk-0ejjgzwc.js} +2 -2
- package/dist/{chunk-x5m12vkw.js.map → chunk-0ejjgzwc.js.map} +1 -1
- package/dist/{chunk-7rffbkmg.js → chunk-0k02tza1.js} +1 -1
- package/dist/{chunk-14xk8kq0.js → chunk-0yj0s1pn.js} +2 -2
- package/dist/{chunk-14xk8kq0.js.map → chunk-0yj0s1pn.js.map} +1 -1
- package/dist/{chunk-6pqbsc5y.js → chunk-19dpzp4y.js} +3 -3
- package/dist/{chunk-6pqbsc5y.js.map → chunk-19dpzp4y.js.map} +1 -1
- package/dist/{chunk-3vt172y7.js → chunk-1wnnkde0.js} +3 -3
- package/dist/{chunk-3vt172y7.js.map → chunk-1wnnkde0.js.map} +1 -1
- package/dist/{chunk-ct1vwaw7.js → chunk-1xdrs2hx.js} +3 -3
- package/dist/{chunk-ct1vwaw7.js.map → chunk-1xdrs2hx.js.map} +1 -1
- package/dist/{chunk-79rtpahn.js → chunk-2c0s0561.js} +2 -2
- package/dist/{chunk-79rtpahn.js.map → chunk-2c0s0561.js.map} +1 -1
- package/dist/{chunk-nfq127pg.js → chunk-2n3pgfnb.js} +2 -2
- package/dist/{chunk-nfq127pg.js.map → chunk-2n3pgfnb.js.map} +1 -1
- package/dist/{chunk-s2h85rbf.js → chunk-32n8t8x6.js} +2 -2
- package/dist/{chunk-s2h85rbf.js.map → chunk-32n8t8x6.js.map} +1 -1
- package/dist/{chunk-6gfsjgra.js → chunk-3gsv1vv1.js} +2 -2
- package/dist/{chunk-6gfsjgra.js.map → chunk-3gsv1vv1.js.map} +1 -1
- package/dist/{chunk-862jeyz0.js → chunk-3wnghdsx.js} +2 -2
- package/dist/{chunk-862jeyz0.js.map → chunk-3wnghdsx.js.map} +1 -1
- package/dist/{chunk-yn4x9wxc.js → chunk-471htqmz.js} +2 -2
- package/dist/{chunk-yn4x9wxc.js.map → chunk-471htqmz.js.map} +1 -1
- package/dist/{chunk-w1zqg54r.js → chunk-48gmyaxc.js} +2 -2
- package/dist/{chunk-w1zqg54r.js.map → chunk-48gmyaxc.js.map} +1 -1
- package/dist/{chunk-299zx9dv.js → chunk-4acpw92g.js} +3 -3
- package/dist/{chunk-299zx9dv.js.map → chunk-4acpw92g.js.map} +1 -1
- package/dist/{chunk-9c5s06gc.js → chunk-4fx8p02c.js} +2 -2
- package/dist/{chunk-9c5s06gc.js.map → chunk-4fx8p02c.js.map} +1 -1
- package/dist/{chunk-xpz1bp50.js → chunk-51w5ktv2.js} +3 -3
- package/dist/{chunk-xpz1bp50.js.map → chunk-51w5ktv2.js.map} +1 -1
- package/dist/{chunk-9qkjkse0.js → chunk-5nj94s66.js} +4 -4
- package/dist/{chunk-9qkjkse0.js.map → chunk-5nj94s66.js.map} +1 -1
- package/dist/{chunk-j632p533.js → chunk-5tdxbwzg.js} +3 -3
- package/dist/{chunk-j632p533.js.map → chunk-5tdxbwzg.js.map} +1 -1
- package/dist/{chunk-zq1bhsdg.js → chunk-65beps2q.js} +3 -3
- package/dist/{chunk-zq1bhsdg.js.map → chunk-65beps2q.js.map} +1 -1
- package/dist/{chunk-xeh1mw1d.js → chunk-6yhpprzs.js} +3 -3
- package/dist/{chunk-xeh1mw1d.js.map → chunk-6yhpprzs.js.map} +1 -1
- package/dist/{chunk-620yeafr.js → chunk-7ftj43vp.js} +2 -2
- package/dist/{chunk-620yeafr.js.map → chunk-7ftj43vp.js.map} +1 -1
- package/dist/{chunk-4kj4e22e.js → chunk-7g649j8h.js} +2 -2
- package/dist/{chunk-4kj4e22e.js.map → chunk-7g649j8h.js.map} +1 -1
- package/dist/{chunk-675kzd7z.js → chunk-7mmw0jr2.js} +2 -2
- package/dist/{chunk-675kzd7z.js.map → chunk-7mmw0jr2.js.map} +1 -1
- package/dist/{chunk-k1ncgq7p.js → chunk-9d2d08qm.js} +2 -2
- package/dist/{chunk-k1ncgq7p.js.map → chunk-9d2d08qm.js.map} +1 -1
- package/dist/{chunk-wdg83tgd.js → chunk-9rr5h818.js} +3 -3
- package/dist/{chunk-wdg83tgd.js.map → chunk-9rr5h818.js.map} +1 -1
- package/dist/{chunk-30xxc6r7.js → chunk-9xyxbxgk.js} +2 -2
- package/dist/{chunk-30xxc6r7.js.map → chunk-9xyxbxgk.js.map} +1 -1
- package/dist/{chunk-khd9ft0s.js → chunk-ar4d3vmr.js} +3 -3
- package/dist/{chunk-khd9ft0s.js.map → chunk-ar4d3vmr.js.map} +1 -1
- package/dist/chunk-b5a5vvkk.js +57 -0
- package/dist/{chunk-bz5gda3b.js.map → chunk-b5a5vvkk.js.map} +7 -6
- package/dist/{chunk-6ggmk2eg.js → chunk-c0v61fp5.js} +2 -2
- package/dist/{chunk-6ggmk2eg.js.map → chunk-c0v61fp5.js.map} +1 -1
- package/dist/{chunk-bw2pfaz3.js → chunk-c7qs1xp3.js} +2 -2
- package/dist/{chunk-bw2pfaz3.js.map → chunk-c7qs1xp3.js.map} +1 -1
- package/dist/{chunk-2kegxt0s.js → chunk-cca0grq3.js} +2 -2
- package/dist/{chunk-2kegxt0s.js.map → chunk-cca0grq3.js.map} +1 -1
- package/dist/{chunk-b336h3hj.js → chunk-cskqet01.js} +2 -2
- package/dist/{chunk-b336h3hj.js.map → chunk-cskqet01.js.map} +1 -1
- package/dist/{chunk-pzk2a5sr.js → chunk-cvr5624r.js} +1 -1
- package/dist/chunk-cytq2msw.js +24 -0
- package/dist/{chunk-w8d37mcq.js.map → chunk-cytq2msw.js.map} +3 -3
- package/dist/{chunk-8507ez1g.js → chunk-d2c3947c.js} +2 -2
- package/dist/{chunk-8507ez1g.js.map → chunk-d2c3947c.js.map} +1 -1
- package/dist/{chunk-q0djcyj2.js → chunk-d5f1m3d2.js} +2 -2
- package/dist/{chunk-q0djcyj2.js.map → chunk-d5f1m3d2.js.map} +1 -1
- package/dist/{chunk-f9tfpn3w.js → chunk-dedqr5wb.js} +2 -2
- package/dist/{chunk-f9tfpn3w.js.map → chunk-dedqr5wb.js.map} +1 -1
- package/dist/{chunk-h02kyxgg.js → chunk-dhbgrv58.js} +1 -1
- package/dist/{chunk-d4dd7jde.js → chunk-dwedx1jb.js} +3 -3
- package/dist/{chunk-d4dd7jde.js.map → chunk-dwedx1jb.js.map} +1 -1
- package/dist/{chunk-5crtgt1y.js → chunk-ep0baa9g.js} +2 -2
- package/dist/{chunk-5crtgt1y.js.map → chunk-ep0baa9g.js.map} +1 -1
- package/dist/{chunk-kk77x2v4.js → chunk-er8acmch.js} +7 -7
- package/dist/{chunk-kk77x2v4.js.map → chunk-er8acmch.js.map} +3 -3
- package/dist/{chunk-thz75w6e.js → chunk-fcqx2t0p.js} +2 -2
- package/dist/{chunk-thz75w6e.js.map → chunk-fcqx2t0p.js.map} +1 -1
- package/dist/{chunk-1p87gdd2.js → chunk-fenc5tpv.js} +2 -2
- package/dist/{chunk-1p87gdd2.js.map → chunk-fenc5tpv.js.map} +1 -1
- package/dist/{chunk-fmea4sak.js → chunk-gc2dz11k.js} +2 -2
- package/dist/{chunk-fmea4sak.js.map → chunk-gc2dz11k.js.map} +1 -1
- package/dist/{chunk-qxxbp3nn.js → chunk-gemzbw7f.js} +2 -2
- package/dist/{chunk-qxxbp3nn.js.map → chunk-gemzbw7f.js.map} +1 -1
- package/dist/{chunk-qpy25jj9.js → chunk-gy81nd9a.js} +2 -2
- package/dist/{chunk-qpy25jj9.js.map → chunk-gy81nd9a.js.map} +1 -1
- package/dist/{chunk-c8vttyem.js → chunk-h43jp8ws.js} +2 -2
- package/dist/{chunk-c8vttyem.js.map → chunk-h43jp8ws.js.map} +1 -1
- package/dist/chunk-htgmy3x7.js +5 -0
- package/dist/{chunk-15v719sq.js.map → chunk-htgmy3x7.js.map} +1 -1
- package/dist/{chunk-xqd3zde5.js → chunk-jaa6xkeh.js} +2 -2
- package/dist/{chunk-xqd3zde5.js.map → chunk-jaa6xkeh.js.map} +1 -1
- package/dist/{chunk-2bja99cq.js → chunk-kk18xqgc.js} +2 -2
- package/dist/{chunk-2bja99cq.js.map → chunk-kk18xqgc.js.map} +1 -1
- package/dist/{chunk-mcjbck8e.js → chunk-krk7mcgm.js} +3 -3
- package/dist/{chunk-mcjbck8e.js.map → chunk-krk7mcgm.js.map} +1 -1
- package/dist/{chunk-hd5ztshp.js → chunk-krtybgz1.js} +2 -2
- package/dist/{chunk-hd5ztshp.js.map → chunk-krtybgz1.js.map} +1 -1
- package/dist/{chunk-fjhnn3de.js → chunk-m53fgf20.js} +3 -3
- package/dist/{chunk-fjhnn3de.js.map → chunk-m53fgf20.js.map} +1 -1
- package/dist/{chunk-4c1npv8k.js → chunk-m83zm86m.js} +2 -2
- package/dist/{chunk-4c1npv8k.js.map → chunk-m83zm86m.js.map} +1 -1
- package/dist/{chunk-q6a30w8w.js → chunk-meg8rtr6.js} +2 -2
- package/dist/{chunk-q6a30w8w.js.map → chunk-meg8rtr6.js.map} +1 -1
- package/dist/{chunk-vy0tnx2s.js → chunk-mr94nfp1.js} +3 -3
- package/dist/{chunk-vy0tnx2s.js.map → chunk-mr94nfp1.js.map} +1 -1
- package/dist/{chunk-zb8zzf5x.js → chunk-nz8z8jr1.js} +3 -3
- package/dist/{chunk-zb8zzf5x.js.map → chunk-nz8z8jr1.js.map} +1 -1
- package/dist/{chunk-d38x71xy.js → chunk-pemhmjzp.js} +3 -3
- package/dist/{chunk-d38x71xy.js.map → chunk-pemhmjzp.js.map} +1 -1
- package/dist/{chunk-d2v78b77.js → chunk-pn2x59ge.js} +3 -3
- package/dist/{chunk-d2v78b77.js.map → chunk-pn2x59ge.js.map} +1 -1
- package/dist/{chunk-qm6j85fq.js → chunk-qphjhpad.js} +2 -2
- package/dist/{chunk-qm6j85fq.js.map → chunk-qphjhpad.js.map} +1 -1
- package/dist/{chunk-p5xy9cn8.js → chunk-qsz9241c.js} +2 -2
- package/dist/{chunk-p5xy9cn8.js.map → chunk-qsz9241c.js.map} +1 -1
- package/dist/{chunk-d6nhcqvt.js → chunk-qy8c0gzr.js} +2 -2
- package/dist/{chunk-d6nhcqvt.js.map → chunk-qy8c0gzr.js.map} +1 -1
- package/dist/{chunk-7ns5506p.js → chunk-r01aqf0q.js} +2 -2
- package/dist/{chunk-7ns5506p.js.map → chunk-r01aqf0q.js.map} +1 -1
- package/dist/{chunk-0p6mdba6.js → chunk-rhvc1axc.js} +2 -2
- package/dist/{chunk-0p6mdba6.js.map → chunk-rhvc1axc.js.map} +1 -1
- package/dist/{chunk-pjz79c2c.js → chunk-s07v65x6.js} +3 -3
- package/dist/{chunk-pjz79c2c.js.map → chunk-s07v65x6.js.map} +1 -1
- package/dist/{chunk-q00f25na.js → chunk-s5k3yq6t.js} +2 -2
- package/dist/{chunk-q00f25na.js.map → chunk-s5k3yq6t.js.map} +1 -1
- package/dist/{chunk-ty8gxbgj.js → chunk-s6vvqsd0.js} +3 -3
- package/dist/{chunk-ty8gxbgj.js.map → chunk-s6vvqsd0.js.map} +3 -3
- package/dist/{chunk-2854taf5.js → chunk-sx340k85.js} +2 -2
- package/dist/{chunk-2854taf5.js.map → chunk-sx340k85.js.map} +1 -1
- package/dist/{chunk-j5q5ysng.js → chunk-tewhms9w.js} +2 -2
- package/dist/{chunk-j5q5ysng.js.map → chunk-tewhms9w.js.map} +1 -1
- package/dist/{chunk-7pxdvvrz.js → chunk-tk135gmj.js} +3 -3
- package/dist/{chunk-7pxdvvrz.js.map → chunk-tk135gmj.js.map} +1 -1
- package/dist/{chunk-yvd4pgd9.js → chunk-vx7hvyvq.js} +2 -2
- package/dist/{chunk-yvd4pgd9.js.map → chunk-vx7hvyvq.js.map} +1 -1
- package/dist/{chunk-xecnc8zv.js → chunk-wjkh2gem.js} +1 -1
- package/dist/{chunk-511zqetr.js → chunk-wqe47c0j.js} +2 -2
- package/dist/{chunk-511zqetr.js.map → chunk-wqe47c0j.js.map} +1 -1
- package/dist/{chunk-2y0r4b7g.js → chunk-y6wt5b6t.js} +1 -1
- package/dist/{chunk-kkx8a35r.js → chunk-yds7zwc3.js} +2 -2
- package/dist/{chunk-kkx8a35r.js.map → chunk-yds7zwc3.js.map} +1 -1
- package/dist/{chunk-w7am9q0q.js → chunk-zefs2b6h.js} +2 -2
- package/dist/{chunk-w7am9q0q.js.map → chunk-zefs2b6h.js.map} +1 -1
- package/dist/{chunk-de4t48j9.js → chunk-zg6hmc48.js} +1 -1
- package/dist/{chunk-svn6zvzd.js → chunk-zrcd9hxr.js} +2 -2
- package/dist/{chunk-svn6zvzd.js.map → chunk-zrcd9hxr.js.map} +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +26 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/staticNavigation.d.ts +26 -0
- package/dist/client/staticNavigation.d.ts.map +1 -0
- package/dist/config/index.js +1 -1
- package/dist/console/run.js +2 -2
- package/dist/console/run.js.map +1 -1
- package/dist/container/index.js +2 -2
- package/dist/container/index.js.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/email/index.js +2 -2
- package/dist/email/index.js.map +1 -1
- package/dist/facades/index.js +2 -2
- package/dist/facades/index.js.map +1 -1
- package/dist/foundation/index.js +2 -2
- package/dist/foundation/index.js.map +1 -1
- package/dist/http/ViewRouter.d.ts +36 -2
- package/dist/http/ViewRouter.d.ts.map +1 -1
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +2 -2
- package/dist/http/index.js.map +1 -1
- package/dist/i18n/dictionaryRuntime.js +2 -2
- package/dist/i18n/dictionaryRuntime.js.map +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +2 -2
- package/dist/internal/islandRuntime.d.ts +16 -0
- package/dist/internal/islandRuntime.d.ts.map +1 -1
- package/dist/internal/staticNavigationRuntime.d.ts +8 -0
- package/dist/internal/staticNavigationRuntime.d.ts.map +1 -0
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +2 -2
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +1 -1
- package/dist/server/devFetch.d.ts.map +1 -1
- package/dist/server/httpProd.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -3
- package/dist/services/index.js.map +2 -2
- package/dist/services/queue/work.js +2 -2
- package/dist/services/queue/work.js.map +1 -1
- package/dist/services/router/ViewRouteDispatcher.d.ts +5 -0
- package/dist/services/router/ViewRouteDispatcher.d.ts.map +1 -1
- package/dist/services/router/staticDocument.d.ts +30 -21
- package/dist/services/router/staticDocument.d.ts.map +1 -1
- package/dist/stats/bundleStats.d.ts +6 -2
- package/dist/stats/bundleStats.d.ts.map +1 -1
- package/dist/stats/route-table.js +2 -2
- package/dist/stats/route-table.js.map +3 -3
- package/dist/stats/routeTable.d.ts +5 -1
- package/dist/stats/routeTable.d.ts.map +1 -1
- package/dist/support/index.js +2 -2
- package/dist/support/index.js.map +1 -1
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +185 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/staticDocument.d.ts +80 -0
- package/dist/testing/staticDocument.d.ts.map +1 -0
- package/dist/vitest/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-15v719sq.js +0 -5
- package/dist/chunk-bz5gda3b.js +0 -57
- package/dist/chunk-w8d37mcq.js +0 -24
- /package/dist/{chunk-7rffbkmg.js.map → chunk-0k02tza1.js.map} +0 -0
- /package/dist/{chunk-pzk2a5sr.js.map → chunk-cvr5624r.js.map} +0 -0
- /package/dist/{chunk-h02kyxgg.js.map → chunk-dhbgrv58.js.map} +0 -0
- /package/dist/{chunk-xecnc8zv.js.map → chunk-wjkh2gem.js.map} +0 -0
- /package/dist/{chunk-2y0r4b7g.js.map → chunk-y6wt5b6t.js.map} +0 -0
- /package/dist/{chunk-de4t48j9.js.map → chunk-zg6hmc48.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{Mc as E,Pc as T}from"../../chunk-dwedx1jb.js";import"../../chunk-meg8rtr6.js";import"../../chunk-h43jp8ws.js";import"../../chunk-s07v65x6.js";import"../../chunk-gc2dz11k.js";import"../../chunk-nz8z8jr1.js";import"../../chunk-4fx8p02c.js";import{Zi as I,_i as J,bj as O}from"../../chunk-2n3pgfnb.js";import{fj as N}from"../../chunk-d5f1m3d2.js";import"../../chunk-tewhms9w.js";import L from"path";class F extends Error{name="QueueWorkerRefused"}class H{kernel;stopping;keepAlive;settings;constructor(y,z={}){this.kernel=y;this.settings={...J(),...z}}async start(){if(await this.kernel.waitForBoot(),this.stopping)return;let y=this.kernel.app;if(!y.bound(E))throw new F("[gemi] `gemi queue:work` has no queue to claim from: this application does not register QueueServiceProvider.");let z=y.make(E);if(!z.durable)throw new F('[gemi] `gemi queue:work` refuses to start: the queue uses the memory driver, which keeps each job in the process that dispatched it, so a worker never sees one. Set `driver: "database"` (or another driver every process can reach) in app/config/queue.ts, or run jobs in the server and drop the worker.');z.start(),this.keepAlive=setInterval(()=>{},1073741824),console.log(`[gemi] Queue worker started: claiming up to ${z.config.concurrency} job(s) at a time.`)}stop(y={}){return this.stopping??=this.drain({...this.settings,...y}),this.stopping}async drain(y){I();let z=this.kernel.app,A=z.resolved(E)?z.make(E):void 0;if(A)console.log(`[gemi] Shutting down: waiting for ${A.running} running job(s) (up to ${y.timeoutMs/1000}s).`),await A.drain(y.timeoutMs);let B=await this.kernel.shutdown({timeoutMs:y.providerTimeoutMs});clearInterval(this.keepAlive);let C=(A?.running??0)===0&&B.failed.length===0&&B.timedOut.length===0;return console.log(`[gemi] Shutdown ${C?"complete":"finished with errors"}.`),C?0:1}}async function U(){let y=N();process.env.ROOT_DIR=y,process.env.APP_DIR=L.join(y,"app"),T();let z=L.join(y,"app/kernel/Kernel.ts"),{default:A}=await import(z);if(typeof A!=="function")return console.error(`[gemi] ${z} has no default export to boot the worker from.`),1;let B=new A;B.boot();let C=new H(B);O(()=>C.stop());try{await C.start()}catch(G){if(!(G instanceof F))throw G;return console.error(G.message),1}return}U().then((y)=>{if(y!==void 0)process.exit(y)},(y)=>{console.error("[gemi] The queue worker failed to start:",y),process.exit(1)});
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=6BB0BA54803EFE8864756E2164756E21
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
"import type { Application, ShutdownReport } from \"../../foundation/Application\";\nimport { markShuttingDown, shutdownSettings, type ShutdownSettings } from \"../../server/shutdown\";\nimport { QueueManager } from \"./QueueManager\";\n\n/** The part of a `Kernel` a worker drives. */\nexport type WorkerKernel = {\n readonly app: Application;\n waitForBoot(): Promise<void>;\n shutdown(options?: { timeoutMs?: number }): Promise<ShutdownReport>;\n};\n\n/**\n * A worker that was told to start in an application it cannot claim for. The\n * message is written for the operator reading the deploy's logs.\n */\nexport class QueueWorkerRefused extends Error {\n name = \"QueueWorkerRefused\";\n}\n\n/**\n * The process `gemi queue:work` runs: the application booted as a server boots\n * it, claiming from the queue, and no `Bun.serve`. It exists so job capacity\n * can be scaled apart from request traffic, which needs a driver both kinds of\n * process can reach; see `start` for why the memory driver is refused.\n *\n * The caller marks the process as a worker (`markQueueWorker`) before the\n * kernel registers, so every claim rule that asks `claimsInThisProcess` sees a\n * process that claims, whatever `GEMI_QUEUE_CLAIM` says.\n */\nexport class QueueWorker {\n private stopping: Promise<number> | undefined;\n private keepAlive: ReturnType<typeof setInterval> | undefined;\n private readonly settings: ShutdownSettings;\n\n /**\n * `settings` default to the `GEMI_SHUTDOWN_*` variables, read here rather\n * than at the signal so a bad value is warned about while the deploy is\n * being watched, as `Server.start` does.\n */\n constructor(\n private readonly kernel: WorkerKernel,\n settings: Partial<ShutdownSettings> = {},\n ) {\n this.settings = { ...shutdownSettings(), ...settings };\n }\n\n /**\n * Boots the application and starts claiming. Rejects with\n * `QueueWorkerRefused` when the application has no queue, or its queue uses\n * the memory driver.\n *\n * Refused rather than warned about, because a memory worker can never do\n * anything: its jobs live in a `Map` in the process that dispatched them,\n * so a worker's is always empty. Left running, it looks like a healthy\n * deploy — a process up, no errors — that runs nothing, and scaling it out\n * adds no capacity. An exit the platform reports as a crash loop is a form\n * of the mistake someone will see.\n */\n async start(): Promise<void> {\n await this.kernel.waitForBoot();\n // A signal during the boot has already drained and cleared the handle\n // below. Going on would start the loop again and arm a handle nothing\n // clears, holding open a worker that has finished shutting down.\n if (this.stopping) return;\n\n const application = this.kernel.app;\n // `bound`, not `make` in a try: an application built without the queue\n // provider is a configuration to name, not an unbound-token stack trace.\n if (!application.bound(QueueManager)) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` has no queue to claim from: this application \" +\n \"does not register QueueServiceProvider.\",\n );\n }\n const queue = application.make(QueueManager);\n if (!queue.durable) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` refuses to start: the queue uses the memory \" +\n \"driver, which keeps each job in the process that dispatched it, so \" +\n 'a worker never sees one. Set `driver: \"database\"` (or another driver ' +\n \"every process can reach) in app/config/queue.ts, or run jobs in the \" +\n \"server and drop the worker.\",\n );\n }\n\n // Idempotent: a production boot with a durable driver has already started\n // it (`startClaimingIfServing`). Development has not, and a worker claims\n // in either.\n queue.start();\n // The queue's poll timer is unref'd, so that a script's queue does not\n // hold it open; here the queue is the process, and without a handle of its\n // own an idle worker would exit 0 as soon as it booted.\n this.keepAlive = setInterval(() => {}, 1 << 30);\n console.log(\n `[gemi] Queue worker started: claiming up to ${queue.config.concurrency} job(s) at a time.`,\n );\n }\n\n /**\n * Stops claiming, waits for the running jobs, runs every provider's\n * `shutdown()`, and resolves with the exit code: 0 when no job was left\n * running and every provider finished in time, 1 otherwise. Idempotent.\n *\n * `gemi start`'s drain, with the jobs where the requests were:\n * `isShuttingDown()` turns true, which stops a durable queue claiming;\n * running jobs get `timeoutMs` (`GEMI_SHUTDOWN_TIMEOUT`), which a server\n * spends on requests; then `Application.shutdown` gets `providerTimeoutMs`,\n * and in it the queue provider waits for whatever is still running and\n * names it. The two budgets add up as they do for a server, so a worker\n * fits the same grace period. `delayMs` is not waited: it is for a load\n * balancer, and nothing routes to a worker.\n */\n stop(settings: Partial<ShutdownSettings> = {}): Promise<number> {\n this.stopping ??= this.drain({ ...this.settings, ...settings });\n return this.stopping;\n }\n\n private async drain(settings: ShutdownSettings): Promise<number> {\n markShuttingDown();\n const application = this.kernel.app;\n // Resolving the manager now would build a driver only to stop it, which\n // is what a signal during the boot, before the provider resolved it, finds.\n const queue = application.resolved(QueueManager) ? application.make(QueueManager) : undefined;\n if (queue) {\n console.log(\n `[gemi] Shutting down: waiting for ${queue.running} running job(s) ` +\n `(up to ${settings.timeoutMs / 1000}s).`,\n );\n await queue.drain(settings.timeoutMs);\n }\n\n const report = await this.kernel.shutdown({ timeoutMs: settings.providerTimeoutMs });\n clearInterval(this.keepAlive);\n const clean =\n (queue?.running ?? 0) === 0 && report.failed.length === 0 && report.timedOut.length === 0;\n console.log(`[gemi] Shutdown ${clean ? \"complete\" : \"finished with errors\"}.`);\n return clean ? 0 : 1;\n }\n}\n"
|
|
7
7
|
],
|
|
8
8
|
"mappings": ";iZAYA,kBCGO,IAAM,QAA2B,GAAM,DAC5C,GAAO,kBACT,DAYO,IAAM,CAAY,CAWJ,OAVX,SACA,UACS,SAOjB,WAAW,CACQ,EACjB,EAAsC,CAAC,EACvC,CAFiB,cAGjB,KAAK,SAAW,IAAK,EAAiB,KAAM,CAAS,OAejD,MAAK,EAAkB,CAK3B,GAJA,MAAM,KAAK,OAAO,YAAY,EAI1B,KAAK,SAAU,OAEnB,IAAM,EAAc,KAAK,OAAO,IAGhC,GAAI,CAAC,EAAY,MAAM,CAAY,EACjC,MAAM,IAAI,EACR,+GAEF,EAEF,IAAM,EAAQ,EAAY,KAAK,CAAY,EAC3C,GAAI,CAAC,EAAM,QACT,MAAM,IAAI,EACR,8SAKF,EAMF,EAAM,MAAM,EAIZ,KAAK,UAAY,YAAY,IAAM,GAAI,UAAO,EAC9C,QAAQ,IACN,+CAA+C,EAAM,OAAO,+BAC9D,EAiBF,IAAI,CAAC,EAAsC,CAAC,EAAoB,CAE9D,OADA,KAAK,WAAa,KAAK,MAAM,IAAK,KAAK,YAAa,CAAS,CAAC,EACvD,KAAK,cAGA,MAAK,CAAC,EAA6C,CAC/D,EAAiB,EACjB,IAAM,EAAc,KAAK,OAAO,IAG1B,EAAQ,EAAY,SAAS,CAAY,EAAI,EAAY,KAAK,CAAY,EAAI,OACpF,GAAI,EACF,QAAQ,IACN,qCAAqC,EAAM,iCAC/B,EAAS,UAAY,SACnC,EACA,MAAM,EAAM,MAAM,EAAS,SAAS,EAGtC,IAAM,EAAS,MAAM,KAAK,OAAO,SAAS,CAAE,UAAW,EAAS,iBAAkB,CAAC,EACnF,cAAc,KAAK,SAAS,EAC5B,IAAM,GACH,GAAO,SAAW,KAAO,GAAK,EAAO,OAAO,SAAW,GAAK,EAAO,SAAS,SAAW,EAE1F,OADA,QAAQ,IAAI,mBAAmB,EAAQ,WAAa,yBAAyB,EACtE,EAAQ,EAAI,EAEvB,CDvHA,eAAe,CAAI,EAAgC,CACjD,IAAM,EAAU,EAAY,EAI5B,QAAQ,IAAI,SAAW,EACvB,QAAQ,IAAI,QAAU,EAAK,KAAK,EAAS,KAAK,EAE9C,EAAgB,EAEhB,IAAM,EAAa,EAAK,KAAK,EAAS,sBAAsB,GACpD,QAAS,GAAY,MAAa,UAG1C,GAAI,OAAO,IAAW,WAEpB,OADA,QAAQ,MAAM,UAAU,kDAA2D,EAC5E,EAET,IAAM,EAAS,IAAI,EACnB,EAAO,KAAK,EAEZ,IAAM,EAAS,IAAI,EAAY,CAAM,EAKrC,EAAuB,IAAM,EAAO,KAAK,CAAC,EAE1C,GAAI,CACF,MAAM,EAAO,MAAM,EACnB,MAAO,EAAO,CACd,GAAI,EAAE,aAAiB,GAAqB,MAAM,EAElD,OADA,QAAQ,MAAM,EAAM,OAAO,EACpB,EAGT,OAGF,EAAK,EAAE,KACL,CAAC,IAAS,CACR,GAAI,IAAS,OAAW,QAAQ,KAAK,CAAI,GAE3C,CAAC,IAAU,CACT,QAAQ,MAAM,2CAA4C,CAAK,EAC/D,QAAQ,KAAK,CAAC,EAElB",
|
|
9
|
-
"debugId": "
|
|
9
|
+
"debugId": "6BB0BA54803EFE8864756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
|
@@ -165,6 +165,11 @@ export declare class ViewRouteDispatcher {
|
|
|
165
165
|
assetBase?: string;
|
|
166
166
|
/** Where island client modules are served from; see `injectIslands`. */
|
|
167
167
|
resolveIsland?: IslandResolver;
|
|
168
|
+
/**
|
|
169
|
+
* Identifies the client build, so a static page with `navigation` loads
|
|
170
|
+
* a page of another deploy in full rather than swapping it in.
|
|
171
|
+
*/
|
|
172
|
+
buildId?: string;
|
|
168
173
|
}) => Promise<Response>)>;
|
|
169
174
|
}
|
|
170
175
|
//# sourceMappingURL=ViewRouteDispatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewRouteDispatcher.d.ts","sourceRoot":"","sources":["../../../services/router/ViewRouteDispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,cAAc,EAAmC,MAAM,2BAA2B,CAAC;AAEjG,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAU7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAyBxD,OAAO,
|
|
1
|
+
{"version":3,"file":"ViewRouteDispatcher.d.ts","sourceRoot":"","sources":["../../../services/router/ViewRouteDispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,cAAc,EAAmC,MAAM,2BAA2B,CAAC;AAEjG,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAU7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAyBxD,OAAO,EAGL,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAC;AAiH1B;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,YAAY,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,QAY9D;AAaD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAQ1D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAM7D;AAED,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,KAAK,SAAiB;IAE7B,cAAc,EAAE,cAAc,CAAM;IACpC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAM;IAC7C,0FAA0F;IAC1F,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAM;IACnD,aAAa,EAAE,aAAa,CAAM;IAClC,iBAAiB,EAAE,MAAM,EAAE,CAAM;IACjC;;;;OAIG;IACH,YAAY,EAAE,MAAM,EAAE,CAAM;IAC5B,IAAI,EAAE,GAAG,CAAQ;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa,CAAgC;IAErD;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY,CAGhB;IAEJ,OAAO,CAAC,QAAQ,CAAC,KAAK,CAKpB;IAEF,8CAA8C;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IAEnC,2CAA2C;IAC3C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAE1B,MAAM,EAAE,eAAe;IAwCnC;;;;;;OAMG;YACW,kBAAkB;IAQ1B,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAO;IAY5E;;;;;;;;;;OAUG;IACH,OAAO,CAAC,cAAc;IAatB,0BAA0B;IAC1B,OAAO,CAAC,kBAAkB;IA0C1B;;;;;;OAMG;YACW,YAAY;YAmHZ,MAAM;IA4cpB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IAyBnB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,gCA7Y7C;QACpB;;;;;WAKG;QACH,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5F,aAAa,EAAE,GAAG,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3B;;;;WAIG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAClC;;;;;;;;;;;WAWG;QACH,WAAW,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;QACpD;;;WAGG;QACH,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD;;;;WAIG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,wEAAwE;QACxE,aAAa,CAAC,EAAE,cAAc,CAAC;QAC/B;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAs7BJ"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { type StaticRenderCollector } from "../../client/islands";
|
|
2
|
+
import { ISLAND_LOADER_SOURCE } from "../../internal/islandRuntime";
|
|
3
|
+
import { STATIC_NAVIGATION_SOURCE } from "../../internal/staticNavigationRuntime";
|
|
4
|
+
export { ISLAND_LOADER_SOURCE, STATIC_NAVIGATION_SOURCE };
|
|
2
5
|
/**
|
|
3
6
|
* Where an island's entry is served from: `src` is imported by the loader,
|
|
4
7
|
* `preload` is every chunk that import pulls in (itself first), React
|
|
@@ -12,22 +15,6 @@ export type IslandAsset = {
|
|
|
12
15
|
export type IslandResolver = (moduleKey: string) => IslandAsset | undefined;
|
|
13
16
|
/** The id of the JSON block the loader reads its island table from. */
|
|
14
17
|
export declare const ISLAND_DATA_ID = "gemi-islands";
|
|
15
|
-
/**
|
|
16
|
-
* The island loader, inlined into a static document that uses islands.
|
|
17
|
-
*
|
|
18
|
-
* Kept byte-for-byte constant (the per-page island table travels in a
|
|
19
|
-
* separate `<script type="application/json">`, which a Content Security Policy
|
|
20
|
-
* does not treat as script), so a strict policy can allow it by hash:
|
|
21
|
-
* `script-src 'sha256-…'` with `ISLAND_LOADER_CSP_HASH`. Everything it loads
|
|
22
|
-
* is a plain `import()` of a same-origin (or asset-base) file.
|
|
23
|
-
*
|
|
24
|
-
* The table is `{ i: [{ s: entry URL, e: export, l: load }] }` and each
|
|
25
|
-
* marker's `data-island` indexes `i`. Per marker, on its schedule: import the
|
|
26
|
-
* island's entry (the module as `m`, the runtime's `h`), then
|
|
27
|
-
* `h(marker, m[export])`, which calls `hydrateRoot`. A failure is logged and
|
|
28
|
-
* leaves the server-rendered markup in place.
|
|
29
|
-
*/
|
|
30
|
-
export declare const ISLAND_LOADER_SOURCE: string;
|
|
31
18
|
/**
|
|
32
19
|
* `'sha256-…'` for the production island loader, ready to put in a
|
|
33
20
|
* `script-src` directive. The dev loader also installs the React Refresh
|
|
@@ -36,17 +23,39 @@ export declare const ISLAND_LOADER_SOURCE: string;
|
|
|
36
23
|
*/
|
|
37
24
|
export declare const ISLAND_LOADER_CSP_HASH: string;
|
|
38
25
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
26
|
+
* `'sha256-…'` for the production navigation runtime (`.static({ navigation })`),
|
|
27
|
+
* for a `script-src` directive. It replaces the island loader on those pages
|
|
28
|
+
* (it carries its own), so a policy for them needs this hash instead of (or
|
|
29
|
+
* besides) `ISLAND_LOADER_CSP_HASH`. Like the loader's, the dev script differs.
|
|
30
|
+
*/
|
|
31
|
+
export declare const STATIC_NAVIGATION_CSP_HASH: string;
|
|
32
|
+
/** The name of the `<meta>` that identifies a navigable static document. */
|
|
33
|
+
export declare const STATIC_IDENTITY_META = "gemi-static";
|
|
34
|
+
/**
|
|
35
|
+
* A static document's navigation settings, from `.static({ navigation })`:
|
|
36
|
+
* `identity` is the `<meta name="gemi-static">` content (`layout|build|version`)
|
|
37
|
+
* the runtime compares before it swaps a fetched page in.
|
|
38
|
+
*/
|
|
39
|
+
export interface StaticNavigationMarker {
|
|
40
|
+
identity: string;
|
|
41
|
+
prefetch: "intent" | "none";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Adds the client runtime to a settled static document.
|
|
45
|
+
*
|
|
46
|
+
* Without `navigation`, that is the island loader, and only when the render
|
|
47
|
+
* recorded an island, so a page without one keeps no script at all. With it,
|
|
48
|
+
* the page always gets the navigation runtime (which carries the loader) and
|
|
49
|
+
* the `<meta name="gemi-static">` that identifies it.
|
|
41
50
|
*
|
|
42
51
|
* Eager islands get `modulepreload`s in the head for their entry's whole
|
|
43
52
|
* static import closure (React included); lazy ones are fetched when their
|
|
44
53
|
* schedule fires, so nothing about them is announced up front.
|
|
45
54
|
*
|
|
46
|
-
* Without a resolver (a test rendering through `app.fetch`),
|
|
47
|
-
*
|
|
55
|
+
* Without a resolver (a test rendering through `app.fetch`), no island table
|
|
56
|
+
* is injected and nothing is logged.
|
|
48
57
|
*/
|
|
49
|
-
export declare function injectIslands(html: string, collector: StaticRenderCollector, resolveIsland: IslandResolver | undefined, dev: boolean): string;
|
|
58
|
+
export declare function injectIslands(html: string, collector: StaticRenderCollector, resolveIsland: IslandResolver | undefined, dev: boolean, navigation?: StaticNavigationMarker): string;
|
|
50
59
|
/**
|
|
51
60
|
* Moves each island's children into its slot.
|
|
52
61
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staticDocument.d.ts","sourceRoot":"","sources":["../../../services/router/staticDocument.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"staticDocument.d.ts","sourceRoot":"","sources":["../../../services/router/staticDocument.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAElF,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,CAAC;AAE1D;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE7D,qFAAqF;AACrF,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;AAE5E,uEAAuE;AACvE,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAEb,CAAC;AAgBvB;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAEjB,CAAC;AAWvB,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,aAAa,EAAE,cAAc,GAAG,SAAS,EACzC,GAAG,EAAE,OAAO,EACZ,UAAU,CAAC,EAAE,sBAAsB,GAClC,MAAM,CA0CR;AAcD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtD"}
|
|
@@ -17,8 +17,10 @@ import type { RouteTableEntry } from "./routeTable";
|
|
|
17
17
|
* from the route's views (and the document layout) through static or lazy
|
|
18
18
|
* imports; the route then counts that island entry with its static imports. A
|
|
19
19
|
* page loads only the islands it shows, so this is its most. Chunks the islands
|
|
20
|
-
* share (the runtime, React) count once per route. The
|
|
21
|
-
*
|
|
20
|
+
* share (the runtime, React) count once per route. The script inlined into the
|
|
21
|
+
* HTML counts too: the island loader when the route can render an island, or
|
|
22
|
+
* the navigation runtime (which carries the loader) for `.static({ navigation })`,
|
|
23
|
+
* which every such page gets.
|
|
22
24
|
*
|
|
23
25
|
* Sizes are raw, gzip -9 and brotli q11, the encodings `gemi build` writes
|
|
24
26
|
* next to each asset; those files are read when present.
|
|
@@ -87,6 +89,8 @@ export interface BundleStatsOptions {
|
|
|
87
89
|
manifest?: ViteManifest;
|
|
88
90
|
}
|
|
89
91
|
export declare function bundleStats(options: BundleStatsOptions): BuildStats;
|
|
92
|
+
/** Raw, gzip -9 and brotli q11 bytes of a string. */
|
|
93
|
+
export declare function measureSource(source: string): Size;
|
|
90
94
|
/** The budget that applies to a route: its own, its page view's, or the default. */
|
|
91
95
|
export declare function budgetFor(key: string, route: Pick<RouteStats, "views">, budgets: StatsBudgets | undefined): number | undefined;
|
|
92
96
|
/** The routes over their budget, as messages. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundleStats.d.ts","sourceRoot":"","sources":["../../stats/bundleStats.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bundleStats.d.ts","sourceRoot":"","sources":["../../stats/bundleStats.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"../chunk-
|
|
2
|
+
import"../chunk-tewhms9w.js";import M from"path";import{writeFileSync as Q}from"fs";var L=new Set(["FILE","REDIRECT"]);function H(j){return j.run(()=>{let x=[];for(let{group:z,view:D}of j.domains().viewGroups())for(let[G,B]of Object.entries(D.flatViewRoutes)){let C=D.routeManifest[G]??B.segments.map((K)=>K.viewPath);if(C.length===0||L.has(C.at(-1)))continue;x.push({path:G,group:z,views:C,...B.static?{static:{...B.static.layout?{layout:B.static.layout}:{},...B.static.navigation?{navigation:!0}:{}}}:{}})}return x})}var J=process.argv[2];async function U(){if(!J)throw Error("usage: route-table <out.json>");let j=M.resolve(process.cwd(),"app/kernel/Kernel.ts"),x=await import(j);if(typeof x.default!=="function")throw Error(`${j} has no default export (the Kernel subclass).`);let z=new x.default;z.boot();try{Q(J,JSON.stringify(H(z)))}finally{z.destroy()}}U().then(()=>process.exit(0),(j)=>{console.error(j?.stack??String(j)),process.exit(1)});
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=05EB0087C5A2060D64756E2164756E21
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"sources": ["../stats/route-table.ts", "../stats/routeTable.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * The entry `gemi stats` (and `gemi build --stats`) spawns to read the app's\n * route table: `bun --preload gemi/bun/preload stats/route-table.ts <out>`.\n *\n * `gemi build` deliberately never boots the app (see `bin/createRollupInput`).\n * This doesn't either, in the sense that matters: it imports the Kernel and\n * runs only its synchronous `boot()`, which registers providers and constructs\n * nothing that does I/O. No provider `boot()`, no service, no database, no\n * queue claiming and no scheduler. Importing the app's route files is the one\n * side effect, the same one `gemi app:route-manifest` has.\n *\n * Exposed as `gemi/stats/route-table` and resolved from the application's\n * `node_modules`, like `gemi/console/run`: the routers the app's files extend\n * are the app's copy of gemi, so the code reading them has to be as well.\n *\n * The table is written to the file named by the first argument rather than to\n * stdout, which app code is free to log to while it is imported.\n */\nimport path from \"node:path\";\nimport { writeFileSync } from \"node:fs\";\nimport type { Kernel } from \"../kernel/Kernel\";\nimport { collectRouteTable } from \"./routeTable\";\n\nconst out = process.argv[2];\n\nasync function main() {\n if (!out) throw new Error(\"usage: route-table <out.json>\");\n const kernelPath = path.resolve(process.cwd(), \"app/kernel/Kernel.ts\");\n const module: { default?: new () => Kernel } = await import(kernelPath);\n if (typeof module.default !== \"function\") {\n throw new Error(`${kernelPath} has no default export (the Kernel subclass).`);\n }\n const kernel = new module.default();\n kernel.boot();\n try {\n writeFileSync(out, JSON.stringify(collectRouteTable(kernel)));\n } finally {\n kernel.destroy();\n }\n}\n\n// `.then` rather than a top-level `await`; see `console/run.ts`.\nmain().then(\n () => process.exit(0),\n (error) => {\n console.error((error as Error)?.stack ?? String(error));\n process.exit(1);\n },\n);\n",
|
|
6
|
-
"import type { Kernel } from \"../kernel/Kernel\";\n\n/**\n * One document route, as `gemi stats` needs it: which views render it (layouts\n * first, the page last) and whether it is a `.static()` view.\n */\nexport interface RouteTableEntry {\n /** The route pattern, e.g. `/p/:slug`. */\n path: string;\n /** The host group: `\"\"` for the root, a subdomain, `\"*\"` for the custom fallback. */\n group: string;\n /** View paths (`app/views/<path>.tsx`), outermost layout first. */\n views: string[];\n
|
|
6
|
+
"import type { Kernel } from \"../kernel/Kernel\";\n\n/**\n * One document route, as `gemi stats` needs it: which views render it (layouts\n * first, the page last) and whether it is a `.static()` view.\n */\nexport interface RouteTableEntry {\n /** The route pattern, e.g. `/p/:slug`. */\n path: string;\n /** The host group: `\"\"` for the root, a subdomain, `\"*\"` for the custom fallback. */\n group: string;\n /** View paths (`app/views/<path>.tsx`), outermost layout first. */\n views: string[];\n /**\n * Set for a `.static()` route; `layout` is its document layout, if any, and\n * `navigation` is set when it ships the navigation runtime.\n */\n static?: { layout?: string; navigation?: true };\n}\n\n/** View paths that name no component: file and redirect routes. */\nconst NOT_A_VIEW = new Set([\"FILE\", \"REDIRECT\"]);\n\n/**\n * Every document route the app declares, from a kernel that has only run its\n * synchronous `boot()`: providers have registered, nothing has booted, so no\n * database, queue, scheduler or listener is touched. Reading the routers only\n * constructs them, which is what `app:route-manifest` has always done.\n */\nexport function collectRouteTable(kernel: Kernel): RouteTableEntry[] {\n return kernel.run(() => {\n const entries: RouteTableEntry[] = [];\n for (const { group, view } of kernel.domains().viewGroups()) {\n for (const [path, route] of Object.entries(view.flatViewRoutes)) {\n const views = view.routeManifest[path] ?? route.segments.map((s) => s.viewPath);\n if (views.length === 0 || NOT_A_VIEW.has(views.at(-1)!)) continue;\n entries.push({\n path,\n group,\n views,\n ...(route.static\n ? {\n static: {\n ...(route.static.layout ? { layout: route.static.layout } : {}),\n ...(route.static.navigation ? { navigation: true as const } : {}),\n },\n }\n : {}),\n });\n }\n }\n return entries;\n });\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";6BAkBA,oBACA,wBAAS,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": ";6BAkBA,oBACA,wBAAS,WCET,IAAM,EAAa,IAAI,IAAI,CAAC,OAAQ,UAAU,CAAC,EAQxC,SAAS,CAAiB,CAAC,EAAmC,CACnE,OAAO,EAAO,IAAI,IAAM,CACtB,IAAM,EAA6B,CAAC,EACpC,QAAa,QAAO,UAAU,EAAO,QAAQ,EAAE,WAAW,EACxD,QAAY,EAAM,KAAU,OAAO,QAAQ,EAAK,cAAc,EAAG,CAC/D,IAAM,EAAQ,EAAK,cAAc,IAAS,EAAM,SAAS,IAAI,CAAC,IAAM,EAAE,QAAQ,EAC9E,GAAI,EAAM,SAAW,GAAK,EAAW,IAAI,EAAM,GAAG,EAAE,CAAE,EAAG,SACzD,EAAQ,KAAK,CACX,OACA,QACA,WACI,EAAM,OACN,CACE,OAAQ,IACF,EAAM,OAAO,OAAS,CAAE,OAAQ,EAAM,OAAO,MAAO,EAAI,CAAC,KACzD,EAAM,OAAO,WAAa,CAAE,WAAY,EAAc,EAAI,CAAC,CACjE,CACF,EACA,CAAC,CACP,CAAC,EAGL,OAAO,EACR,ED7BH,IAAM,EAAM,QAAQ,KAAK,GAEzB,eAAe,CAAI,EAAG,CACpB,GAAI,CAAC,EAAK,MAAU,MAAM,+BAA+B,EACzD,IAAM,EAAa,EAAK,QAAQ,QAAQ,IAAI,EAAG,sBAAsB,EAC/D,EAAyC,MAAa,UAC5D,GAAI,OAAO,EAAO,UAAY,WAC5B,MAAU,MAAM,GAAG,gDAAyD,EAE9E,IAAM,EAAS,IAAI,EAAO,QAC1B,EAAO,KAAK,EACZ,GAAI,CACF,EAAc,EAAK,KAAK,UAAU,EAAkB,CAAM,CAAC,CAAC,SAC5D,CACA,EAAO,QAAQ,GAKnB,EAAK,EAAE,KACL,IAAM,QAAQ,KAAK,CAAC,EACpB,CAAC,IAAU,CACT,QAAQ,MAAO,GAAiB,OAAS,OAAO,CAAK,CAAC,EACtD,QAAQ,KAAK,CAAC,EAElB",
|
|
9
|
+
"debugId": "05EB0087C5A2060D64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
|
@@ -10,9 +10,13 @@ export interface RouteTableEntry {
|
|
|
10
10
|
group: string;
|
|
11
11
|
/** View paths (`app/views/<path>.tsx`), outermost layout first. */
|
|
12
12
|
views: string[];
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Set for a `.static()` route; `layout` is its document layout, if any, and
|
|
15
|
+
* `navigation` is set when it ships the navigation runtime.
|
|
16
|
+
*/
|
|
14
17
|
static?: {
|
|
15
18
|
layout?: string;
|
|
19
|
+
navigation?: true;
|
|
16
20
|
};
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeTable.d.ts","sourceRoot":"","sources":["../../stats/routeTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB
|
|
1
|
+
{"version":3,"file":"routeTable.d.ts","sourceRoot":"","sources":["../../stats/routeTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC;CACjD;AAKD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAwBnE"}
|
package/dist/support/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{Tc as Y}from"../chunk-9xyxbxgk.js";import{Lh as M}from"../chunk-h43jp8ws.js";import{Ni as P,Pi as R}from"../chunk-nz8z8jr1.js";import"../chunk-4fx8p02c.js";import{cj as Q,dj as U,ej as V,fj as W}from"../chunk-d5f1m3d2.js";import"../chunk-tewhms9w.js";class S{static token;async boot(){}static inject(){if(!this.token)throw Error(`Service [${this.name}] does not declare a \`static token\`, so the container has no key to resolve it by.`);try{return R(this)}catch(x){throw Error(`Could not inject [${this.name}]. Services are constructed when the kernel boots, so `+"inject() only works from code that runs after that \u2014 a constructor default or a method "+`body, never module top level. Check that [${this.name}] is listed in \`services\` on your Kernel.`,{cause:x})}}static with(x){let f=new this;for(let[C,g]of Object.entries(x))if(g!==void 0)f[C]=g;return f}}import{readdir as z}from"fs/promises";import{join as B,parse as j}from"path";var H=[".ts",".tsx",".js",".mjs",".jsx"];function J(x={}){let f={};for(let[C,g]of Object.entries(x))f[C]=q(g);return new P(f)}async function L(x,f=new P){let C=[];try{C=await z(x)}catch(D){return f}let g=C.filter((D)=>{let{ext:v,name:F}=j(D);return H.includes(v)&&!F.startsWith(".")}).sort();for(let D of g){let{name:v}=j(D),F=await import(B(x,D));f.set(v,q(F))}return f}function q(x){if(x&&typeof x==="object"&&"default"in x)return x.default;return x}export{M as withDefaults,Q as sourceFiles,W as projectRoot,L as loadConfigFrom,V as discoverClasses,J as createConfigRepository,Y as ServiceProvider,S as Service,P as Repository,U as DiscoveryError};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=FD3C9F750E2A58A164756E2164756E21
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
"import { readdir } from \"node:fs/promises\";\nimport { join, parse } from \"node:path\";\n\nimport { Repository } from \"./Repository\";\n\nconst CONFIG_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".mjs\", \".jsx\"];\n\n// Builds a Repository from an already-imported map of config modules. The map\n// key becomes the top-level config key, so `{ mail: mailModule }` is readable\n// as `config.get(\"mail.driver\")`. Each entry may be either the module namespace\n// (its `default` export is unwrapped) or the config object itself.\nexport function createConfigRepository(\n modules: Record<string, any> = {},\n): Repository {\n const items: Record<string, any> = {};\n\n for (const [key, mod] of Object.entries(modules)) {\n items[key] = unwrap(mod);\n }\n\n return new Repository(items);\n}\n\n// Reads every config module in an app's `app/config` directory into a\n// Repository. The file's basename is the top-level key: `app/config/mail.ts`\n// populates `mail.*`. A missing directory yields an empty Repository so apps\n// that declare no config still boot.\nexport async function loadConfigFrom(\n directory: string,\n repository = new Repository(),\n): Promise<Repository> {\n let entries: string[] = [];\n\n try {\n entries = await readdir(directory);\n } catch (err) {\n return repository;\n }\n\n const files = entries\n .filter((entry) => {\n const { ext, name } = parse(entry);\n return CONFIG_EXTENSIONS.includes(ext) && !name.startsWith(\".\");\n })\n .sort();\n\n for (const file of files) {\n const { name } = parse(file);\n const mod = await import(join(directory, file));\n repository.set(name, unwrap(mod));\n }\n\n return repository;\n}\n\nfunction unwrap(mod: any) {\n if (mod && typeof mod === \"object\" && \"default\" in mod) {\n return mod.default;\n }\n return mod;\n}\n"
|
|
7
7
|
],
|
|
8
8
|
"mappings": ";2RAgCO,CAAe,JAAQ,EAOrB,OAMD,AAAI,EAAkB,QAmBrB,OAAS,EAKX,CACH,GAAI,CAAC,KAAK,MACR,MAAU,MACR,YAAY,KAAK,0FACnB,EAGF,GAAI,CACF,OAAO,EAAI,IAAuB,EAClC,MAAO,EAAO,CACd,MAAU,MACR,qBAAqB,KAAK,6DACxB,+FACA,6CAA6C,KAAK,kDAEpD,CAAE,OAAM,CACV,SAoBG,KAAuB,CAAoB,EAA0B,CAC1E,IAAM,EAAW,IAAI,KACrB,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAS,EACjD,GAAI,IAAU,OAAW,EAAS,GAAO,EAE3C,OAAO,EAEX,CChHA,kBAAS,oBACT,eAAS,WAAM,aAIf,IAAM,EAAoB,CAAC,MAAO,OAAQ,MAAO,OAAQ,MAAM,EAMxD,SAAS,CAAsB,CACpC,EAA+B,CAAC,EACpB,CACZ,IAAM,EAA6B,CAAC,EAEpC,QAAY,EAAK,KAAQ,OAAO,QAAQ,CAAO,EAC7C,EAAM,GAAO,EAAO,CAAG,EAGzB,OAAO,IAAI,EAAW,CAAK,EAO7B,eAAsB,CAAc,CAClC,EACA,EAAa,IAAI,EACI,CACrB,IAAI,EAAoB,CAAC,EAEzB,GAAI,CACF,EAAU,MAAM,EAAQ,CAAS,EACjC,MAAO,EAAK,CACZ,OAAO,EAGT,IAAM,EAAQ,EACX,OAAO,CAAC,IAAU,CACjB,IAAQ,MAAK,QAAS,EAAM,CAAK,EACjC,OAAO,EAAkB,SAAS,CAAG,GAAK,CAAC,EAAK,WAAW,GAAG,EAC/D,EACA,KAAK,EAER,QAAW,KAAQ,EAAO,CACxB,IAAQ,QAAS,EAAM,CAAI,EACrB,EAAM,MAAa,SAAK,EAAW,CAAI,GAC7C,EAAW,IAAI,EAAM,EAAO,CAAG,CAAC,EAGlC,OAAO,EAGT,SAAS,CAAM,CAAC,EAAU,CACxB,GAAI,GAAO,OAAO,IAAQ,UAAY,YAAa,EACjD,OAAO,EAAI,QAEb,OAAO",
|
|
9
|
-
"debugId": "
|
|
9
|
+
"debugId": "FD3C9F750E2A58A164756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -24,4 +24,6 @@ export type { PageProps, PageDictionary } from "./Page";
|
|
|
24
24
|
* test's module graph.
|
|
25
25
|
*/
|
|
26
26
|
export type { DispatchedEvent, FakeEventManager } from "../services/events/FakeEventManager";
|
|
27
|
+
export { renderStaticDocument } from "./staticDocument";
|
|
28
|
+
export type { StaticDocumentHandle, StaticDocumentOptions, StaticNavigationResult, StaticTestPage, } from "./staticDocument";
|
|
27
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,kBAAkB,CAAC"}
|
package/dist/testing/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { B as QueryManagerProvider, D as I18nProvider, F as createMemoryHistory, I as toVariantKey, J as Subject, L as applyParams, N as ProgressManager, O as ServerDataContext, P as Action, i as RouteTransitionProvider, o as ClientRouterContext, r as m, t as ThemeProvider, z as QueryManagerContext } from "../chunks/ThemeProvider-BLI4zpLu.js";
|
|
2
2
|
import { r as RouteStateProvider } from "../chunks/useParams-BN3XXfmG.js";
|
|
3
|
-
import { Suspense, useContext, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Suspense, createElement, useContext, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { hydrateRoot } from "react-dom/client";
|
|
5
6
|
//#region testing/Page.tsx
|
|
6
7
|
/** `"?a=b"` (or `""`) from any of the shapes `searchParams` accepts. */
|
|
7
8
|
function toSearchString(search) {
|
|
@@ -362,7 +363,189 @@ var Boundary = (props) => {
|
|
|
362
363
|
children: content
|
|
363
364
|
});
|
|
364
365
|
};
|
|
366
|
+
/**
|
|
367
|
+
* `h(marker, Component)`: hydrates one `<gemi-island>` marker with the island's
|
|
368
|
+
* component and the props the server serialised into `data-props`.
|
|
369
|
+
*
|
|
370
|
+
* The island's static children were rendered on the server into a
|
|
371
|
+
* `<gemi-slot>` (the first one that belongs to this marker, not to an island
|
|
372
|
+
* nested in it). They are handed back to the component as that same element
|
|
373
|
+
* with the server's HTML, so hydration matches and React leaves them alone.
|
|
374
|
+
*
|
|
375
|
+
* `data-uid` is the `identifierPrefix` the server rendered the island with, so
|
|
376
|
+
* `useId` agrees on both sides and two islands never share an id.
|
|
377
|
+
*
|
|
378
|
+
* Written as a function body with `createElement` and `hydrateRoot` free, so a
|
|
379
|
+
* test can run it against real React without a bundler.
|
|
380
|
+
*/
|
|
381
|
+
var ISLAND_HYDRATE_SOURCE = `function h(marker, Component) {
|
|
382
|
+
if (typeof Component !== "function" && (typeof Component !== "object" || Component === null)) {
|
|
383
|
+
throw new Error("gemi: island module has no component export for " + marker.outerHTML.slice(0, 80));
|
|
384
|
+
}
|
|
385
|
+
const json = marker.getAttribute("data-props");
|
|
386
|
+
const props = json ? JSON.parse(json) : {};
|
|
387
|
+
let slot = null;
|
|
388
|
+
for (const candidate of marker.querySelectorAll("gemi-slot")) {
|
|
389
|
+
if (candidate.closest("gemi-island") === marker) {
|
|
390
|
+
slot = candidate;
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const children = slot
|
|
395
|
+
? [createElement("gemi-slot", {
|
|
396
|
+
style: { display: "contents" },
|
|
397
|
+
suppressHydrationWarning: true,
|
|
398
|
+
dangerouslySetInnerHTML: { __html: slot.innerHTML },
|
|
399
|
+
})]
|
|
400
|
+
: [];
|
|
401
|
+
return hydrateRoot(marker, createElement(Component, props, ...children), {
|
|
402
|
+
identifierPrefix: marker.getAttribute("data-uid") || undefined,
|
|
403
|
+
});
|
|
404
|
+
}`;
|
|
405
|
+
`${ISLAND_HYDRATE_SOURCE}`;
|
|
406
|
+
//#endregion
|
|
407
|
+
//#region internal/staticNavigationRuntime.ts
|
|
408
|
+
/**
|
|
409
|
+
* The navigation runtime (with the island loader) a static view with
|
|
410
|
+
* `.static({ navigation })` inlines. Byte-for-byte constant.
|
|
411
|
+
*/
|
|
412
|
+
var STATIC_NAVIGATION_SOURCE = "var r=document,i=window,a=history;i.__gemi_nav?.d();var L=new AbortController,h=(t,e,n,s)=>t.addEventListener(e,n,{signal:L.signal,...s}),q=i.__gemi_nav={d:()=>L.abort()},v=(t,e)=>{if(!t.g)t.g=1,import(e.s).then((n)=>{if(t.isConnected)t.r=n.h(t,n.m[e.e])}).catch((n)=>console.error(n))},D=(t)=>{let e=t.getElementById(\"gemi-islands\");return e?JSON.parse(e.textContent):{i:[]}},R=(t,e)=>{for(let n of t.querySelectorAll(\"gemi-island\")){let s=e.i[n.dataset.island];if(!s||n.o)continue;if(s.l==\"eager\")v(n,s);else if(s.l==\"idle\"||!i.IntersectionObserver||!n.children.length)(i.requestIdleCallback||setTimeout)(()=>v(n,s));else{let l=new IntersectionObserver((m)=>{if(m.some((d)=>d.isIntersecting))l.disconnect(),v(n,s)});for(let m of n.children)l.observe(m)}}},O='meta[name=\"gemi-static\"]',A=\"style:not([data-gemi-fonts])\",T=A+\",link[rel=stylesheet]\",K=`head>${A},body>${A},link[rel=stylesheet]`,I='meta[name]:not([name=viewport]),meta[property],link[rel~=canonical],link[rel~=alternate],link[rel~=icon],link[rel=preload][as=font],style[data-gemi-fonts],script[type=\"application/ld+json\"]',w=(t)=>t.querySelector(O)?.content,C=(t)=>[...t.querySelectorAll(K)].map((e)=>e.outerHTML).join(),c=(t)=>t.href.split(\"#\")[0],p=r.createElement(\"div\");p.setAttribute(\"aria-live\",\"polite\");p.style.cssText=\"position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap\";r.body.append(p);var _=(t)=>{q.p={url:location.href,title:r.title,initial:t},r.dispatchEvent(new CustomEvent(\"gemi:page-load\",{detail:q.p}))},f=new Map,k=(t)=>{let e=f.get(t);if(!e||Date.now()-e[0]>30000){let n=fetch(t,{headers:{accept:\"text/html\",\"x-gemi-navigate\":\"1\"},signal:AbortSignal.timeout(1e4)}).then((s)=>{if(!s.ok||!/^text\\/html/.test(s.headers.get(\"content-type\"))||new URL(s.url||t).origin!=location.origin)throw s;return s.text().then((l)=>[s.url||t,l])});e=[Date.now(),n],n.catch(()=>f.get(t)==e&&f.delete(t))}if(f.delete(t),f.set(t,e),f.size>10)f.delete(f.keys().next().value);return e[1]},M=(t)=>{let e=t.target.closest?.(\"a[href]\"),n=e?.getAttribute(\"target\");if(!e||n&&n!=\"_self\"||e.hasAttribute(\"download\")||/(^|\\s)external(\\s|$)/i.test(e.getAttribute(\"rel\"))||e.closest(\"[data-gemi-reload]\"))return;let s=new URL(e.getAttribute(\"href\"),r.baseURI);if(s.origin==location.origin&&!(s.href.includes(\"#\")&&c(s)==c(location)))return s},y={},U=()=>Math.random().toString(36).slice(2),E=()=>a.state?.g||a.replaceState({...a.state,g:U()},\"\"),P=c(location),b=0,N=(t)=>{if(!t.hasAttribute(\"tabindex\"))t.setAttribute(\"tabindex\",\"-1\"),t.addEventListener(\"blur\",()=>t.removeAttribute(\"tabindex\"),{once:!0});t.focus({preventScroll:!0})},Y=(t)=>{let e=r.body,n=t.body,s=D(t),l=r.documentElement;r.title=t.title;for(let o of[\"lang\",\"dir\"]){let u=t.documentElement.getAttribute(o);if(u==null)l.removeAttribute(o);else l.setAttribute(o,u)}for(let o of r.head.querySelectorAll(I))o.remove();let m=new Set([...r.querySelectorAll(\"link[rel=modulepreload]\")].map((o)=>o.getAttribute(\"href\")));r.head.append(...t.head.querySelectorAll(I),...[...t.head.querySelectorAll(\"link[rel=modulepreload]\")].filter((o)=>!m.has(o.getAttribute(\"href\"))));let d=new Map([...e.querySelectorAll(\"[data-gemi-persist]\")].map((o)=>[o.dataset.gemiPersist,o])),g=[...n.querySelectorAll(\"[data-gemi-persist]\")].map((o)=>[o,d.get(o.dataset.gemiPersist)]).filter((o)=>o[1]);for(let o of[...e.querySelectorAll(\"gemi-island\")].reverse())if(o.o=1,!g.some((u)=>u[1].contains(o)))try{o.r?.unmount()}catch(u){console.error(u)}for(let[o,u]of g)o.replaceWith(u);for(let o of[...e.childNodes])if(!o.matches?.(T))o.remove();for(let o of[...n.children])if(o.matches(T))o.remove();for(let o of[...e.attributes])e.removeAttribute(o.name);for(let o of n.attributes)e.setAttribute(o.name,o.value);e.append(...n.childNodes,p),R(e,s)},H=async(t,e)=>{let n=++b,s=!e&&y[a.state?.g];a.scrollRestoration=\"manual\";try{let[l,m]=await k(c(t));if(n!=b)return;let d=new DOMParser().parseFromString(m,\"text/html\");if(w(d)==null||w(d)!=w(r)||C(d)!=C(r))throw 0;if(e){let o=new URL(l);o.hash=t.hash,a.pushState({g:U()},\"\",o.href)}P=c(location),Y(d);let g=e&&t.hash&&r.getElementById(decodeURIComponent(t.hash.slice(1)));if(g)g.scrollIntoView({behavior:\"instant\"});else i.scrollTo({left:s?.[0]||0,top:s?.[1]||0,behavior:\"instant\"});if(e)N(g||r.querySelector(\"h1\")||r.querySelector(\"main\")||r.body);p.textContent=r.title,_(!1)}catch{if(n!=b)return;if(e)location.assign(t.href);else location.reload()}};h(r,\"click\",(t)=>{if(t.defaultPrevented||t.button||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;let e=M(t);if(e&&r.dispatchEvent(new CustomEvent(\"gemi:before-navigate\",{cancelable:!0,detail:{url:e.href}})))t.preventDefault(),E(),y[a.state.g]=[i.scrollX,i.scrollY],H(e,1)});h(i,\"popstate\",()=>{if(b++,c(location)==P){let t=y[a.state?.g];if(t)i.scrollTo({left:t[0],top:t[1],behavior:\"instant\"})}else if(a.state?.g)H(new URL(location.href),0);else location.reload()});h(i,\"hashchange\",E);h(i,\"scroll\",()=>a.state?.g&&(y[a.state.g]=[i.scrollX,i.scrollY]),{passive:!0});var S,x=(t)=>{if(r.querySelector(O)?.dataset.prefetch==\"none\"||navigator.connection?.saveData)return;let e=M(t);if(e&&c(e)!=c(location))k(c(e))};h(r,\"pointerover\",(t)=>{clearTimeout(S),S=setTimeout(()=>x(t),65)});h(r,\"pointerout\",()=>clearTimeout(S));h(r,\"focusin\",x);h(r,\"touchstart\",x,{passive:!0});E();R(r,D(r));_(!0);";
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region testing/staticDocument.ts
|
|
415
|
+
var hydrate = new Function("createElement", "hydrateRoot", `${ISLAND_HYDRATE_SOURCE};return h;`)(createElement, hydrateRoot);
|
|
416
|
+
/**
|
|
417
|
+
* Puts a static document (`.static({ navigation })`) into the test's DOM and
|
|
418
|
+
* starts its navigation runtime against stubbed pages, so a test can check that
|
|
419
|
+
* a site's links are followed client-side, and what the next page looks like.
|
|
420
|
+
* Needs a DOM (`// @vitest-environment jsdom`).
|
|
421
|
+
*
|
|
422
|
+
* ```ts
|
|
423
|
+
* const html = await (await render("/")).text(); // the page, from your app
|
|
424
|
+
* const page = renderStaticDocument(html, { pages: { "/about": aboutHtml } });
|
|
425
|
+
* expect(await page.navigate("/about")).toEqual({ kind: "swap", url: "http://localhost:3000/about" });
|
|
426
|
+
* expect(document.querySelector("h1")!.textContent).toBe("About");
|
|
427
|
+
* page.dispose();
|
|
428
|
+
* ```
|
|
429
|
+
*
|
|
430
|
+
* The document's own scripts do not run (the helper runs the runtime itself),
|
|
431
|
+
* and a link the runtime leaves alone is not followed. Islands hydrate
|
|
432
|
+
* asynchronously, as in a browser: wrap what follows in `act`, or wait for it.
|
|
433
|
+
*/
|
|
434
|
+
function renderStaticDocument(html, options = {}) {
|
|
435
|
+
const requests = [];
|
|
436
|
+
const fullLoads = [];
|
|
437
|
+
let settle;
|
|
438
|
+
const outcome = () => new Promise((resolve, reject) => {
|
|
439
|
+
const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("the navigation did not finish in 5 s")), 5e3);
|
|
440
|
+
settle = (result) => {
|
|
441
|
+
clearTimeout(timer);
|
|
442
|
+
settle = void 0;
|
|
443
|
+
resolve(result);
|
|
444
|
+
};
|
|
445
|
+
});
|
|
446
|
+
history.replaceState(null, "", options.url ?? "/");
|
|
447
|
+
const parsed = new DOMParser().parseFromString(html, "text/html");
|
|
448
|
+
for (const script of Array.from(parsed.querySelectorAll("script"))) if (!/json/.test(script.type)) script.remove();
|
|
449
|
+
document.replaceChild(document.importNode(parsed.documentElement, true), document.documentElement);
|
|
450
|
+
const fullLoad = (url) => {
|
|
451
|
+
fullLoads.push(url);
|
|
452
|
+
settle?.({
|
|
453
|
+
kind: "full-load",
|
|
454
|
+
url
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
const location = {
|
|
458
|
+
get href() {
|
|
459
|
+
return window.location.href;
|
|
460
|
+
},
|
|
461
|
+
get origin() {
|
|
462
|
+
return window.location.origin;
|
|
463
|
+
},
|
|
464
|
+
assign: (url) => fullLoad(new URL(url, window.location.href).href),
|
|
465
|
+
reload: () => fullLoad(window.location.href)
|
|
466
|
+
};
|
|
467
|
+
const pages = options.pages ?? {};
|
|
468
|
+
const fetch = async (input) => {
|
|
469
|
+
const url = new URL(input, window.location.href);
|
|
470
|
+
requests.push(url.href);
|
|
471
|
+
const page = typeof pages === "function" ? await pages(url) : pages[url.href] ?? pages[url.pathname + url.search];
|
|
472
|
+
const spec = page === void 0 ? {
|
|
473
|
+
status: 404,
|
|
474
|
+
html: "not found",
|
|
475
|
+
contentType: "text/plain"
|
|
476
|
+
} : typeof page === "string" ? { html: page } : page;
|
|
477
|
+
const response = new Response(spec.html ?? "", {
|
|
478
|
+
status: spec.status ?? 200,
|
|
479
|
+
headers: { "content-type": spec.contentType ?? "text/html; charset=utf-8" }
|
|
480
|
+
});
|
|
481
|
+
Object.defineProperty(response, "url", { value: new URL(spec.url ?? url.href, url).href });
|
|
482
|
+
return response;
|
|
483
|
+
};
|
|
484
|
+
const importIsland = async (src) => {
|
|
485
|
+
const module = options.islands?.[src];
|
|
486
|
+
if (!module) throw new Error(`renderStaticDocument: no island module for ${src} in options.islands`);
|
|
487
|
+
return {
|
|
488
|
+
m: module,
|
|
489
|
+
h: hydrate
|
|
490
|
+
};
|
|
491
|
+
};
|
|
492
|
+
let announced;
|
|
493
|
+
const onBeforeNavigate = (event) => {
|
|
494
|
+
announced = event;
|
|
495
|
+
};
|
|
496
|
+
document.addEventListener("gemi:before-navigate", onBeforeNavigate);
|
|
497
|
+
const onClick = (event) => {
|
|
498
|
+
const taken = announced !== void 0 && !announced.defaultPrevented;
|
|
499
|
+
announced = void 0;
|
|
500
|
+
if (taken || !event.target.closest?.("a[href]")) return;
|
|
501
|
+
event.preventDefault();
|
|
502
|
+
settle?.({ kind: "native" });
|
|
503
|
+
};
|
|
504
|
+
window.addEventListener("click", onClick);
|
|
505
|
+
const onPageLoad = (event) => {
|
|
506
|
+
const detail = event.detail;
|
|
507
|
+
if (!detail.initial) settle?.({
|
|
508
|
+
kind: "swap",
|
|
509
|
+
url: detail.url
|
|
510
|
+
});
|
|
511
|
+
};
|
|
512
|
+
document.addEventListener("gemi:page-load", onPageLoad);
|
|
513
|
+
const scrollTo = window.scrollTo;
|
|
514
|
+
window.scrollTo = () => {};
|
|
515
|
+
const scrollIntoView = Element.prototype.scrollIntoView;
|
|
516
|
+
Element.prototype.scrollIntoView = function() {};
|
|
517
|
+
const source = STATIC_NAVIGATION_SOURCE.replace("import(", "__import(");
|
|
518
|
+
new Function("__import", "location", "fetch", source)(importIsland, location, fetch);
|
|
519
|
+
return {
|
|
520
|
+
requests,
|
|
521
|
+
fullLoads,
|
|
522
|
+
async navigate(href, init) {
|
|
523
|
+
const link = Array.from(document.querySelectorAll("a[href]")).find((a) => a.getAttribute("href") === href);
|
|
524
|
+
if (!link) throw new Error(`renderStaticDocument: no <a href="${href}"> on the page`);
|
|
525
|
+
const done = outcome();
|
|
526
|
+
link.dispatchEvent(new MouseEvent("click", {
|
|
527
|
+
bubbles: true,
|
|
528
|
+
cancelable: true,
|
|
529
|
+
...init
|
|
530
|
+
}));
|
|
531
|
+
return await done;
|
|
532
|
+
},
|
|
533
|
+
async back() {
|
|
534
|
+
const done = outcome();
|
|
535
|
+
history.back();
|
|
536
|
+
return await done;
|
|
537
|
+
},
|
|
538
|
+
dispose() {
|
|
539
|
+
window.__gemi_nav?.d();
|
|
540
|
+
window.removeEventListener("click", onClick);
|
|
541
|
+
document.removeEventListener("gemi:before-navigate", onBeforeNavigate);
|
|
542
|
+
document.removeEventListener("gemi:page-load", onPageLoad);
|
|
543
|
+
window.scrollTo = scrollTo;
|
|
544
|
+
Element.prototype.scrollIntoView = scrollIntoView;
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
}
|
|
365
548
|
//#endregion
|
|
366
|
-
export { Page };
|
|
549
|
+
export { Page, renderStaticDocument };
|
|
367
550
|
|
|
368
551
|
//# sourceMappingURL=index.js.map
|