refactor: mixin

This commit is contained in:
cha0s 2024-01-05 15:52:29 -06:00
parent 37d9a22479
commit c8a6f68628
28 changed files with 164 additions and 91 deletions

View File

@ -29,7 +29,6 @@
- [ ] redux store provider fails if not in request - [ ] redux store provider fails if not in request
- [ ] add building to publish process ... - [ ] add building to publish process ...
- [ ] @babel/register@7.18.x has a bug - [ ] @babel/register@7.18.x has a bug
- [ ] `$flecks/db/sequelize` should be `$flecks/db.sequelize`
- [x] `url()` in styles breaks HMR - [x] `url()` in styles breaks HMR
- [x] 2 underscores for `FLECKS_ENV` variables - [x] 2 underscores for `FLECKS_ENV` variables
- [x] flecks add - [x] flecks add

View File

@ -128,8 +128,8 @@ export default class ServerFlecks extends Flecks {
const entries = Object.keys(resolver).map((path) => [path, R(this.resolve(resolver, path))]); const entries = Object.keys(resolver).map((path) => [path, R(this.resolve(resolver, path))]);
// Flecks mixins. // Flecks mixins.
const mixins = entries.map(([, M]) => M.hooks?.['@flecks/core.mixin']).filter((e) => e); const mixins = entries.map(([, M]) => M.hooks?.['@flecks/core.mixin']).filter((e) => e);
const Class = compose(...mixins)(ServerFlecks); const MixedServerFlecks = compose(...mixins)(ServerFlecks);
return new Class({ return new MixedServerFlecks({
config, config,
flecks: Object.fromEntries(entries), flecks: Object.fromEntries(entries),
platforms, platforms,

View File

@ -50,7 +50,7 @@ export async function createDatabaseConnection(flecks) {
}); });
} }
} }
const Models = flecks.get('$flecks/db.models')[ByType]; const Models = flecks.db.Models[ByType];
await register(Models, sequelize); await register(Models, sequelize);
debug('synchronizing...'); debug('synchronizing...');
await sequelize.sync(); await sequelize.sync();

View File

@ -44,21 +44,32 @@ export const hooks = {
}), }),
'@flecks/core.hmr.gathered': (gathered, hook, flecks) => { '@flecks/core.hmr.gathered': (gathered, hook, flecks) => {
if ('@flecks/db/server.models' === hook) { if ('@flecks/db/server.models' === hook) {
register(gathered, flecks.get('$flecks/db/sequelize')); register(gathered, flecks.db.sequelize);
} }
}, },
'@flecks/core.mixin': (Flecks) => (
class FlecksWithDb extends Flecks {
db = {
Models: {},
$$sequelize: undefined,
get sequelize() {
return this.$$sequelize;
},
set sequelize(sequelize) {
this.$$sequelize = sequelize;
this.transaction = sequelize.transaction.bind(sequelize);
},
transaction: () => {},
}
}
),
'@flecks/core.starting': (flecks) => { '@flecks/core.starting': (flecks) => {
flecks.set('$flecks/db.models', flecks.gather( flecks.db.Models = flecks.gather('@flecks/db/server.models', {typeProperty: 'name'});
'@flecks/db/server.models',
{typeProperty: 'name'},
));
}, },
'@flecks/docker.containers': containers, '@flecks/docker.containers': containers,
'@flecks/server.up': async (flecks) => { '@flecks/server.up': async (flecks) => {
flecks.set('$flecks/db/sequelize', await createDatabaseConnection(flecks)); flecks.db.sequelize = await createDatabaseConnection(flecks);
}, },
'@flecks/repl.context': (flecks) => ({
Models: flecks.get('$flecks/db.models'),
sequelize: flecks.get('$flecks/db/sequelize'),
}),
}; };

View File

