gemi 0.57.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/index.js +1 -1
- package/dist/broadcasting/index.js +1 -1
- package/dist/bun/plugin.js +1 -1
- package/dist/bun/preload.js +1 -1
- package/dist/{chunk-msyqr4y7.js → chunk-0a2xgcj3.js} +2 -2
- package/dist/{chunk-msyqr4y7.js.map → chunk-0a2xgcj3.js.map} +1 -1
- package/dist/{chunk-64bq12j3.js → chunk-3337e5g0.js} +2 -2
- package/dist/{chunk-64bq12j3.js.map → chunk-3337e5g0.js.map} +1 -1
- package/dist/{chunk-5fmbsy4q.js → chunk-3aa287k7.js} +2 -2
- package/dist/{chunk-5fmbsy4q.js.map → chunk-3aa287k7.js.map} +1 -1
- package/dist/{chunk-f233yzxf.js → chunk-3g5bjvdf.js} +2 -2
- package/dist/{chunk-f233yzxf.js.map → chunk-3g5bjvdf.js.map} +1 -1
- package/dist/{chunk-rc2asvyf.js → chunk-3xadx444.js} +2 -2
- package/dist/{chunk-rc2asvyf.js.map → chunk-3xadx444.js.map} +1 -1
- package/dist/{chunk-7pn0bnsc.js → chunk-3zxwscmf.js} +2 -2
- package/dist/{chunk-4f69ygc8.js.map → chunk-3zxwscmf.js.map} +1 -1
- package/dist/{chunk-jzatvtjd.js → chunk-437085pe.js} +2 -2
- package/dist/{chunk-jzatvtjd.js.map → chunk-437085pe.js.map} +1 -1
- package/dist/{chunk-17m5wxv0.js → chunk-4yt5x8s2.js} +2 -2
- package/dist/{chunk-17m5wxv0.js.map → chunk-4yt5x8s2.js.map} +1 -1
- package/dist/{chunk-dxxak51x.js → chunk-5athahgr.js} +2 -2
- package/dist/{chunk-dxxak51x.js.map → chunk-5athahgr.js.map} +1 -1
- package/dist/{chunk-dcwjwfjc.js → chunk-5n2rvfh3.js} +2 -2
- package/dist/{chunk-dcwjwfjc.js.map → chunk-5n2rvfh3.js.map} +1 -1
- package/dist/{chunk-r8637cqv.js → chunk-6235kb30.js} +3 -3
- package/dist/{chunk-r8637cqv.js.map → chunk-6235kb30.js.map} +1 -1
- package/dist/{chunk-67zyjx0c.js → chunk-7b0x860b.js} +2 -2
- package/dist/{chunk-67zyjx0c.js.map → chunk-7b0x860b.js.map} +1 -1
- package/dist/{chunk-q8k3gh8k.js → chunk-7ef5n8k2.js} +2 -2
- package/dist/{chunk-q8k3gh8k.js.map → chunk-7ef5n8k2.js.map} +1 -1
- package/dist/{chunk-n2zmg475.js → chunk-7j6wbv12.js} +2 -2
- package/dist/{chunk-n2zmg475.js.map → chunk-7j6wbv12.js.map} +1 -1
- package/dist/{chunk-g5pj95dz.js → chunk-86jebsm4.js} +3 -3
- package/dist/{chunk-g5pj95dz.js.map → chunk-86jebsm4.js.map} +1 -1
- package/dist/chunk-87qab82w.js +5 -0
- package/dist/{chunk-9j9wqrb2.js.map → chunk-87qab82w.js.map} +7 -3
- package/dist/{chunk-dwz0wbhj.js → chunk-8gew8b9a.js} +2 -2
- package/dist/{chunk-dwz0wbhj.js.map → chunk-8gew8b9a.js.map} +1 -1
- package/dist/{chunk-74aj8ms2.js → chunk-9m2tbf3n.js} +2 -2
- package/dist/{chunk-74aj8ms2.js.map → chunk-9m2tbf3n.js.map} +1 -1
- package/dist/{chunk-bw8kt7ps.js → chunk-a2sgjpvq.js} +2 -2
- package/dist/{chunk-bw8kt7ps.js.map → chunk-a2sgjpvq.js.map} +1 -1
- package/dist/chunk-b35e128b.js +5 -0
- package/dist/{chunk-r9as9htn.js.map → chunk-b35e128b.js.map} +1 -1
- package/dist/{chunk-1esnvq2z.js → chunk-cyaz97p5.js} +2 -2
- package/dist/{chunk-1esnvq2z.js.map → chunk-cyaz97p5.js.map} +1 -1
- package/dist/{chunk-mqwrmbh4.js → chunk-d125j8t0.js} +3 -3
- package/dist/{chunk-mqwrmbh4.js.map → chunk-d125j8t0.js.map} +1 -1
- package/dist/{chunk-yhzb9qpk.js → chunk-dgsgjg53.js} +2 -2
- package/dist/{chunk-yhzb9qpk.js.map → chunk-dgsgjg53.js.map} +1 -1
- package/dist/{chunk-6c14bexh.js → chunk-eejmhtnc.js} +2 -2
- package/dist/{chunk-6c14bexh.js.map → chunk-eejmhtnc.js.map} +1 -1
- package/dist/{chunk-vdzb29p5.js → chunk-fjm4y8bn.js} +2 -2
- package/dist/{chunk-vdzb29p5.js.map → chunk-fjm4y8bn.js.map} +1 -1
- package/dist/{chunk-ma5rj4st.js → chunk-grdahng8.js} +2 -2
- package/dist/{chunk-ma5rj4st.js.map → chunk-grdahng8.js.map} +1 -1
- package/dist/{chunk-5txddtaa.js → chunk-gw6agevz.js} +3 -3
- package/dist/{chunk-5txddtaa.js.map → chunk-gw6agevz.js.map} +1 -1
- package/dist/{chunk-ba0rkpk5.js → chunk-hppagzz4.js} +4 -4
- package/dist/{chunk-ba0rkpk5.js.map → chunk-hppagzz4.js.map} +1 -1
- package/dist/chunk-hwa5sqw5.js +19 -0
- package/dist/{chunk-r9h6aj7g.js.map → chunk-hwa5sqw5.js.map} +12 -6
- package/dist/chunk-hxf1re93.js +4 -0
- package/dist/{chunk-6fc909z5.js.map → chunk-hxf1re93.js.map} +6 -5
- package/dist/{chunk-d6kgxmp7.js → chunk-j0c6ytkj.js} +3 -3
- package/dist/{chunk-d6kgxmp7.js.map → chunk-j0c6ytkj.js.map} +1 -1
- package/dist/{chunk-4f69ygc8.js → chunk-jhkjz9jr.js} +2 -2
- package/dist/{chunk-7pn0bnsc.js.map → chunk-jhkjz9jr.js.map} +1 -1
- package/dist/{chunk-e9zz0zfv.js → chunk-k0fvsyeh.js} +1 -1
- package/dist/{chunk-j21tm6jf.js → chunk-keehyx51.js} +2 -2
- package/dist/{chunk-j21tm6jf.js.map → chunk-keehyx51.js.map} +1 -1
- package/dist/{chunk-a70s8pz4.js → chunk-m3xy5xyf.js} +2 -2
- package/dist/{chunk-a70s8pz4.js.map → chunk-m3xy5xyf.js.map} +1 -1
- package/dist/{chunk-swe2b6rv.js → chunk-mkfpnymy.js} +1 -1
- package/dist/{chunk-qkrba9c2.js → chunk-mwpdp09e.js} +2 -2
- package/dist/{chunk-qkrba9c2.js.map → chunk-mwpdp09e.js.map} +1 -1
- package/dist/{chunk-tzsnadg1.js → chunk-pmhd6zfc.js} +3 -3
- package/dist/{chunk-tzsnadg1.js.map → chunk-pmhd6zfc.js.map} +1 -1
- package/dist/chunk-qb5mv6pj.js +5 -0
- package/dist/chunk-qb5mv6pj.js.map +12 -0
- package/dist/{chunk-nqk3cx97.js → chunk-qgxr0g36.js} +2 -2
- package/dist/{chunk-nqk3cx97.js.map → chunk-qgxr0g36.js.map} +1 -1
- package/dist/{chunk-btr9kyqh.js → chunk-sy7jbdeb.js} +2 -2
- package/dist/{chunk-btr9kyqh.js.map → chunk-sy7jbdeb.js.map} +1 -1
- package/dist/{chunk-5z5xskg1.js → chunk-szss069z.js} +2 -2
- package/dist/{chunk-5z5xskg1.js.map → chunk-szss069z.js.map} +1 -1
- package/dist/{chunk-rxsmwbxv.js → chunk-tss5svjr.js} +2 -2
- package/dist/{chunk-rxsmwbxv.js.map → chunk-tss5svjr.js.map} +1 -1
- package/dist/{chunk-32d510cd.js → chunk-vr90r27j.js} +2 -2
- package/dist/{chunk-32d510cd.js.map → chunk-vr90r27j.js.map} +1 -1
- package/dist/{chunk-jny4f23c.js → chunk-w62m5f0n.js} +3 -3
- package/dist/{chunk-jny4f23c.js.map → chunk-w62m5f0n.js.map} +1 -1
- package/dist/{chunk-k5bjfhz8.js → chunk-w7rf99w6.js} +2 -2
- package/dist/{chunk-k5bjfhz8.js.map → chunk-w7rf99w6.js.map} +1 -1
- package/dist/{chunk-fck5yw2s.js → chunk-wbrj0gya.js} +2 -2
- package/dist/{chunk-fck5yw2s.js.map → chunk-wbrj0gya.js.map} +1 -1
- package/dist/{chunk-11dkjm1r.js → chunk-xdv1b8mr.js} +2 -2
- package/dist/{chunk-11dkjm1r.js.map → chunk-xdv1b8mr.js.map} +1 -1
- package/dist/{chunk-katt90qz.js → chunk-xey9cbap.js} +2 -2
- package/dist/{chunk-katt90qz.js.map → chunk-xey9cbap.js.map} +1 -1
- package/dist/{chunk-ae6xz52s.js → chunk-xzk827r3.js} +2 -2
- package/dist/{chunk-ae6xz52s.js.map → chunk-xzk827r3.js.map} +1 -1
- package/dist/{chunk-8v81dvje.js → chunk-y6a8r2bn.js} +3 -3
- package/dist/{chunk-8v81dvje.js.map → chunk-y6a8r2bn.js.map} +1 -1
- package/dist/{chunk-nkbreczg.js → chunk-yed5whgs.js} +3 -3
- package/dist/{chunk-nkbreczg.js.map → chunk-yed5whgs.js.map} +1 -1
- package/dist/{chunk-cecq6q1b.js → chunk-yf7vz71n.js} +1 -1
- package/dist/{chunk-knvxwrwh.js → chunk-yjzs247s.js} +2 -2
- package/dist/{chunk-knvxwrwh.js.map → chunk-yjzs247s.js.map} +1 -1
- package/dist/{chunk-ka4tdhm8.js → chunk-yy0eb9wn.js} +2 -2
- package/dist/{chunk-ka4tdhm8.js.map → chunk-yy0eb9wn.js.map} +1 -1
- package/dist/{chunk-1nqdzmvm.js → chunk-zbxgbr12.js} +2 -2
- package/dist/{chunk-1nqdzmvm.js.map → chunk-zbxgbr12.js.map} +1 -1
- package/dist/{chunk-wrypq618.js → chunk-zh2egcyb.js} +2 -2
- package/dist/{chunk-wrypq618.js.map → chunk-zh2egcyb.js.map} +1 -1
- package/dist/chunks/ThemeProvider-li1J_igh.js.map +1 -1
- package/dist/client/ClientRouter.d.ts.map +1 -1
- package/dist/client/ProgressManager.d.ts +1 -1
- package/dist/client/RouteStateContext.d.ts +9 -0
- package/dist/client/RouteStateContext.d.ts.map +1 -1
- package/dist/client/ServerDataProvider.d.ts +7 -0
- package/dist/client/ServerDataProvider.d.ts.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +68 -10
- package/dist/client/index.js.map +1 -1
- package/dist/client/rpc.d.ts +42 -0
- package/dist/client/rpc.d.ts.map +1 -1
- package/dist/client/useFeature.d.ts +40 -0
- package/dist/client/useFeature.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/Features.d.ts +57 -0
- package/dist/facades/Features.d.ts.map +1 -0
- package/dist/facades/index.d.ts +1 -0
- package/dist/facades/index.d.ts.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/gemi.d.ts +13 -5
- package/dist/http/ApiRouter.d.ts +3 -2
- package/dist/http/ApiRouter.d.ts.map +1 -1
- package/dist/http/HttpRequest.d.ts +4 -0
- package/dist/http/HttpRequest.d.ts.map +1 -1
- package/dist/http/ViewRouter.d.ts +127 -4
- package/dist/http/ViewRouter.d.ts.map +1 -1
- package/dist/http/index.d.ts +1 -0
- 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/http/middlewareList.d.ts +25 -0
- package/dist/http/middlewareList.d.ts.map +1 -0
- package/dist/http/requestContext.d.ts +57 -0
- package/dist/http/requestContext.d.ts.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 +1 -1
- package/dist/kernel/index.js +3 -3
- package/dist/kernel/index.js.map +3 -3
- package/dist/kernel/providers.d.ts +2 -2
- package/dist/kernel/providers.d.ts.map +1 -1
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/services/features/FeatureFlagStore.d.ts +60 -0
- package/dist/services/features/FeatureFlagStore.d.ts.map +1 -0
- package/dist/services/features/FeatureManager.d.ts +82 -0
- package/dist/services/features/FeatureManager.d.ts.map +1 -0
- package/dist/services/features/FeaturesServiceProvider.d.ts +6 -0
- package/dist/services/features/FeaturesServiceProvider.d.ts.map +1 -0
- package/dist/services/features/bucket.d.ts +57 -0
- package/dist/services/features/bucket.d.ts.map +1 -0
- package/dist/services/features/config.d.ts +57 -0
- package/dist/services/features/config.d.ts.map +1 -0
- package/dist/services/features/context.d.ts +31 -0
- package/dist/services/features/context.d.ts.map +1 -0
- package/dist/services/features/defineFeature.d.ts +145 -0
- package/dist/services/features/defineFeature.d.ts.map +1 -0
- package/dist/services/features/evaluate.d.ts +74 -0
- package/dist/services/features/evaluate.d.ts.map +1 -0
- package/dist/services/features/sources/DatabaseFeatureFlagSource.d.ts +19 -0
- package/dist/services/features/sources/DatabaseFeatureFlagSource.d.ts.map +1 -0
- package/dist/services/features/sources/FeatureFlagSource.d.ts +30 -0
- package/dist/services/features/sources/FeatureFlagSource.d.ts.map +1 -0
- package/dist/services/features/sources/StaticFeatureFlagSource.d.ts +24 -0
- package/dist/services/features/sources/StaticFeatureFlagSource.d.ts.map +1 -0
- package/dist/services/features/types.d.ts +63 -0
- package/dist/services/features/types.d.ts.map +1 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +8 -8
- package/dist/services/index.js.map +6 -4
- package/dist/services/router/ViewRouteDispatcher.d.ts +8 -0
- package/dist/services/router/ViewRouteDispatcher.d.ts.map +1 -1
- package/dist/services/router/createFlatViewRoutes.d.ts +14 -0
- package/dist/services/router/createFlatViewRoutes.d.ts.map +1 -1
- package/dist/services/router/streamQueryInjection.d.ts.map +1 -1
- package/dist/support/index.js +2 -2
- package/dist/support/index.js.map +1 -1
- package/dist/testing/Page.d.ts +12 -0
- package/dist/testing/Page.d.ts.map +1 -1
- package/dist/testing/index.js +7 -3
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6fc909z5.js +0 -4
- package/dist/chunk-9j9wqrb2.js +0 -5
- package/dist/chunk-qfzyym5h.js +0 -5
- package/dist/chunk-qfzyym5h.js.map +0 -12
- package/dist/chunk-r9as9htn.js +0 -5
- package/dist/chunk-r9h6aj7g.js +0 -19
- /package/dist/{chunk-e9zz0zfv.js.map → chunk-k0fvsyeh.js.map} +0 -0
- /package/dist/{chunk-swe2b6rv.js.map → chunk-mkfpnymy.js.map} +0 -0
- /package/dist/{chunk-cecq6q1b.js.map → chunk-yf7vz71n.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{Tb as E,Ub as O,Vb as x}from"./chunk-fjm4y8bn.js";import{qf as B}from"./chunk-sy7jbdeb.js";import{Af as I}from"./chunk-d125j8t0.js";function b(_){return _}function P(){return{jobs:[],jobsDir:"app/jobs",concurrency:1}}function D(){let _=process.env.APP_DIR,Q=process.env.ROOT_DIR,F=Bun.env.NODE_ENV==="production"?`${Q}/dist/server/bootstrap.mjs`:`${_}/bootstrap.ts`,X=new File([`
|
|
3
3
|
import { app } from "${F}"
|
|
4
4
|
self.onmessage = async (event) => {
|
|
5
5
|
const clone = app.clone()
|
|
@@ -32,6 +32,6 @@ import{Nb as E,Ob as O,Pb as x}from"./chunk-vdzb29p5.js";import{_e as B}from"./c
|
|
|
32
32
|
static event = UserRegistered;
|
|
33
33
|
|
|
34
34
|
If this is an abstract base its subclasses extend, move it out of the `+"listeners directory \u2014 the walk excludes gemi's `Listener` and "+"nothing else, so a base sitting beside its subclasses is registered and run like one of them.")}function g(_){for(let Q of _){if(Object.getOwnPropertyDescriptor(Q,"name")?.writable)continue;console.warn(`Event listener ${Q.name} does not declare \`static name\`, so it is registered under its class name, which a production build renames. Nothing reads that name across a build boundary while the `+"listener is sync, which is why this is a warning \u2014 but adding "+`\`queued = true\` to it is refused at boot for the same reason, because the queue's key is that string. Add: static name = "${Q.name}";`)}}function m(_){let Q=new Set;for(let{event:F}of _){if(Q.has(F))continue;if(Object.getOwnPropertyDescriptor(F,"name")?.writable)continue;Q.add(F),console.warn(`Event ${F.name} does not declare \`static name\`, so it is dispatched under its class name. A production build minifies the code that dispatches it and renames the class, while discovery reads `+"the listener's copy from source and does not \u2014 so the dispatch would "+`reach no listener in production and nowhere else. Add: static name = "${F.name}";`)}}
|
|
35
|
-
export{b as
|
|
35
|
+
export{b as zb,P as Ab,J as Bb,k as Cb,K as Db,n as Eb,C as Fb,s as Gb,S as Hb,__ as Ib,A as Jb,F_ as Kb,W as Lb,U as Mb,L as Nb,E_ as Ob,B_ as Pb,C_ as Qb,T_ as Rb};
|
|
36
36
|
|
|
37
|
-
//# debugId=
|
|
37
|
+
//# debugId=B91404D39945B18264756E2164756E21
|
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
"import { existsSync } from \"node:fs\";\nimport { dirname, isAbsolute, join } from \"node:path\";\n\nimport {\n discoverClasses,\n DiscoveryError,\n projectRoot,\n} from \"../support/discover\";\nimport { Command, type CommandClass } from \"../console/Command\";\nimport { commandConfigDefaults } from \"../console/config\";\nimport { isUnfinishedBuilder } from \"../console/builder\";\nimport { CronJob } from \"./cron/CronJob\";\nimport { scheduleConfigDefaults } from \"./cron/config\";\nimport { eventConfigDefaults } from \"./events/config\";\nimport type { EventClass } from \"./events/Event\";\nimport { Listener, type ListenerClass } from \"./events/Listener\";\nimport { Job } from \"./queue/Job\";\nimport { queueConfigDefaults } from \"./queue/config\";\n\n/**\n * Reading an application's jobs off the filesystem, for the two subsystems that\n * were asking every app to write its job list twice.\n *\n * Both functions here are the same call to `discoverClasses` with a different\n * base class, which is deliberate: one walk, one set of skip rules, one answer\n * to \"what does this app have\". They are exported from `gemi/services` rather\n * than kept private to the providers because the list stopped being something\n * an app could import — a test that used to walk the exported `jobs` array\n * needs somewhere to ask the same question, and so does a script.\n *\n * What the providers add on top of these is the decision of *whether* to ask,\n * which is the config's to make and not this file's.\n */\n\n/**\n * A directory the app named, resolved the way the app meant it.\n *\n * Relative paths hang off the project root rather than `process.cwd()` at the\n * moment of the call, because a config slice saying `app/jobs` means the app's\n * `app/jobs` and not whatever directory somebody happened to launch a script\n * from. Absolute paths are taken as given, which is what makes these callable\n * from a test that has no project around it.\n */\nfunction resolveDir(dir: string): string {\n return isAbsolute(dir) ? dir : join(projectRoot(), dir);\n}\n\n/**\n * Says something when the directory is missing *and so is the tree it lives in*.\n *\n * A missing directory has two readings and they want opposite responses. An app\n * that has never written a cron job has no `app/cron`, and warning about that on\n * every boot for the rest of its life is noise — the answer \"you have no cron\n * jobs\" is correct and uninteresting. But a deploy that ships `dist/` and\n * `node_modules/` without the source has no `app/cron` *and no `app/`*, and\n * there discovery quietly returns nothing while the app very much does have\n * jobs: the exact silence #322 and #323 exist to remove, reintroduced one layer\n * down and in production only.\n *\n * The parent directory is what tells them apart. If neither the directory nor\n * the one above it is there, the tree this was pointed into is not there\n * either, and that is worth a sentence.\n */\nfunction warnIfSourceIsMissing(\n resolved: string,\n subject: string,\n slice: string,\n) {\n if (existsSync(resolved) || existsSync(dirname(resolved))) return;\n\n console.warn(\n `No ${subject} were discovered: neither ${resolved} nor the directory ` +\n `above it exists, so this process cannot see the application's source. ` +\n `If this is a deploy that ships only the build output, list the classes ` +\n `explicitly in app/config/${slice}.ts so they travel with it.`,\n );\n}\n\n/**\n * The `Job` subclasses under `dir`, defaulting to the config slice's `app/jobs`.\n *\n * This is what a `queue` config slice with no `jobs` key resolves to. Call it\n * directly to ask the question a test used to answer by importing the array:\n * every job this application would register, in the order it would register\n * them.\n *\n * Every file underneath is imported, so calling this runs the app's job modules\n * — the cost `discoverClasses` documents at length, paid once per call.\n */\nexport async function discoverJobs(\n dir: string = queueConfigDefaults().jobsDir,\n): Promise<Array<new () => Job>> {\n const resolved = resolveDir(dir);\n warnIfSourceIsMissing(resolved, \"queue jobs\", \"queue\");\n const jobs = await discoverClasses(resolved, Job);\n warnIfNameWillNotSurviveTheBuild(jobs);\n return jobs;\n}\n\n/**\n * Says something about a discovered job that never declared `static name`.\n *\n * This is the one hazard discovery introduces rather than removes, and it is\n * production-only. `gemi build` minifies the server entry, and app code\n * reachable from it — a controller, and every job class that controller\n * imports to dispatch — is bundled and minified with it. Minification renames\n * the class binding, and a class's implicit `.name` is that binding: a\n * `TestJob` in the bundle reports `\"D\"`. Discovery, meanwhile, imports\n * `app/jobs/TestJob.ts` from source at runtime, where it is still `\"TestJob\"`.\n * The queue is keyed by that name, so the two halves stop agreeing and the\n * dispatch is dropped — in production, and only there.\n *\n * A declared `static name = \"TestJob\"` is a string literal, which survives\n * minification intact, and the two halves agree again. `docs/jobs-and-queues.md`\n * has always called it required; before discovery an app could get away without\n * it, because the explicit `jobs` array was bundled too and both sides were\n * wrong in the same way.\n *\n * The check is exact rather than a guess: a `static name = \"...\"` class field\n * defines a *writable* own property, while the implicit class name is\n * non-writable. Cron is unaffected — `CronJob.name` is an instance field\n * holding a string literal, not the class binding.\n */\nfunction warnIfNameWillNotSurviveTheBuild(jobs: Array<new () => Job>) {\n for (const job of jobs) {\n if (Object.getOwnPropertyDescriptor(job, \"name\")?.writable) continue;\n\n console.warn(\n `Queued job ${job.name} does not declare \\`static name\\`, so it is ` +\n `registered under its class name. A production build minifies the ` +\n `class that dispatches it and renames it, while discovery reads this ` +\n `file from source and does not — so the dispatch would be dropped in ` +\n `production and nowhere else. Add: static name = \"${job.name}\";`,\n );\n }\n}\n\n/**\n * The `CronJob` subclasses under `dir`, defaulting to the config slice's\n * `app/cron`.\n *\n * This is what a `schedule` config slice with no `jobs` key resolves to. Call it\n * directly to ask the question a test used to answer by importing the array —\n * though after boot `app(Scheduler).jobs` is the better one, because it is what\n * the scheduler actually took rather than what this would find if asked again.\n *\n * Every file underneath is imported, so calling this runs the app's cron\n * modules — the cost `discoverClasses` documents at length, paid once per call.\n */\nexport async function discoverCronJobs(\n dir: string = scheduleConfigDefaults().jobsDir,\n): Promise<Array<new () => CronJob>> {\n const resolved = resolveDir(dir);\n warnIfSourceIsMissing(resolved, \"cron jobs\", \"schedule\");\n return await discoverClasses(resolved, CronJob);\n}\n\n/**\n * The `Command` subclasses under `dir`, defaulting to the config slice's\n * `app/commands`.\n *\n * This is what a `commands`-less `command` slice resolves to, and what\n * `gemi run` lists. Unlike the two above it is not called during boot — a\n * command registry has one consumer, and importing every file under\n * `app/commands` into every server process would be a cost paid on every start\n * for code no request reaches.\n *\n * Every file underneath is imported, so calling this runs the app's command\n * modules — the cost `discoverClasses` documents at length, paid once per call.\n */\nexport async function discoverCommands(\n dir: string = commandConfigDefaults().commandsDir,\n): Promise<CommandClass[]> {\n const resolved = resolveDir(dir);\n warnIfSourceIsMissing(resolved, \"commands\", \"command\");\n\n const unfinished: string[] = [];\n\n const commands = await discoverClasses(\n resolved,\n Command,\n [],\n (value, file) => {\n if (isUnfinishedBuilder(value)) unfinished.push(file);\n },\n );\n\n refuseUnfinishedBuilders(unfinished);\n\n return commands as CommandClass[];\n}\n\n/**\n * Stops the walk for a builder chain that was never finished.\n *\n * This is the one silence the builder introduces, and it is the exact shape\n * #322 and #323 exist to remove. `defineCommand(...).arg(...)` without a\n * trailing `.handle(...)` is a plain object rather than a class, so\n * `discoverClasses` discards it along with every constant and helper a command\n * file happens to export — and the command disappears from `gemi run` with\n * nothing raised. The author sees a listing containing every command except the\n * one they just wrote.\n *\n * A throw rather than a warning, because there is no reading of an unfinished\n * builder under which the author meant it: the chain builds a description of a\n * command and then discards it.\n *\n * \"Unfinished\" is decided by `.handle()` clearing the brand, not by the export\n * still being a builder object. Those differ for the natural way to share\n * declarations —\n *\n * export const base = defineCommand(\"reindex\").option(\"verbose\", …);\n * export default base.handle(async () => {});\n *\n * — where `base` is a builder that *did* produce a command. Keying off the shape\n * alone made that file abort the whole of `gemi run`, taking every other command\n * in the project down with it, under a message that was untrue for it.\n */\nfunction refuseUnfinishedBuilders(files: string[]): void {\n if (files.length === 0) return;\n\n const subject =\n files.length === 1\n ? `${files[0]} exports a command builder that never called \\`.handle()\\``\n : `${files.length} files export a command builder that never called ` +\n `\\`.handle()\\`:\\n ${files.join(\"\\n \")}`;\n\n throw new DiscoveryError(\n `${subject}, so there is no command to run. \\`.handle()\\` is what turns ` +\n `the chain into a command — finish it:\\n\\n` +\n ` export default defineCommand(\"my-command\")\\n` +\n ` .handle(async ({ line }) => { line(\"hello\") })`,\n );\n}\n\n/**\n * The `Listener` subclasses under `dir`, defaulting to the config slice's\n * `app/listeners`.\n *\n * This is what an `events` config slice with no `listeners` key resolves to.\n * Call it directly to ask what an application would register: every listener,\n * in the order it would register them.\n *\n * Only listeners are walked. Event classes are never discovered — each is\n * imported by the listener that binds to it and by the code that dispatches it,\n * so there is nothing a walk over them would find that is not already in the\n * module graph.\n *\n * **Known residual, matching jobs and cron.** `discoverClasses` excludes the\n * `base` it is handed and not intermediates, so an abstract listener base\n * written in `listenersDir` and extended by its siblings is discovered and\n * registered alongside them — constructed, with its `handle` called, on every\n * dispatch of whatever event it declares. Keep shared bases outside the\n * directory.\n *\n * Every file underneath is imported, so calling this runs the app's listener\n * modules — the cost `discoverClasses` documents at length, paid once per call.\n *\n * @throws DiscoveryError if a discovered listener declares no `static event`.\n */\nexport async function discoverListeners(\n dir: string = eventConfigDefaults().listenersDir,\n): Promise<ListenerClass[]> {\n const resolved = resolveDir(dir);\n warnIfSourceIsMissing(resolved, \"event listeners\", \"events\");\n\n const listeners = (await discoverClasses(\n resolved,\n Listener,\n )) as ListenerClass[];\n\n refuseListenersWithNoEvent(listeners);\n warnIfListenerNameWillNotSurviveTheBuild(listeners);\n warnIfEventNameWillNotSurviveTheBuild(listeners);\n\n return listeners;\n}\n\n/**\n * Stops the walk for a listener that binds to nothing.\n *\n * `static event` is declared as required on the base and the compiler still\n * cannot see it missing: every subclass inherits the declaration whether or not\n * it assigns to one, so `typeof SomeListener` type-checks either way. What the\n * author gets instead is a file that is imported, registered under no name, and\n * never called — the silence this whole module is arranged against.\n *\n * A throw rather than a warning, because there is no reading of a listener with\n * no event under which the author meant it. The usual cause is the residual\n * above: an abstract base sharing a gate between two listeners, sitting in\n * `listenersDir` where the walk finds it. Moving it out is the fix, and the\n * message says so — the alternative, excluding it by some guess about\n * abstractness, is how a discovery pass ends up quietly covering less than the\n * directory holds.\n */\nfunction refuseListenersWithNoEvent(listeners: ListenerClass[]): void {\n const orphans = listeners.filter((listener) => !listener.event);\n if (orphans.length === 0) return;\n\n throw new DiscoveryError(\n `${orphans\n .map((listener) => listener.name)\n .join(\", \")} declare no \\`static event\\`, so there is no event name to ` +\n `register them under and their \\`handle\\` would never run. Every ` +\n `listener binds to exactly one event:\\n\\n` +\n ` static event = UserRegistered;\\n\\n` +\n `If this is an abstract base its subclasses extend, move it out of the ` +\n `listeners directory — the walk excludes gemi's \\`Listener\\` and ` +\n `nothing else, so a base sitting beside its subclasses is registered ` +\n `and run like one of them.`,\n );\n}\n\n/**\n * Says something about a discovered listener that never declared `static name`.\n *\n * The hazard is `warnIfNameWillNotSurviveTheBuild`'s, one subsystem over: a\n * `static name = \"...\"` class field defines a *writable* own property while the\n * implicit class binding does not, and a minifier renames the binding while\n * leaving the string literal alone. The two spellings are indistinguishable by\n * value — both read `\"SendWelcomeEmail\"` in development — so the descriptor is\n * the only thing that tells them apart, and the difference only becomes visible\n * in a production build.\n *\n * A warning rather than a refusal, because a *sync* listener's name has no\n * second half to disagree with: every reader of it comes from this same\n * source-side walk, so a minified build and this walk cannot produce two\n * different strings for it. A **queued** listener does have one — the name is\n * the queue's key and it crosses a JSON boundary — and that case is refused\n * outright, by `jobForListener`, at the point the listener is registered with\n * the queue rather than here. This walk cannot tell the two apart without\n * constructing every listener it found; the registry constructs them anyway.\n */\nfunction warnIfListenerNameWillNotSurviveTheBuild(listeners: ListenerClass[]) {\n for (const listener of listeners) {\n if (Object.getOwnPropertyDescriptor(listener, \"name\")?.writable) continue;\n\n console.warn(\n `Event listener ${listener.name} does not declare \\`static name\\`, so ` +\n `it is registered under its class name, which a production build ` +\n `renames. Nothing reads that name across a build boundary while the ` +\n `listener is sync, which is why this is a warning — but adding ` +\n `\\`queued = true\\` to it is refused at boot for the same reason, ` +\n `because the queue's key is that string. Add: static name = ` +\n `\"${listener.name}\";`,\n );\n }\n}\n\n/**\n * Says something about the *event* a discovered listener binds to, when that\n * event's name is the implicit class binding.\n *\n * This is the check that matters from the first dispatch, and it is the reason\n * `discoverListeners` reads `static event` at all. The registry is keyed by the\n * event's name; the dispatcher supplies that name from the class it constructs.\n * A production build minifies the server entry and the app code reachable from\n * it — the controller, and the event class it imports in order to dispatch —\n * while discovery imports `app/listeners/*.ts` from source, and those files\n * import `app/events/*.ts` from source too. Two module graphs, two class\n * objects, and an implicit `.name` that reads `\"UserRegistered\"` on one side\n * and `\"D\"` on the other. The dispatch then finds no listeners, which is legal,\n * normal, and completely silent.\n *\n * A declared `static name` is a string literal, which survives minification\n * intact, and the two halves agree again.\n *\n * Checked through the descriptor rather than the string, and not by comparing\n * `event.name` to anything: in development the two spellings produce the same\n * value, so a check on the string would be a tautology that passes forever.\n */\nfunction warnIfEventNameWillNotSurviveTheBuild(listeners: ListenerClass[]) {\n const warned = new Set<EventClass>();\n\n for (const { event } of listeners) {\n if (warned.has(event)) continue;\n if (Object.getOwnPropertyDescriptor(event, \"name\")?.writable) continue;\n warned.add(event);\n\n console.warn(\n `Event ${event.name} does not declare \\`static name\\`, so it is ` +\n `dispatched under its class name. A production build minifies the ` +\n `code that dispatches it and renames the class, while discovery reads ` +\n `the listener's copy from source and does not — so the dispatch would ` +\n `reach no listener in production and nowhere else. Add: ` +\n `static name = \"${event.name}\";`,\n );\n }\n}\n"
|
|
16
16
|
],
|
|
17
17
|
"mappings": "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",
|
|
18
|
-
"debugId": "
|
|
18
|
+
"debugId": "B91404D39945B18264756E2164756E21",
|
|
19
19
|
"names": []
|
|
20
20
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{of as P}from"./chunk-3g5bjvdf.js";import{Ff as O}from"./chunk-jhkjz9jr.js";var S={};O(S,{registeredNames:()=>_,register:()=>W,has:()=>A,get:()=>R,clearRegistry:()=>C});var F=new Map;function W(j,z){F.set(j,z)}function A(j){return F.has(j)}function R(j){let z=F.get(j);if(z===void 0)throw new P(j,[...F.keys()]);return z}function _(){return[...F.keys()]}function C(){F.clear()}import{AsyncLocalStorage as k}from"async_hooks";class V{content={title:"Gemi App",description:null,openGraph:null};touched=!1;render(){return{title:this.content.title,description:this.content.description,openGraph:this.content.openGraph}}title(j){this.touched=!0,this.content.title=j}description(j){this.touched=!0,this.content.description=j}openGraph({title:j,description:z,type:B,url:Q,image:G,imageAlt:Y,imageWidth:Z,imageHeight:$,twitterImage:D=G,twitterImageAlt:M=Y,twitterImageWidth:E=Z,twitterImageHeight:b=$}){this.touched=!0;let K=G,L=D;if(G&&!G.startsWith("http"))K=`${process.env.HOST_NAME}${G}`,L=`${process.env.HOST_NAME}${D}`;this.content.openGraph=Object.fromEntries(Object.entries({title:j,description:z,type:B,url:Q,image:K,imageAlt:Y,imageWidth:Z,imageHeight:$,twitterImage:L,twitterImageAlt:M,twitterImageWidth:E,twitterImageHeight:b}).filter(([v,H])=>H!==void 0))}}function U(j,z,B={}){return[`${j}=${z}`,B.maxAge?`Max-Age=${B.maxAge}`:"",B.httpOnly?"HttpOnly":"",B.secure?"Secure":"",B.sameSite?`SameSite=${B.sameSite}`:"SameSite=Strict",B.path?`Path=${B.path}`:"Path=/",B.domain?`Domain=${B.domain}`:"",B.expires?`Expires=${B.expires.toUTCString()}`:"",B.partitioned?"Partitioned":""].filter((Q)=>Q!=="").join("; ")}var J=new k;class T{req;cookies=new Set;headers=new Headers;serverQueries=null;user=null;csrfHmac=null;locale=null;metadata=new V;rangeRequest=null;sessionId=null;featureEvaluations=null;featureContext=null;featureBuckets=null;constructor(j){this.req=j}setLocale(j){this.locale=j}renderMeta(){return this.metadata.render()}setCSRFHmac(j){this.csrfHmac=j}setCookie(j,z,B={}){this.cookies.add(U(j,z,B))}deleteCookie(j){this.cookies.add(U(j,"",{maxAge:-1}))}setHeaders(j,z){this.headers.set(j,z)}setUser(j){this.user=j}setRequest(j){this.req=j}destroy(){delete this.cookies,delete this.headers,this.serverQueries=null,this.sessionId=null,this.featureEvaluations=null,this.featureContext=null,this.featureBuckets=null,delete this.user}}var N="session_id";function x(){let j=X.getStore();if(!j)return null;if(j.sessionId)return j.sessionId;let z=j.req?.cookies?.get(N);if(z)j.sessionId=z;return j.sessionId}function I(){let j=X.getStore();if(!j)return null;let z=x();if(z)return z;let B=Bun.randomUUIDv7();return j.sessionId=B,j.setCookie(N,B,{httpOnly:!0,secure:Bun.env.NODE_ENV==="production",sameSite:"Lax",expires:new Date(Date.now()+31536000000)}),B}class X{static getStore(){return J.getStore()}static setRequest(j){J.getStore().req=j}static run(j,z){return J.run(new T(j),z)}static runWith(j,z){return J.run(j,z)}}
|
|
3
|
+
export{x as Oe,I as Pe,X as Qe,W as Re,A as Se,R as Te,_ as Ue,S as Ve};
|
|
4
|
+
|
|
5
|
+
//# debugId=24A7B907AED3DD1264756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../orm/registry.ts", "../http/requestContext.ts", "../http/Metadata.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { ModelNotRegisteredError } from \"./errors\";\n\n/**\n * Name-keyed, resolved at call time, never at module load.\n *\n * The generated schema refers to a relation's target by model *name*, not by\n * importing the class. Without that indirection `User.ts` imports `Post.ts`\n * imports `User.ts` and, under ESM, one of them is `undefined` while the other\n * is still evaluating. It is the classic ORM bootstrap failure and it shows up\n * the moment two models reference each other — which, in any real schema, is\n * immediately.\n *\n * It also keeps the generated files free of an import graph: they hold data and\n * strings only.\n */\nconst models = new Map<string, unknown>();\n\nexport function register(name: string, model: unknown): void {\n models.set(name, model);\n}\n\nexport function has(name: string): boolean {\n return models.has(name);\n}\n\nexport function get<T = unknown>(name: string): T {\n const model = models.get(name);\n if (model === undefined) {\n throw new ModelNotRegisteredError(name, [...models.keys()]);\n }\n return model as T;\n}\n\nexport function registeredNames(): string[] {\n return [...models.keys()];\n}\n\nexport function clearRegistry(): void {\n models.clear();\n}\n",
|
|
6
|
+
"import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { HttpRequest } from \"./HttpRequest\";\nimport { Metadata } from \"./Metadata\";\nimport type { ByteRange } from \"./range\";\n// Type-only: `services/router` imports from `http`, so a runtime import here\n// would be circular.\nimport type { ServerQueryStore } from \"../services/router/ServerQueryStore\";\n\nexport interface CreateCookieOptions {\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"Strict\" | \"Lax\";\n path?: string;\n domain?: string;\n partitioned?: boolean;\n}\n\nexport function createCookie(\n name: string,\n value: string,\n options: CreateCookieOptions = {},\n) {\n return [\n `${name}=${value}`,\n options.maxAge ? `Max-Age=${options.maxAge}` : \"\",\n options.httpOnly ? \"HttpOnly\" : \"\",\n options.secure ? \"Secure\" : \"\",\n options.sameSite ? `SameSite=${options.sameSite}` : \"SameSite=Strict\",\n options.path ? `Path=${options.path}` : \"Path=/\",\n options.domain ? `Domain=${options.domain}` : \"\",\n options.expires ? `Expires=${options.expires.toUTCString()}` : \"\",\n options.partitioned ? \"Partitioned\" : \"\",\n ]\n .filter((i) => i !== \"\")\n .join(\"; \");\n}\n\nconst requestContext = new AsyncLocalStorage<Store>();\n\nclass Store {\n cookies: Set<string> = new Set();\n headers: Headers = new Headers();\n /**\n * Every server-side query of this request — prefetched or discovered during\n * the streaming render. Assigned by the view router (or lazily by the\n * `Query` facade); `null` for api requests, which must not query themselves.\n */\n serverQueries: ServerQueryStore | null = null;\n user: any = null;\n csrfHmac: string | null = null;\n locale: string | null = null;\n metadata = new Metadata();\n /**\n * The parsed `Range` of the in-flight request, picked up by\n * `FileStorage.read()` so a range reaches the storage backend without every\n * handler having to thread it through by hand.\n *\n * Only populated inside a `this.stream()` route, and cleared once that route\n * returns: a `FileStorage.read()` in an ordinary handler must never start\n * silently returning partial bytes.\n */\n rangeRequest: ByteRange | null = null;\n\n /**\n * This request's `session_id`, once read or minted.\n *\n * The cookie itself cannot answer for it. `setCookie` appends a *serialized*\n * `Set-Cookie` string to `cookies`, so a value written during this request is\n * not readable back out of it, and `req.cookies` still holds only what the\n * browser sent. Anything needing the id in the same request that mints it —\n * feature-flag bucketing, most obviously — has to read it from here.\n */\n sessionId: string | null = null;\n\n /**\n * This request's feature-flag evaluations, computed once.\n *\n * One map per request is what keeps a handler and the SSR payload from\n * disagreeing: a percentage rollout evaluated twice would be consistent\n * anyway — the bucketing is deterministic — but an attribute hook reading a\n * clock, or a `now`-based rule, would not be. Anything the page renders and\n * anything the server branched on have to be the same answer.\n */\n featureEvaluations: Map<string, unknown> | null = null;\n /** The context those evaluations were made against, built at most once. */\n featureContext: unknown = null;\n /** Bucket memo, shared across every flag evaluated for this request. */\n featureBuckets: Map<string, number> | null = null;\n\n constructor(public req: HttpRequest) {}\n\n setLocale(locale: string) {\n this.locale = locale;\n }\n\n renderMeta() {\n return this.metadata.render();\n }\n\n setCSRFHmac(hmac: string) {\n this.csrfHmac = hmac;\n }\n\n setCookie(name: string, value: string, options: CreateCookieOptions = {}) {\n this.cookies.add(createCookie(name, value, options));\n }\n\n deleteCookie(name: string) {\n this.cookies.add(createCookie(name, \"\", { maxAge: -1 }));\n }\n\n setHeaders(name: string, value: string) {\n this.headers.set(name, value);\n }\n\n setUser(user: any) {\n this.user = user;\n }\n\n setRequest(req: HttpRequest<any, any>) {\n this.req = req;\n }\n\n destroy() {\n delete this.cookies;\n delete this.headers;\n this.serverQueries = null;\n this.sessionId = null;\n this.featureEvaluations = null;\n this.featureContext = null;\n this.featureBuckets = null;\n delete this.user;\n }\n}\n\nexport const SESSION_ID_COOKIE = \"session_id\";\n\n/**\n * The `session_id` the browser sent, or the one minted earlier in this request.\n * Never mints one, so it is safe on an api request, where a `Set-Cookie` nobody\n * asked for would be a surprise.\n *\n * `null` outside a request, and for an anonymous visitor whose first request is\n * not a view — both meaning \"no stable subject\", which callers must handle\n * rather than paper over with a random value. A per-call random id would give\n * every request its own bucket, which is worse than no bucketing at all: a\n * percentage rollout would reshuffle on every page load.\n *\n * ## It is client-supplied, and unauthenticated\n *\n * Whatever the browser sent, unvalidated. It is a bucketing subject, not a\n * credential — never authenticate or authorize on it. A visitor can pick a value\n * that lands them in any percentage rollout, and signing it would not change\n * that: they can discard the cookie and collect fresh ones until one does. Load\n * bearing enough to state, because `.feature()` route gating is built on top of\n * evaluation — see its documentation for what may safely gate a route.\n */\nexport function sessionId(): string | null {\n const store = RequestContext.getStore();\n if (!store) {\n return null;\n }\n if (store.sessionId) {\n return store.sessionId;\n }\n const sent = store.req?.cookies?.get(SESSION_ID_COOKIE);\n if (sent) {\n store.sessionId = sent;\n }\n return store.sessionId;\n}\n\n/**\n * The same, but mints and sets the cookie when the browser sent none.\n *\n * Call this once per **view** request, early enough that everything downstream —\n * flag evaluation included — sees the same id the browser is about to be given.\n * It used to live inline in `ViewRouteDispatcher.onRequestEnd`, which ran only\n * on the document path and only after the response was decided, so a client-side\n * navigation minted nothing and a first-ever visitor had no id at the point\n * flags were evaluated.\n */\nexport function ensureSessionId(): string | null {\n const store = RequestContext.getStore();\n if (!store) {\n return null;\n }\n const existing = sessionId();\n if (existing) {\n return existing;\n }\n\n const minted = Bun.randomUUIDv7();\n store.sessionId = minted;\n store.setCookie(SESSION_ID_COOKIE, minted, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n // `Lax`, not `Strict`, and the difference is load-bearing. `Strict`\n // withholds the cookie on cross-site *top-level navigation*, so a visitor\n // arriving from a search result or a shared link would arrive without it,\n // be minted a new id, and overwrite the old one — re-bucketing on every\n // external entry, which is how most anonymous traffic arrives. This is not\n // a credential (`access_token` stays `Strict`); it is an opaque bucketing\n // id, and `Lax` still blocks cross-site POST.\n sameSite: \"Lax\",\n expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),\n });\n return minted;\n}\n\nexport class RequestContext {\n static getStore() {\n return requestContext.getStore()!;\n }\n\n static setRequest(req: HttpRequest<any, any>) {\n requestContext.getStore().req = req;\n }\n\n static run<T>(httpRequest: HttpRequest, fn: () => T): T {\n return requestContext.run(new Store(httpRequest), fn);\n }\n\n /**\n * Re-enters an *existing* request scope. Stream lifecycle callbacks fire\n * after the HTTP server has taken over the response body — outside the\n * AsyncLocalStorage scope the request ran in — so the view router captures\n * the live store and re-enters it around user-facing hooks, keeping\n * `req.ctx()` (and everything context-backed) working inside them.\n */\n static runWith<T>(store: Store, fn: () => T): T {\n return requestContext.run(store, fn);\n }\n}\n",
|
|
7
|
+
"export type OpenGraphParams = {\n title: string;\n description?: string;\n type: string;\n url: string;\n image: string;\n imageAlt?: string;\n imageWidth?: number;\n imageHeight?: number;\n twitterImage?: string;\n twitterImageAlt?: string;\n twitterImageWidth?: number;\n twitterImageHeight?: number;\n};\nexport class Metadata {\n content: any = {\n title: \"Gemi App\",\n description: null,\n openGraph: null,\n };\n\n /**\n * Whether a handler set anything, as opposed to `content` still being the\n * defaults. A partially rendered response that touched no metadata sends\n * none, so the client keeps what the skipped segments put there.\n */\n touched = false;\n\n render() {\n return {\n title: this.content.title,\n description: this.content.description,\n openGraph: this.content.openGraph,\n };\n }\n\n title(title: string) {\n this.touched = true;\n this.content.title = title;\n }\n\n description(description: string) {\n this.touched = true;\n this.content.description = description;\n }\n\n openGraph({\n title,\n description,\n type,\n url,\n image,\n imageAlt,\n imageWidth,\n imageHeight,\n twitterImage = image,\n twitterImageAlt = imageAlt,\n twitterImageWidth = imageWidth,\n twitterImageHeight = imageHeight,\n }: OpenGraphParams) {\n this.touched = true;\n let _image = image;\n let _twitterImage = twitterImage;\n if (image && !image.startsWith(\"http\")) {\n _image = `${process.env.HOST_NAME}${image}`;\n _twitterImage = `${process.env.HOST_NAME}${twitterImage}`;\n }\n this.content.openGraph = Object.fromEntries(\n Object.entries({\n title,\n description,\n type,\n url,\n image: _image,\n imageAlt,\n imageWidth,\n imageHeight,\n twitterImage: _twitterImage,\n twitterImageAlt,\n twitterImageWidth,\n twitterImageHeight,\n }).filter(([_, value]) => value !== undefined),\n );\n }\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "24A7B907AED3DD1264756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|