@ -2,6 +2,8 @@ import {join} from 'path';
import {banner} from '@flecks/core/server'; import {banner} from '@flecks/core/server';
const electron = __non_webpack_require__('electron');
const { const {
NODE_ENV, NODE_ENV,
} = process.env; } = process.env;
@ -9,7 +11,7 @@ const {
let win; let win;
async function createWindow(flecks) { async function createWindow(flecks) {
const {BrowserWindow} = flecks.get('$flecks/electron'); const {BrowserWindow} = flecks.electron;
const {browserWindowOptions} = flecks.get('@flecks/electron/server'); const {browserWindowOptions} = flecks.get('@flecks/electron/server');
win = new BrowserWindow(browserWindowOptions); win = new BrowserWindow(browserWindowOptions);
await flecks.invokeSequentialAsync('@flecks/electron/server.window', win); await flecks.invokeSequentialAsync('@flecks/electron/server.window', win);
@ -69,6 +71,13 @@ export const hooks = {
} }
} }
}, },
'@flecks/core.mixin': (Flecks) => (
class FlecksWithElectron extends Flecks {
electron = electron.app ? electron : undefined;
}
),
'@flecks/electron/server.initialize': async (electron, flecks) => { '@flecks/electron/server.initialize': async (electron, flecks) => {
electron.app.on('window-all-closed', () => { electron.app.on('window-all-closed', () => {
const {quitOnClosed} = flecks.get('@flecks/electron/server'); const {quitOnClosed} = flecks.get('@flecks/electron/server');
@ -121,14 +130,6 @@ export const hooks = {
}, },
}), }),
'@flecks/server.up': async (flecks) => { '@flecks/server.up': async (flecks) => {
// Local require because electron is kinda skittish. await flecks.invokeSequentialAsync('@flecks/electron/server.initialize', flecks.electron);
// eslint-disable-next-line global-require
const electron = require('electron');
// `electron.app` will be undefined if we aren't running in an electron environment. Just bail.
if (!electron.app) {
return;
}
flecks.set('$flecks/electron', electron);
await flecks.invokeSequentialAsync('@flecks/electron/server.initialize', electron);
}, },
}; };

View File

@ -4,8 +4,7 @@ export default (flecks, [name, Packet]) => {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
const {[name]: limiter} = flecks.get('$flecks/governor.packet.limiters'); this.limit = flecks.governor.packet[name];
this.limit = limiter;
} }
static async validate(packet, socket) { static async validate(packet, socket) {

View File

@ -24,12 +24,18 @@ export const hooks = {
ttl: 30, ttl: 30,
}, },
}), }),
'@flecks/core.mixin': (Flecks) => (
class FlecksWithGovernor extends Flecks {
governor = {}
}
),
'@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)), '@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
'@flecks/web/server.request.route': (flecks) => { '@flecks/web/server.request.route': (flecks) => {
const {web} = flecks.get('@flecks/governor/server'); const {web} = flecks.get('@flecks/governor/server');
const limiter = flecks.get('$flecks/governor.web.limiter');
return async (req, res, next) => { return async (req, res, next) => {
const {Ban} = flecks.get('$flecks/db.models'); const {Ban} = flecks.db.Models;
try { try {
await Ban.check(req); await Ban.check(req);
} }
@ -43,7 +49,7 @@ export const hooks = {
res.status(403).send(`<pre>${Ban.format([ban])}</pre>`); res.status(403).send(`<pre>${Ban.format([ban])}</pre>`);
}; };
try { try {
await limiter.consume(req.ip); await flecks.governor.web.consume(req.ip);
next(); next();
} }
catch (error) { catch (error) {
@ -57,20 +63,18 @@ export const hooks = {
'@flecks/server.up': async (flecks) => { '@flecks/server.up': async (flecks) => {
if (flecks.fleck('@flecks/web/server')) { if (flecks.fleck('@flecks/web/server')) {
const {web} = flecks.get('@flecks/governor/server'); const {web} = flecks.get('@flecks/governor/server');
const limiter = await createLimiter( flecks.governor.web = await createLimiter(
flecks, flecks,
{ {
keyPrefix: '@flecks/governor.web.request.route', keyPrefix: '@flecks/governor.web.request.route',
...web, ...web,
}, },
); );
flecks.set('$flecks/governor.web.limiter', limiter);
} }
if (flecks.fleck('@flecks/socket/server')) { if (flecks.fleck('@flecks/socket/server')) {
const {[ByType]: Packets} = flecks.get('$flecks/socket.packets'); flecks.governor.packet = Object.fromEntries(
const limiters = Object.fromEntries(
await Promise.all( await Promise.all(
Object.entries(Packets) Object.entries(flecks.socket.Packets[ByType])
.filter(([, Packet]) => Packet.limit) .filter(([, Packet]) => Packet.limit)
.map(async ([name, Packet]) => ( .map(async ([name, Packet]) => (
[ [
@ -83,23 +87,20 @@ export const hooks = {
)), )),
), ),
); );
flecks.set('$flecks/governor.packet.limiters', limiters);
const {socket} = flecks.get('@flecks/governor/server'); const {socket} = flecks.get('@flecks/governor/server');
const limiter = await createLimiter( flecks.governor.socket = await createLimiter(
flecks, flecks,
{ {
keyPrefix: '@flecks/governor.socket.request.socket', keyPrefix: '@flecks/governor.socket.request.socket',
...socket, ...socket,
}, },
); );
flecks.set('$flecks/governor.socket.limiter', limiter);
} }
}, },
'@flecks/socket/server.request.socket': (flecks) => { '@flecks/socket/server.request.socket': (flecks) => (
const limiter = flecks.get('$flecks/governor.socket.limiter'); async (socket, next) => {
return async (socket, next) => {
const {handshake: req} = socket; const {handshake: req} = socket;
const {Ban} = flecks.get('$flecks/db.models'); const {Ban} = flecks.db.Models;
try { try {
await Ban.check(req); await Ban.check(req);
} }
@ -112,7 +113,7 @@ export const hooks = {
socket.disconnect(); socket.disconnect();
}; };
try { try {
await limiter.consume(req.ip); await flecks.governor.socket.consume(req.ip);
next(); next();
} }
catch (error) { catch (error) {
@ -120,8 +121,8 @@ export const hooks = {
await Ban.create(Ban.fromRequest(req, keys, ttl)); await Ban.create(Ban.fromRequest(req, keys, ttl));
next(error); next(error);
} }
}; }
}, ),
'@flecks/socket.packets.decorate': (Packets, flecks) => ( '@flecks/socket.packets.decorate': (Packets, flecks) => (
Object.fromEntries( Object.fromEntries(
Object.entries(Packets).map(([keyPrefix, Packet]) => [ Object.entries(Packets).map(([keyPrefix, Packet]) => [

View File

@ -6,7 +6,7 @@ import {HistoryRouter as ReduxHistoryRouter} from 'redux-first-history/rr6';
export const hooks = { export const hooks = {
'@flecks/react.providers': (req, flecks) => ( '@flecks/react.providers': (req, flecks) => (
flecks.fleck('@flecks/redux') flecks.fleck('@flecks/redux')
? [ReduxHistoryRouter, {history: createReduxHistory(flecks.get('$flecks/redux.store'))}] ? [ReduxHistoryRouter, {history: createReduxHistory(flecks.redux)}]
: [HistoryRouter, {history}] : [HistoryRouter, {history}]
), ),
}; };

View File

@ -5,13 +5,20 @@ import configureStore, {createReducer} from '../store';
import localStorageEnhancer from './local-storage'; import localStorageEnhancer from './local-storage';
export const hooks = { export const hooks = {
'@flecks/core.mixin': (Flecks) => (
class FlecksWithRedux extends Flecks {
redux;
}
),
'@flecks/react.providers': async (req, flecks) => { '@flecks/react.providers': async (req, flecks) => {
const slices = await flecks.invokeMergeUnique('@flecks/redux.slices'); const slices = await flecks.invokeMergeUnique('@flecks/redux.slices');
const reducer = createReducer(flecks, slices); const reducer = createReducer(flecks, slices);
// Hydrate from server. // Hydrate from server.
const {preloadedState} = flecks.get('@flecks/redux/client'); const {preloadedState} = flecks.get('@flecks/redux/client');
const store = await configureStore(flecks, reducer, {preloadedState}); const store = await configureStore(flecks, reducer, {preloadedState});
flecks.set('$flecks/redux.store', store); flecks.redux = store;
return [Provider, {store}]; return [Provider, {store}];
}, },
'@flecks/redux.store': ({enhancers}) => { '@flecks/redux.store': ({enhancers}) => {

View File

@ -1,7 +1,7 @@
export default (Action, flecks) => class ActionClient extends Action { export default (Action, flecks) => class ActionClient extends Action {
static async respond(packet) { static async respond(packet) {
flecks.get('$flecks/redux.store').dispatch(packet.data); flecks.redux.dispatch(packet.data);
} }
}; };

View File

@ -61,7 +61,7 @@ export async function createReplServer(flecks) {
} }
} }
const socket = join(tmpdir(), 'flecks', id, 'repl', `${id}-${Date.now()}.sock`); const socket = join(tmpdir(), 'flecks', id, 'repl', `${id}-${Date.now()}.sock`);
flecks.set('$flecks/repl.socket', socket); flecks.repl = socket;
await new Promise((resolve) => { await new Promise((resolve) => {
netServer.listen(socket, resolve); netServer.listen(socket, resolve);
}); });

View File

@ -3,5 +3,12 @@ import {createReplServer} from './repl';
export const hooks = { export const hooks = {
'@flecks/core.commands': commands, '@flecks/core.commands': commands,
'@flecks/core.mixin': (Flecks) => (
class FlecksWithRepl extends Flecks {
repl;
}
),
'@flecks/server.up': (flecks) => createReplServer(flecks), '@flecks/server.up': (flecks) => createReplServer(flecks),
}; };

View File

@ -2,8 +2,8 @@ import {mkdir} from 'fs/promises';
import {tmpdir} from 'os'; import {tmpdir} from 'os';
import {join} from 'path'; import {join} from 'path';
import {D} from '@flecks/core'; import {compose, D} from '@flecks/core';
import {Flecks} from '@flecks/core/server'; import {Flecks as BaseFlecks} from '@flecks/core/server';
const {version} = require('../package.json'); const {version} = require('../package.json');
@ -22,12 +22,18 @@ const {version} = require('../package.json');
const debug = D('@flecks/server/entry'); const debug = D('@flecks/server/entry');
debug('starting server...'); debug('starting server...');
// Make resolver. // Make resolver.
// Flecks mixins.
const flecks = await loadFlecks();
const mixins = Object.entries(flecks)
.map(([, M]) => M.hooks?.['@flecks/core.mixin'])
.filter((e) => e);
const Flecks = compose(...mixins)(BaseFlecks);
const resolver = Flecks.makeResolver(config); const resolver = Flecks.makeResolver(config);
const rcs = Flecks.loadRcs(resolver); const rcs = Flecks.loadRcs(resolver);
Flecks.installCompilers(rcs, resolver); Flecks.installCompilers(rcs, resolver);
global.flecks = new Flecks({ global.flecks = new Flecks({
config, config,
flecks: await loadFlecks(), flecks,
platforms, platforms,
resolver, resolver,
rcs, rcs,

View File

@ -1,9 +1,22 @@
import SocketClient from './socket'; import SocketClient from './socket';
export const hooks = { export const hooks = {
'@flecks/core.mixin': (Flecks) => (
class FlecksWithSocket extends Flecks {
constructor(...args) {
super(...args);
if (!this.socket) {
this.socket = {};
}
this.socket.client = undefined;
}
}
),
'@flecks/web/client.up': (flecks) => { '@flecks/web/client.up': (flecks) => {
const socket = new SocketClient(flecks); const socket = new SocketClient(flecks);
flecks.set('$flecks/socket.socket', socket); flecks.socket.client = socket;
socket.connect(); socket.connect();
socket.listen(); socket.listen();
}, },

View File

@ -2,6 +2,5 @@ import {useFlecks} from '@flecks/react';
export default function useSocket() { export default function useSocket() {
const flecks = useFlecks(); const flecks = useFlecks();
const sock = flecks.get('$flecks/socket.socket'); return flecks.socket.client;
return sock;
} }

View File

@ -8,11 +8,21 @@ export * from './hooks';
export {Packet, Packer, ValidationError} from './packet'; export {Packet, Packer, ValidationError} from './packet';
export const hooks = { export const hooks = {
'@flecks/core.mixin': (Flecks) => (
class FlecksWithSocket extends Flecks {
constructor(...args) {
super(...args);
if (!this.socket) {
this.socket = {};
}
this.socket.Packets = {};
}
}
),
'@flecks/core.starting': (flecks) => { '@flecks/core.starting': (flecks) => {
flecks.set('$flecks/socket.packets', flecks.gather( flecks.socket.Packets = flecks.gather('@flecks/socket.packets', {check: badPacketsCheck});
'@flecks/socket.packets',
{check: badPacketsCheck},
));
}, },
'@flecks/web.config': async ( '@flecks/web.config': async (
req, req,

View File

@ -1,5 +1,5 @@
const hydrate = (flecks, [type, data]) => { const hydrate = (flecks, [type, data]) => {
const {[type]: Packet} = flecks.get('$flecks/socket.packets'); const {[type]: Packet} = flecks.socket.Packets;
if (!Packet) { if (!Packet) {
throw new TypeError(`No packet of type '${type}'`); throw new TypeError(`No packet of type '${type}'`);
} }

View File

@ -68,7 +68,7 @@ export default (flecks) => class BundlePacket extends PacketClass {
packedPacket.writeUInt8(buffer.readUInt8(caret++), i++); packedPacket.writeUInt8(buffer.readUInt8(caret++), i++);
} }
// Lookup packet. // Lookup packet.
const {[packetId]: Packet} = flecks.get('$flecks/socket.packets'); const {[packetId]: Packet} = flecks.socket.Packets;
res.push(new Packet(Packet.decode(packedPacket))); res.push(new Packet(Packet.decode(packedPacket)));
} }
return res; return res;

View File

@ -1,25 +1,30 @@
import createIntercom from './create-intercom'; import createIntercom from './create-intercom';
import SocketServer from './server'; import SocketServer from './server';
const flecksServers = new WeakMap();
export const server = (flecks) => flecksServers.get(flecks);
export const hooks = { export const hooks = {
'@flecks/web/server.request.socket': (flecks) => (req, res, next) => { '@flecks/web/server.request.socket': (flecks) => (req, res, next) => {
req.intercom = createIntercom(server(flecks), 'web'); req.intercom = createIntercom(flecks.socket.server, 'web');
next(); next();
}, },
'@flecks/web/server.up': async (httpServer, flecks) => { '@flecks/web/server.up': async (httpServer, flecks) => {
const server = new SocketServer(httpServer, flecks); const server = new SocketServer(httpServer, flecks);
flecksServers.set(flecks, server); flecks.socket.server = server;
await server.connect(); await server.connect();
}, },
'@flecks/repl.context': (flecks) => ({
Packets: flecks.get('$flecks/socket.packets'),
socketServer: server(flecks),
}),
'@flecks/socket.server': ({config: {'@flecks/core': {id}}}) => ({ '@flecks/socket.server': ({config: {'@flecks/core': {id}}}) => ({
path: `/${id}/socket.io`, path: `/${id}/socket.io`,
}), }),
'@flecks/core.mixin': (Flecks) => (
class FlecksWithSocketServer extends Flecks {
constructor(...args) {
super(...args);
if (!this.socket) {
this.socket = {};
}
this.socket.server = undefined;
}
}
),
}; };

View File

@ -35,7 +35,6 @@ export default class SocketServer {
...await this.flecks.invokeMergeAsync('@flecks/socket.server'), ...await this.flecks.invokeMergeAsync('@flecks/socket.server'),
serveClient: false, serveClient: false,
}); });
this.flecks.set('$flecks/socket.io', this.io);
this.io.use(this.makeSocketMiddleware()); this.io.use(this.makeSocketMiddleware());
this.io.on('@flecks/socket.intercom', this.localIntercom); this.io.on('@flecks/socket.intercom', this.localIntercom);
this.flecks.invoke('@flecks/socket.server.io', this); this.flecks.invoke('@flecks/socket.server.io', this);

View File

@ -12,7 +12,7 @@ export default class Socket {
} }
listen() { listen() {
const {[ByType]: PacketsByType} = this.flecks.get('$flecks/socket.packets'); const {[ByType]: PacketsByType} = this.flecks.socket.Packets;
const Packets = Object.entries(PacketsByType); const Packets = Object.entries(PacketsByType);
for (let i = 0; i < Packets.length; i++) { for (let i = 0; i < Packets.length; i++) {
const [type, Packet] = Packets[i]; const [type, Packet] = Packets[i];

View File

@ -29,7 +29,7 @@ export const hooks = {
]; ];
}, },
'@flecks/repl.commands': (flecks) => { '@flecks/repl.commands': (flecks) => {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.db.Models;
return { return {
createUser: async (spec) => { createUser: async (spec) => {
const [email, maybePassword] = spec.split(' ', 2); const [email, maybePassword] = spec.split(' ', 2);
@ -54,7 +54,7 @@ export const hooks = {
passport.use(new LocalStrategy( passport.use(new LocalStrategy(
{usernameField: 'email'}, {usernameField: 'email'},
async (email, password, fn) => { async (email, password, fn) => {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.db.Models;
try { try {
const user = await User.findOne({where: {email}}); const user = await User.findOne({where: {email}});
fn(undefined, user && await user.validatePassword(password) && user); fn(undefined, user && await user.validatePassword(password) && user);

View File

@ -13,7 +13,7 @@ export const hooks = {
debugSilly('@flecks/web/server.request.route: passport.session()'); debugSilly('@flecks/web/server.request.route: passport.session()');
passport.session()(req, res, () => { passport.session()(req, res, () => {
if (!req.user) { if (!req.user) {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.db.Models;
req.user = new User(); req.user = new User();
req.user.id = 0; req.user.id = 0;
} }
@ -34,7 +34,7 @@ export const hooks = {
'@flecks/server.up': (flecks) => { '@flecks/server.up': (flecks) => {
passport.serializeUser((user, fn) => fn(null, user.id)); passport.serializeUser((user, fn) => fn(null, user.id));
passport.deserializeUser(async (id, fn) => { passport.deserializeUser(async (id, fn) => {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.db.Models;
try { try {
fn(undefined, await User.findByPk(id)); fn(undefined, await User.findByPk(id));
} }
@ -63,7 +63,7 @@ export const hooks = {
debugSilly('@flecks/socket/server.request.socket: passport.session()'); debugSilly('@flecks/socket/server.request.socket: passport.session()');
passport.session()(socket.handshake, undefined, async () => { passport.session()(socket.handshake, undefined, async () => {
if (!socket.handshake.user) { if (!socket.handshake.user) {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.db.Models;
socket.handshake.user = new User(); socket.handshake.user = new User();
socket.handshake.user.id = 0; socket.handshake.user.id = 0;
} }

View File

@ -1,6 +1,6 @@
import {D} from '@flecks/core'; import {D} from '@flecks/core';
import express from 'express'; import express from 'express';
import expressSession from 'express-session'; import user.session from 'express-session';
const debug = D('@flecks/user/session'); const debug = D('@flecks/user/session');
const debugSilly = debug.extend('silly'); const debugSilly = debug.extend('silly');
@ -16,6 +16,15 @@ export const hooks = {
'Set the FLECKS_ENV__flecks_user_session_server__cookieSecret environment variable!' 'Set the FLECKS_ENV__flecks_user_session_server__cookieSecret environment variable!'
), ),
}), }),
'@flecks/core.mixin': (Flecks) => (
class FlecksWithUser extends Flecks {
user = {
session: undefined,
}
}
),
'@flecks/web/server.request.route': (flecks) => { '@flecks/web/server.request.route': (flecks) => {
const urle = express.urlencoded({extended: true}); const urle = express.urlencoded({extended: true});
return (req, res, next) => { return (req, res, next) => {
@ -26,7 +35,7 @@ export const hooks = {
return; return;
} }
debugSilly('@flecks/web/server.request.route: session()'); debugSilly('@flecks/web/server.request.route: session()');
flecks.get('$flecks/user.session')(req, res, (error) => { flecks.user.session(req, res, (error) => {
if (error) { if (error) {
next(error); next(error);
return; return;
@ -38,17 +47,17 @@ export const hooks = {
}; };
}, },
'@flecks/server.up': async (flecks) => { '@flecks/server.up': async (flecks) => {
flecks.set('$flecks/user.session', expressSession({ flecks.user.session = user.session({
resave: false, resave: false,
sameSite: true, sameSite: true,
saveUninitialized: false, saveUninitialized: false,
secret: flecks.get('@flecks/user/session/server.cookieSecret'), secret: flecks.get('@flecks/user/session/server.cookieSecret'),
...await flecks.invokeMergeAsync('@flecks/user.session'), ...await flecks.invokeMergeAsync('@flecks/user.session'),
})); });
}, },
'@flecks/socket/server.request.socket': (flecks) => (socket, next) => { '@flecks/socket/server.request.socket': (flecks) => (socket, next) => {
debugSilly('@flecks/socket/server.request.socket: session()'); debugSilly('@flecks/socket/server.request.socket: session()');
flecks.get('$flecks/user.session')(socket.handshake, {}, () => { flecks.user.session(socket.handshake, {}, () => {
const id = socket.handshake.session?.id; const id = socket.handshake.session?.id;
socket.join(id); socket.join(id);
next(); next();

View File

@ -1,4 +1,4 @@
import {compose, D, Flecks} from '@flecks/core'; import {compose, D, Flecks as BaseFlecks} from '@flecks/core';
// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved // eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
const {version} = require('@flecks/web/package.json'); const {version} = require('@flecks/web/package.json');
@ -56,8 +56,8 @@ const {version} = require('@flecks/web/package.json');
const mixins = Object.entries(runtime.flecks) const mixins = Object.entries(runtime.flecks)
.map(([, M]) => M.hooks?.['@flecks/core.mixin']) .map(([, M]) => M.hooks?.['@flecks/core.mixin'])
.filter((e) => e); .filter((e) => e);
const Class = compose(...mixins)(Flecks); const Flecks = compose(...mixins)(BaseFlecks);
const flecks = new Class(runtime); const flecks = new Flecks(runtime);
window.flecks = flecks; window.flecks = flecks;
try { try {
await Promise.all(flecks.invokeFlat('@flecks/core.starting')); await Promise.all(flecks.invokeFlat('@flecks/core.starting'));

View File

@ -2,7 +2,7 @@ import {Transform} from 'stream';
const config = async (flecks, req) => { const config = async (flecks, req) => {
const httpConfig = await flecks.invokeMergeAsync('@flecks/web.config', req); const httpConfig = await flecks.invokeMergeAsync('@flecks/web.config', req);
const {config} = flecks.get('$flecks/web.flecks'); const {config} = flecks.web.flecks;
const reducedConfig = Object.keys(config) const reducedConfig = Object.keys(config)
.filter((path) => !path.startsWith('$')) .filter((path) => !path.startsWith('$'))
.filter((path) => !path.endsWith('/server')) .filter((path) => !path.endsWith('/server'))

View File

@ -32,7 +32,7 @@ export const createHttpServer = async (flecks) => {
app.set('trust proxy', trust); app.set('trust proxy', trust);
const httpServer = createServer(app); const httpServer = createServer(app);
httpServer.app = app; httpServer.app = app;
flecks.set('$flecks/web/server.instance', httpServer); flecks.web.server = httpServer;
// Compression. heheh // Compression. heheh
app.use(compression({level: 'production' === NODE_ENV ? 6 : 9})); app.use(compression({level: 'production' === NODE_ENV ? 6 : 9}));
// Socket connection. // Socket connection.

View File

@ -183,6 +183,16 @@ export const hooks = {
*/ */
trust: false, trust: false,
}), }),
'@flecks/core.mixin': (Flecks) => (
class FlecksWithWeb extends Flecks {
web = {
flecks: undefined,
server: undefined,
}
}
),
'@flecks/core.starting': (flecks) => { '@flecks/core.starting': (flecks) => {
debug('bootstrapping flecks...'); debug('bootstrapping flecks...');
const webFlecks = Flecks.bootstrap({ const webFlecks = Flecks.bootstrap({
@ -190,7 +200,7 @@ export const hooks = {
platforms: ['client', '!server'], platforms: ['client', '!server'],
}); });
debug('bootstrapped'); debug('bootstrapped');
flecks.set('$flecks/web.flecks', webFlecks); flecks.web.flecks = webFlecks;
}, },
'@flecks/core.targets': (flecks) => [ '@flecks/core.targets': (flecks) => [
'web', 'web',
@ -208,7 +218,4 @@ export const hooks = {
], ],
'@flecks/web/server.stream.html': inlineConfig, '@flecks/web/server.stream.html': inlineConfig,
'@flecks/server.up': (flecks) => createHttpServer(flecks), '@flecks/server.up': (flecks) => createHttpServer(flecks),
'@flecks/repl.context': (flecks) => ({
httpServer: flecks.get('$flecks/web/server.instance'),
}),
}; };