refactor: the great hook renaming

This commit is contained in:
cha0s 2022-03-08 16:03:06 -06:00
parent 218145bcc9
commit 8667d32c14
74 changed files with 535 additions and 228 deletions

View File

@ -137,7 +137,7 @@ import {Hooks} from '@flecks/core';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/starting': () => { '@flecks/core.starting': () => {
console.log('hello, gorgeous'); console.log('hello, gorgeous');
}, },
}, },
@ -149,14 +149,14 @@ you the way you deserve to be treated.
Just to give you an idea of the power of hooks, some will be listed here: Just to give you an idea of the power of hooks, some will be listed here:
- `@flecks/core/config`: - `@flecks/core.config`:
> Define default configuration. > Define default configuration.
- `@flecks/docker/containers`: - `@flecks/docker.containers`:
> Define [Docker](https://www.docker.com/) containers to run alongside your application to > Define [Docker](https://www.docker.com/) containers to run alongside your application to
develop e.g. DB models, redis commands, etc. without having to worry about installing stuff. develop e.g. DB models, redis commands, etc. without having to worry about installing stuff.
- `@flecks/http/server/request.route`: - `@flecks/http/server.request.route`:
> Define [Express](http://expressjs.com/) middleware that runs when an HTTP route is hit. > Define [Express](http://expressjs.com/) middleware that runs when an HTTP route is hit.
- `@flecks/server/up`: - `@flecks/server.up`:
> Do things when server comes up (e.g. DB connection, HTTP listener, make you coffee, etc). > Do things when server comes up (e.g. DB connection, HTTP listener, make you coffee, etc).
...and so many more. ...and so many more.

View File

@ -22,4 +22,4 @@
- [ ] autogenerated config dox page - [ ] autogenerated config dox page
- [x] remove `invokeParallel()` - [x] remove `invokeParallel()`
- [x] Specialize `invokeReduce()` with `invokeMerge()`. - [x] Specialize `invokeReduce()` with `invokeMerge()`.
- [ ] Rename all hooks to dot-first notation; rewrite `lookupFlecks()`. - [x] Rename all hooks to dot-first notation; rewrite `lookupFlecks()`.

View File

@ -0,0 +1,325 @@
# Hooks
Hooks are how everything happens in flecks. There are many hooks and the hooks provided by flecks are documented at the [hooks reference page](ADDME).
To define hooks (and turn your plain ol' boring JS modules into beautiful interesting flecks), you only have to import the `Hooks` symbol and key your default export:
```javascript
import {Hooks} from '@flecks/core';
export default {
[Hooks]: {
'@flecks/core.starting': () => {
console.log('hello, gorgeous');
},
},
};
```
**Note:** All hooks recieve an extra final argument, which is the flecks instance.
## Types
 
### `invoke(hook, ...args)`
Invokes all hook implementations and returns the results keyed by the implementing flecks' paths.
 
### `invokeComposed(hook, initial, ...args)`
### `invokeComposedAsync(hook, initial, ...args)`
See: [function composition](https://www.educative.io/edpresso/function-composition-in-javascript).
`initial` is passed to the first implementation, which returns a result which is passed to the second implementation, which returns a result which is passed to the third implementation, etc.
Composed hooks are ordered.
 
### `invokeFlat(hook, ...args)`
Invokes all hook implementations and returns the results as an array.
 
### `invokeFleck(hook, fleck, ...args)`
Invoke a single fleck's hook implementation and return the result.
 
### `invokeMerge(hook, ...args)`
### `invokeMergeAsync(hook, ...args)`
Invokes all hook implementations and returns the result of merging all implementations' returned objects together.
 
### `invokeReduce(hook, reducer, initial, ...args)`
### `invokeReduceAsync(hook, reducer, initial, ...args)`
See: [Array.prototype.reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)
Invokes hook implementations one at a time, their results being passed to the reducer as `currentValue`. Returns the final reduction.
 
### `invokeSequential(Async)?(hook, ...args)`
Invokes all hook implementations, one after another. In the async variant, each implementation's result is `await`ed before invoking the next implementation.
Sequential hooks are ordered.
 
## Idioms
### `flecks.gather(hook, options)`
Gathering is useful when your fleck defines some sort of specification, and then expects its sibling flecks to actually implement it. Examples of this in flecks would be:
- Models, defined through `@flecks/db/server.models`.
- Packets, defined through `@flecks/socket.packets`.
One constraint of using `flecks.gather()` is that whatever you are gathering must be able to be extended as a class. You can't `flecks.gather()` plain objects, numbers, strings... you get the idea.
The most basic usage:
```javascript
const Gathered = flecks.gather('my-gather-hook');
```
Suppose `my-gather-hook` above resulted in gathering two classes, `Foo` and `Bar`. In this case, `Gathered` would be such as:
```javascript
import {ById, ByType} from '@flecks/core';
const Gathered = {
1: Bar,
2: Foo,
'Bar': Bar,
'Foo': Foo,
[ById]: {
1: Bar,
2: Foo,
},
[ByType]: {
'Bar': Bar,
'Foo': Foo,
},
};
```
`flecks.gather()` gives each of your classes a numeric (nonzero) ID as well as a type name. It also merges all numeric keys and type labels together into the result, so `Gathered[1] === Gathered.Bar` would evaluate to `true` in the example above.
The symbol keys `ById` and `ByType` are useful if you need to iterate over *either* all IDs or all types. Since the numeric IDs and types are merged, iterating over the entire `Gathered` object would otherwise result in duplicates.
Each class gathered by `flecks.gather()` will be extended with two properties by default: `id` and `type`. These correspond to the ID and type referenced above, and are useful for e.g. serialization.
Following from the example above:
```javascript
const foo = new Gathered.Foo();
assert(foo.id === 2);
assert(foo.type === 'Foo);
```
`flecks.gather()` also supports some options:
```javascript
{
// The property added when extending the class to return the numeric ID.
idAttribute = 'id',
// The property added when extending the class to return the type.
typeAttribute = 'type',
// A function called with the `Gathered` object to allow checking validity.
check = () => {},
}
```
As an example, when `@flecks/db/server` gathers models, `typeAttribute` is set to `name`, because Sequelize requires its model classes to have a unique `name` property.
**Note:** the numeric IDs are useful for efficient serialization between the client and server, but **if you are using this property, ensure that `flecks.gather()` is called equivalently on both the client and the server**. As a rule of thumb, if you have serializable `Gathered`s, they should be invoked and defined in `your-fleck`, and not in `your-fleck/[platform]`, so that they are invoked for every platform.
#### `Flecks.provide(context, options)`
Complementary to gather hooks above, `Flecks.provide()` allows you to ergonomically provide your flecks' implementations to a gather hook.
Here's an example of how you could manually provide `@flecks/db/server.models` in your own fleck:
```javascript
import {Hooks} foom '@flecks/core';
import SomeModel from './models/some-model';
import AnotherModel from './models/another-model';
export default {
[Hooks]: {
'@flecks/db/server.models': () => ({
SomeModel,
AnotherModel,
}),
},
};
```
If you think about the example above, you might realize that it will become a lot of typing to keep adding new models over time. Provider hooks exist to reduce this maintenance burden for you.
Webpack provides an API called [require.context](https://v4.webpack.js.org/guides/dependency-management/#requirecontext), and the flecks provider is optimized to work with this API.
Supposing our fleck is structured like so:
```
index.js
models/
├─ some-model.js
└─ another-model.js
```
then, this `index.js`:
```javascript
import {Flecks, Hooks} from '@flecks/core';
export default {
[Hooks]: {
'@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
},
};
```
is *exactly equivalent* to the gather example above. By default, `Flecks.provide()` *CamelCase*s the paths, so `some-model` becomes `SomeModel`, just as in the example above.
`Flecks.provide()` also supports some options:
```javascript
{
// The transformation used on the class path.
transformer = camelCase,
}
```
**Note:** There is no requirement to use `Flecks.provide()`, it is merely a convenience.
### Decorator hooks
When a Model (or any other) is gathered as above, an implicit hook is called: `${hook}.decorate`. This allows other flecks to decorate whatever has been gathered:
```javascript
import {Hooks} from '@flecks/core';
export default {
[Hooks]: {
'@flecks/db/server.models.decorate': (Models) => {
return {
...Models,
User: class extends Models.User {
// Let's mix in some logging...
constructor(...args) {
super(...args);
console.log ('Another user decorated!');
}
},
};
},
},
};
```
#### `Flecks.decorate(context, options)`
As with above, there exists an API for making the maintenance of decorators more ergonomic.
Supposing our fleck is structured like so:
```
index.js
models/
└─ decorators/
└─ user.js
```
and supposing that `./models/decorators/user.js` is written like so:
```javascript
export default (User) => {
return class extends User {
// Let's mix in some logging...
constructor(...args) {
super(...args);
console.log ('Another user decorated!');
}
};
};
```
then, this `index.js`:
```javascript
import {Flecks, Hooks} from '@flecks/core';
export default {
[Hooks]: {
'@flecks/db/server.models.decorate': Flecks.decorate(require.context('./models/decorators', false, /\.js$/)),
},
};
```
is *exactly equivalent* to the decorator example above.
`Flecks.decorate()` also supports some options:
```javascript
{
// The transformation used on the class path.
transformer = camelCase,
}
```
Decorator hooks are ordered.
## Ordered hooks
In many of the instances above, reference was made to the fact that certain hook types are "ordered".
Suppose we are composing an application and we have HTTP session state using cookies. When a user hits a route, we need to load their session and subsequently read a value from said session to determine if the user prefers dark mode. Clearly, we will have to ensure that the session reification happens first. This is one function of ordered hooks.
Flecks uses the name of the hook as a configuration key in order to determine the ordering of a hook. Let's take the hook we alluded to earlier as an example, `@flecks/http/server.request.route`:
Our `flecks.yml` could be configured like so:
```yaml
'@flecks/http/server':
'request.route':
- '@flecks/user/session'
- 'my-cool-fleck'
```
In this application, when `@flecks/http/server.request.route` is invoked, `@flecks/user/session`'s implementation is invoked (which reifies the user's session from cookies), followed by `my-cool-fleck`'s (which, we assume, does some kind of very cool dark mode check).
It may not always be ergonomic to configure the order of every single implementation, but enough to specify which implementations must run first (or last).
For example, suppose we have multiple implementations that require there to have been a reified user session, but which order those implementations run might not be a concern. For this, flecks provides you with the ellipses entry:
```yaml
'@flecks/http/server':
'request.route':
- '@flecks/user/session'
- '...'
- 'some-final-fleck'
```
In this application, we first reify the user session as before, but instead of listing `my-cool-fleck` immediately after, we specify ellipses. After the ellipses we specify `some-final-fleck` to, we assume, do some finalization work.
Ellipses essentially translate to: "every implementing fleck which has not already been explicitly listed in the ordering configuration".
Using more than one ellipses entry in an ordering configuration is ambiguous and will throw an error.
The default ordering configuration for any ordered hook is: `['...']` which translates to all implementations in an undefined order.

View File

@ -7,7 +7,7 @@ export default {
* @param {string} target The build target; e.g. `server`. * @param {string} target The build target; e.g. `server`.
* @param {Object} config The neutrino configuration. * @param {Object} config The neutrino configuration.
*/ */
'@flecks/core/build': (target, config) => { '@flecks/core.build': (target, config) => {
if ('something' === target) { if ('something' === target) {
config[target].use.push(someNeutrinoMiddleware); config[target].use.push(someNeutrinoMiddleware);
} }
@ -17,7 +17,7 @@ export default {
* Alter build configurations after they have been hooked. * Alter build configurations after they have been hooked.
* @param {Object} configs The neutrino configurations. * @param {Object} configs The neutrino configurations.
*/ */
'@flecks/core/build/alter': (configs) => { '@flecks/core.build.alter': (configs) => {
// Maybe we want to do something if a config exists..? // Maybe we want to do something if a config exists..?
if (configs.something) { if (configs.something) {
// Do something... // Do something...
@ -29,7 +29,7 @@ export default {
/** /**
* Define CLI commands. * Define CLI commands.
*/ */
'@flecks/core/commands': (program) => ({ '@flecks/core.commands': (program) => ({
// So this could be invoked like: // So this could be invoked like:
// npx flecks something -t --blow-up blah // npx flecks something -t --blow-up blah
something: { something: {
@ -50,7 +50,7 @@ export default {
/** /**
* Define configuration. * Define configuration.
*/ */
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
whatever: 'configuration', whatever: 'configuration',
your: 1337, your: 1337,
fleck: 'needs', fleck: 'needs',
@ -58,43 +58,43 @@ export default {
}), }),
/** /**
* Invoked when a gathered class is HMR'd. * Invoked when a fleck is HMR'd
* @param {constructor} Class The class. * @param {string} path The path of the fleck
* @param {string} hook The gather hook; e.g. `@flecks/db/server/models`. * @param {Module} updatedFleck The updated fleck module.
*/ */
'@flecks/core/gathered/hmr': (Class, hook) => { '@flecks/core.hmr': (path, updatedFleck) => {
// Do something with Class...
},
/**
* Invoked when a fleck is HMR'd
* @param {string} path The path of the fleck
* @param {Module} updatedFleck The updated fleck module.
*/
'@flecks/core/hmr': (path, updatedFleck) => {
if ('my-fleck' === path) { if ('my-fleck' === path) {
updatedFleck.doSomething(); updatedFleck.doSomething();
} }
}, },
/**
* Invoked when a gathered class is HMR'd.
* @param {constructor} Class The class.
* @param {string} hook The gather hook; e.g. `@flecks/db/server.models`.
*/
'@flecks/core.hmr.gathered': (Class, hook) => {
// Do something with Class...
},
/** /**
* Invoked when the application is starting. Use for order-independent initialization tasks. * Invoked when the application is starting. Use for order-independent initialization tasks.
*/ */
'@flecks/core/starting': (flecks) => { '@flecks/core.starting': (flecks) => {
flecks.set('$my-fleck/value', initializeMyValue()); flecks.set('$my-fleck/value', initializeMyValue());
}, },
/** /**
* Define neutrino build targets. * Define neutrino build targets.
*/ */
'@flecks/core/targets': () => ['sometarget'], '@flecks/core.targets': () => ['sometarget'],
/** /**
* Hook into webpack configuration. * Hook into webpack configuration.
* @param {string} target The build target; e.g. `server`. * @param {string} target The build target; e.g. `server`.
* @param {Object} config The neutrino configuration. * @param {Object} config The neutrino configuration.
*/ */
'@flecks/core/webpack': (target, config) => { '@flecks/core.webpack': (target, config) => {
if ('something' === target) { if ('something' === target) {
config.stats = 'verbose'; config.stats = 'verbose';
} }

View File

@ -29,7 +29,7 @@ module.exports = {
}, },
}, },
], ],
pluginId: '@flecks/core/copy', pluginId: '@flecks/core.copy',
}), }),
autoentry(), autoentry(),
fleck(), fleck(),

View File

@ -16,5 +16,5 @@ const flecks = Flecks.bootstrap();
debug('bootstrapped'); debug('bootstrapped');
const config = R(process.env[targetNeutrino(FLECKS_CORE_BUILD_TARGET)]); const config = R(process.env[targetNeutrino(FLECKS_CORE_BUILD_TARGET)]);
flecks.invokeFlat('@flecks/core/build', FLECKS_CORE_BUILD_TARGET, config); flecks.invokeFlat('@flecks/core.build', FLECKS_CORE_BUILD_TARGET, config);
module.exports = neutrino(config).eslintrc(); module.exports = neutrino(config).eslintrc();

View File

@ -35,7 +35,7 @@ export default (async () => {
debug('bootstrapped'); debug('bootstrapped');
debug('gathering configs'); debug('gathering configs');
let targets = flatten(flecks.invokeFlat('@flecks/core/targets')); let targets = flatten(flecks.invokeFlat('@flecks/core.targets'));
if (buildList.length > 0) { if (buildList.length > 0) {
targets = intersection(targets, buildList); targets = intersection(targets, buildList);
} }
@ -52,16 +52,16 @@ export default (async () => {
)); ));
await Promise.all( await Promise.all(
entries.map(async ([target, config]) => ( entries.map(async ([target, config]) => (
flecks.invokeFlat('@flecks/core/build', target, config) flecks.invokeFlat('@flecks/core.build', target, config)
)), )),
); );
const neutrinoConfigs = Object.fromEntries(entries); const neutrinoConfigs = Object.fromEntries(entries);
await Promise.all(flecks.invokeFlat('@flecks/core/build/alter', neutrinoConfigs)); await Promise.all(flecks.invokeFlat('@flecks/core.build.alter', neutrinoConfigs));
const webpackConfigs = await Promise.all( const webpackConfigs = await Promise.all(
Object.entries(neutrinoConfigs) Object.entries(neutrinoConfigs)
.map(async ([target, config]) => { .map(async ([target, config]) => {
const webpackConfig = neutrino(config).webpack(); const webpackConfig = neutrino(config).webpack();
await flecks.invokeFlat('@flecks/core/webpack', target, webpackConfig); await flecks.invokeFlat('@flecks/core.webpack', target, webpackConfig);
return webpackConfig; return webpackConfig;
}), }),
); );

View File

@ -87,7 +87,7 @@ else {
const flecks = Flecks.bootstrap(); const flecks = Flecks.bootstrap();
debug('bootstrapped'); debug('bootstrapped');
// Register commands. // Register commands.
const commands = flecks.invokeMerge('@flecks/core/commands', program); const commands = flecks.invokeMerge('@flecks/core.commands', program);
const keys = Object.keys(commands).sort(); const keys = Object.keys(commands).sort();
for (let i = 0; i < keys.length; ++i) { for (let i = 0; i < keys.length; ++i) {
const { const {

View File

@ -15,9 +15,9 @@ import Middleware from './middleware';
const debug = D('@flecks/core/flecks'); const debug = D('@flecks/core/flecks');
export const ById = Symbol.for('@flecks/core/byId'); export const ById = Symbol.for('@flecks/core.byId');
export const ByType = Symbol.for('@flecks/core/byType'); export const ByType = Symbol.for('@flecks/core.byType');
export const Hooks = Symbol.for('@flecks/core/hooks'); export const Hooks = Symbol.for('@flecks/core.hooks');
const capitalize = (string) => string.substring(0, 1).toUpperCase() + string.substring(1); const capitalize = (string) => string.substring(0, 1).toUpperCase() + string.substring(1);
@ -67,13 +67,13 @@ export default class Flecks {
configureFleck(fleck) { configureFleck(fleck) {
this.config[fleck] = { this.config[fleck] = {
...this.invokeFleck('@flecks/core/config', fleck), ...this.invokeFleck('@flecks/core.config', fleck),
...this.config[fleck], ...this.config[fleck],
}; };
} }
configureFlecks() { configureFlecks() {
const defaultConfig = this.invoke('@flecks/core/config'); const defaultConfig = this.invoke('@flecks/core.config');
const flecks = Object.keys(defaultConfig); const flecks = Object.keys(defaultConfig);
for (let i = 0; i < flecks.length; i++) { for (let i = 0; i < flecks.length; i++) {
this.configureFleck(flecks[i]); this.configureFleck(flecks[i]);
@ -330,9 +330,11 @@ export default class Flecks {
} }
lookupFlecks(hook) { lookupFlecks(hook) {
const parts = hook.split('/'); const index = hook.indexOf('.');
const key = parts.pop(); if (-1 === index) {
return this.config[parts.join('/')]?.[key]?.concat() || []; return ['...'];
}
return this.get([hook.slice(0, index), hook.slice(index + 1)], ['...']);
} }
makeMiddleware(hook) { makeMiddleware(hook) {
@ -448,7 +450,7 @@ export default class Flecks {
} }
async up(hook) { async up(hook) {
await Promise.all(this.invokeFlat('@flecks/core/starting')); await Promise.all(this.invokeFlat('@flecks/core.starting'));
await this.invokeSequentialAsync(hook); await this.invokeSequentialAsync(hook);
} }
@ -474,7 +476,7 @@ export default class Flecks {
const Subclass = wrapperClass(Class, id, idAttribute, type, typeAttribute); const Subclass = wrapperClass(Class, id, idAttribute, type, typeAttribute);
// eslint-disable-next-line no-multi-assign // eslint-disable-next-line no-multi-assign
gathered[type] = gathered[id] = gathered[ById][id] = gathered[ByType][type] = Subclass; gathered[type] = gathered[id] = gathered[ById][id] = gathered[ByType][type] = Subclass;
this.invoke('@flecks/core/gathered/hmr', Subclass, hook); this.invoke('@flecks/core.hmr.gathered', Subclass, hook);
} }
} }
} }

View File

@ -17,7 +17,7 @@ export {
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
'eslint.exclude': [], 'eslint.exclude': [],
id: 'flecks', id: 'flecks',
}), }),

View File

@ -44,7 +44,7 @@ export const targetNeutrino = (target) => (
); );
export const targetNeutrinos = (flecks) => { export const targetNeutrinos = (flecks) => {
const entries = Object.entries(flecks.invoke('@flecks/core/targets')); const entries = Object.entries(flecks.invoke('@flecks/core.targets'));
const targetNeutrinos = {}; const targetNeutrinos = {};
for (let i = 0; i < entries.length; ++i) { for (let i = 0; i < entries.length; ++i) {
const [fleck, targets] = entries[i]; const [fleck, targets] = entries[i];
@ -86,7 +86,7 @@ export default (program, flecks) => {
], ],
}, },
}; };
const targets = flatten(flecks.invokeFlat('@flecks/core/targets')); const targets = flatten(flecks.invokeFlat('@flecks/core.targets'));
if (targets.length > 0) { if (targets.length > 0) {
commands.build = { commands.build = {
args: [ args: [

View File

@ -18,7 +18,7 @@ export {JsonStream, transform} from './stream';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/build': (target, config, flecks) => { '@flecks/core.build': (target, config, flecks) => {
const {'eslint.exclude': exclude} = flecks.get('@flecks/core'); const {'eslint.exclude': exclude} = flecks.get('@flecks/core');
if (-1 !== exclude.indexOf(target)) { if (-1 !== exclude.indexOf(target)) {
return; return;
@ -43,6 +43,6 @@ export default {
}), }),
); );
}, },
'@flecks/core/commands': commands, '@flecks/core.commands': commands,
}, },
}; };

View File

@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
import {Flecks, Hooks} from '@flecks/core'; import {Flecks, Hooks} from '@flecks/core';
export const testNodespace = () => [ export const testNodespace = () => [
@ -10,9 +10,8 @@ export const testNodespace = () => [
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
foo: 'bar', foo: 'bar',
'test-gather.decorate': ['...'],
}), }),
'@flecks/core/one/test-gather': ( '@flecks/core/one/test-gather': (
Flecks.provide(require.context('./things', false, /\.js$/)) Flecks.provide(require.context('./things', false, /\.js$/))

View File

@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
import {Flecks, Hooks} from '@flecks/core'; import {Flecks, Hooks} from '@flecks/core';
export default { export default {

View File

@ -9,7 +9,7 @@ export default {
* defined in its own file. * defined in its own file.
* See: https://github.com/cha0s/flecks/tree/master/packages/user/src/server/models * See: https://github.com/cha0s/flecks/tree/master/packages/user/src/server/models
*/ */
'@flecks/db/server/models': Flecks.provide(require.context('./models', false, /\.js$/)), '@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
/** /**
* Decorate database models. * Decorate database models.
@ -20,7 +20,7 @@ export default {
* *
* @param {constructor} Model The model to decorate. * @param {constructor} Model The model to decorate.
*/ */
'@flecks/db/server/models.decorate': ( '@flecks/db/server.models.decorate': (
Flecks.decorate(require.context('./models/decorators', false, /\.js$/)) Flecks.decorate(require.context('./models/decorators', false, /\.js$/))
), ),
}, },

View File

@ -11,26 +11,25 @@ export {createDatabaseConnection};
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
database: ':memory:', database: ':memory:',
dialect: 'sqlite', dialect: 'sqlite',
host: undefined, host: undefined,
'models.decorate': ['...'],
password: undefined, password: undefined,
port: undefined, port: undefined,
username: undefined, username: undefined,
}), }),
'@flecks/core/starting': (flecks) => { '@flecks/core.starting': (flecks) => {
flecks.set('$flecks/db.models', flecks.gather( flecks.set('$flecks/db.models', flecks.gather(
'@flecks/db/server/models', '@flecks/db/server.models',
{typeAttribute: 'name'}, {typeAttribute: '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.set('$flecks/db/sequelize', await createDatabaseConnection(flecks));
}, },
'@flecks/repl/context': (flecks) => ({ '@flecks/repl.context': (flecks) => ({
Models: flecks.get('$flecks/db.models'), Models: flecks.get('$flecks/db.models'),
sequelize: flecks.get('$flecks/db/sequelize'), sequelize: flecks.get('$flecks/db/sequelize'),
}), }),

View File

@ -8,7 +8,7 @@ export default {
* Beware: the user running the server must have Docker privileges. * Beware: the user running the server must have Docker privileges.
* See: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user * See: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
*/ */
'@flecks/docker/containers': () => ({ '@flecks/docker.containers': () => ({
someContainer: { someContainer: {
// Environment variables. // Environment variables.
environment: { environment: {

View File

@ -47,7 +47,7 @@ export default (program, flecks) => {
], ],
}, },
}; };
const containers = flecks.invoke('@flecks/docker/containers'); const containers = flecks.invoke('@flecks/docker.containers');
( (
await Promise.all( await Promise.all(
Object.entries(containers) Object.entries(containers)

View File

@ -5,15 +5,15 @@ import startContainer from './start-container';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
enabled: true, enabled: true,
}), }),
'@flecks/core/commands': commands, '@flecks/core.commands': commands,
'@flecks/server/up': async (flecks) => { '@flecks/server.up': async (flecks) => {
if (!flecks.get('@flecks/docker/server.enabled')) { if (!flecks.get('@flecks/docker/server.enabled')) {
return; return;
} }
const containers = await flecks.invokeMergeAsync('@flecks/docker/containers'); const containers = await flecks.invokeMergeAsync('@flecks/docker.containers');
await Promise.all( await Promise.all(
Object.entries(containers) Object.entries(containers)
.map(([key, config]) => startContainer(flecks, key, config)), .map(([key, config]) => startContainer(flecks, key, config)),

View File

@ -82,7 +82,7 @@ const FlecksInvocations = (state, filename) => ({
path.node.loc, path.node.loc,
); );
state.addInvocation( state.addInvocation(
'@flecks/core/starting', '@flecks/core.starting',
'invokeFlat', 'invokeFlat',
filename, filename,
path.node.loc, path.node.loc,

View File

@ -4,8 +4,8 @@ import commands from './commands';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/commands': commands, '@flecks/core.commands': commands,
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
filenameRewriters: {}, filenameRewriters: {},
}), }),
}, },

View File

@ -20,7 +20,7 @@ module.exports = (async () => {
debug('bootstrapped'); debug('bootstrapped');
const compiler = flecks.invokeFleck( const compiler = flecks.invokeFleck(
'@flecks/fleck/compiler', '@flecks/fleck.compiler',
flecks.get('@flecks/fleck.compiler'), flecks.get('@flecks/fleck.compiler'),
); );
if (compiler) { if (compiler) {

View File

@ -10,7 +10,7 @@ import {
spawnWith, spawnWith,
} from '@flecks/core/server'; } from '@flecks/core/server';
const debug = D('@flecks/core/commands'); const debug = D('@flecks/core.commands');
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),

View File

@ -4,7 +4,7 @@ import commands from './commands';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/commands': commands, '@flecks/core.commands': commands,
'@flecks/core/targets': () => ['fleck'], '@flecks/core.targets': () => ['fleck'],
}, },
}; };

View File

@ -7,7 +7,7 @@ export {default as createLimiter} from './limiter';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
keys: ['ip'], keys: ['ip'],
http: { http: {
keys: ['ip'], keys: ['ip'],
@ -22,8 +22,8 @@ export default {
ttl: 30, ttl: 30,
}, },
}), }),
'@flecks/db/server/models': Flecks.provide(require.context('./models', false, /\.js$/)), '@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
'@flecks/http/server/request.route': (flecks) => { '@flecks/http/server.request.route': (flecks) => {
const {http} = flecks.get('@flecks/governor/server'); const {http} = flecks.get('@flecks/governor/server');
const limiter = flecks.get('$flecks/governor.http.limiter'); const limiter = flecks.get('$flecks/governor.http.limiter');
return async (req, res, next) => { return async (req, res, next) => {
@ -52,7 +52,7 @@ export default {
} }
}; };
}, },
'@flecks/server/up': async (flecks) => { '@flecks/server.up': async (flecks) => {
if (flecks.fleck('@flecks/http/server')) { if (flecks.fleck('@flecks/http/server')) {
const {http} = flecks.get('@flecks/governor/server'); const {http} = flecks.get('@flecks/governor/server');
const limiter = await createLimiter( const limiter = await createLimiter(
@ -93,7 +93,7 @@ export default {
flecks.set('$flecks/governor.socket.limiter', limiter); 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'); const limiter = flecks.get('$flecks/governor.socket.limiter');
return async (socket, next) => { return async (socket, next) => {
const {handshake: req} = socket; const {handshake: req} = socket;
@ -120,7 +120,7 @@ export default {
} }
}; };
}, },
'@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]) => [
keyPrefix, keyPrefix,

View File

@ -5,14 +5,14 @@ export default {
/** /**
* Define sequential actions to run when the client comes up. * Define sequential actions to run when the client comes up.
*/ */
'@flecks/http/client/up': async () => { '@flecks/http/client.up': async () => {
await youCanDoAsyncThingsHere(); await youCanDoAsyncThingsHere();
}, },
/** /**
* Override flecks configuration sent to client flecks. * Override flecks configuration sent to client flecks.
* @param {http.ClientRequest} req The HTTP request object. * @param {http.ClientRequest} req The HTTP request object.
*/ */
'@flecks/http/config': (req) => ({ '@flecks/http.config': (req) => ({
someClientFleck: { someClientFleck: {
someConfig: req.someConfig, someConfig: req.someConfig,
}, },
@ -20,7 +20,7 @@ export default {
/** /**
* Define HTTP routes. * Define HTTP routes.
*/ */
'@flecks/http/routes': () => [ '@flecks/http.routes': () => [
{ {
method: 'get', method: 'get',
path: '/some-path', path: '/some-path',
@ -33,20 +33,20 @@ export default {
/** /**
* Define neutrino compilation middleware (e.g. @neutrinojs/react). * Define neutrino compilation middleware (e.g. @neutrinojs/react).
*/ */
'@flecks/http/server/compiler': () => { '@flecks/http/server.compiler': () => {
return require('@neutrinojs/node'); return require('@neutrinojs/node');
}, },
/** /**
* Define middleware to run when a route is matched. * Define middleware to run when a route is matched.
*/ */
'@flecks/http/server/request.route': () => (req, res, next) => { '@flecks/http/server.request.route': () => (req, res, next) => {
// Express-style route middleware... // Express-style route middleware...
next(); next();
}, },
/** /**
* Define middleware to run when an HTTP socket connection is established. * Define middleware to run when an HTTP socket connection is established.
*/ */
'@flecks/http/server/request.socket': () => (req, res, next) => { '@flecks/http/server.request.socket': () => (req, res, next) => {
// Express-style route middleware... // Express-style route middleware...
next(); next();
}, },
@ -55,13 +55,13 @@ export default {
* @param {stream.Readable} stream The HTML stream. * @param {stream.Readable} stream The HTML stream.
* @param {http.ClientRequest} req The HTTP request object. * @param {http.ClientRequest} req The HTTP request object.
*/ */
'@flecks/http/server/stream.html': (stream, req) => { '@flecks/http/server.stream.html': (stream, req) => {
return stream.pipe(myTransformStream); return stream.pipe(myTransformStream);
}, },
/** /**
* Define sequential actions to run when the HTTP server comes up. * Define sequential actions to run when the HTTP server comes up.
*/ */
'@flecks/http/server/up': async () => { '@flecks/http/server.up': async () => {
await youCanDoAsyncThingsHere(); await youCanDoAsyncThingsHere();
}, },
}, },

View File

@ -20,8 +20,6 @@
"files": [ "files": [
"build", "build",
"build/template.ejs", "build/template.ejs",
"client.js",
"client.js.map",
"client/tests.js", "client/tests.js",
"client/tests.js.map", "client/tests.js.map",
"entry.js", "entry.js",

View File

@ -1,9 +0,0 @@
import {Hooks} from '@flecks/core';
export default {
[Hooks]: {
'@flecks/core/config': () => ({
up: ['...'],
}),
},
};

View File

@ -11,7 +11,7 @@ const progress = new Progress(window);
(async () => { (async () => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(`flecks client v${version} loading runtime...`); console.log(`flecks client v${version} loading runtime...`);
const config = window[Symbol.for('@flecks/http/config')]; const config = window[Symbol.for('@flecks/http.config')];
const debug = D(config['@flecks/core']?.id || 'flecks'); const debug = D(config['@flecks/core']?.id || 'flecks');
debug('loading runtime...'); debug('loading runtime...');
const {default: loader} = await __non_webpack_import__( const {default: loader} = await __non_webpack_import__(
@ -24,7 +24,7 @@ const progress = new Progress(window);
const flecks = new Flecks(runtime); const flecks = new Flecks(runtime);
window.flecks = flecks; window.flecks = flecks;
try { try {
await flecks.up('@flecks/http/client/up'); await flecks.up('@flecks/http/client.up');
debug('up!'); debug('up!');
} }
catch (error) { catch (error) {

View File

@ -37,7 +37,7 @@ module.exports = (async () => {
}; };
// Compile code. // Compile code.
const compiler = flecks.invokeFleck( const compiler = flecks.invokeFleck(
'@flecks/http/server/compiler', '@flecks/http/server.compiler',
flecks.get('@flecks/http/server.compiler'), flecks.get('@flecks/http/server.compiler'),
); );
if (compiler) { if (compiler) {

View File

@ -24,7 +24,7 @@ module.exports = async (flecks) => {
const paths = Object.entries(resolver); const paths = Object.entries(resolver);
const source = [ const source = [
'module.exports = (update) => (async () => ({', 'module.exports = (update) => (async () => ({',
" config: window[Symbol.for('@flecks/http/config')],", " config: window[Symbol.for('@flecks/http.config')],",
' flecks: Object.fromEntries(await Promise.all([', ' flecks: Object.fromEntries(await Promise.all([',
paths paths
.map(([path]) => [ .map(([path]) => [
@ -45,7 +45,7 @@ module.exports = async (flecks) => {
source.push(` module.hot.accept('${path}', async () => {`); source.push(` module.hot.accept('${path}', async () => {`);
source.push(` const updatedFleck = require('${path}');`); source.push(` const updatedFleck = require('${path}');`);
source.push(` window.flecks.refresh('${path}', updatedFleck);`); source.push(` window.flecks.refresh('${path}', updatedFleck);`);
source.push(` window.flecks.invoke('@flecks/core/hmr', '${path}', updatedFleck);`); source.push(` window.flecks.invoke('@flecks/core.hmr', '${path}', updatedFleck);`);
source.push(' });'); source.push(' });');
}); });
source.push('}'); source.push('}');

View File

@ -1,7 +1,7 @@
import {Transform} from 'stream'; import {Transform} from 'stream';
const config = async (flecks, req) => { const config = async (flecks, req) => {
const httpConfig = await flecks.invokeMergeAsync('@flecks/http/config', req); const httpConfig = await flecks.invokeMergeAsync('@flecks/http.config', req);
const config = {}; const config = {};
const {resolver} = flecks.get('$flecks/http.flecks'); const {resolver} = flecks.get('$flecks/http.flecks');
const keys = Object.keys(resolver); const keys = Object.keys(resolver);
@ -24,7 +24,7 @@ const config = async (flecks, req) => {
export const configSource = async (flecks, req) => { export const configSource = async (flecks, req) => {
const codedConfig = encodeURIComponent(JSON.stringify(await config(flecks, req))); const codedConfig = encodeURIComponent(JSON.stringify(await config(flecks, req)));
return `window[Symbol.for('@flecks/http/config')] = JSON.parse(decodeURIComponent("${ return `window[Symbol.for('@flecks/http.config')] = JSON.parse(decodeURIComponent("${
codedConfig codedConfig
}"));`; }"));`;
}; };

View File

@ -16,7 +16,7 @@ const {
const debug = D('@flecks/http/server/http'); const debug = D('@flecks/http/server/http');
const deliverHtmlStream = (stream, flecks, req, res) => { const deliverHtmlStream = (stream, flecks, req, res) => {
flecks.invokeComposed('@flecks/http/server/stream.html', stream, req).pipe(res); flecks.invokeComposed('@flecks/http/server.stream.html', stream, req).pipe(res);
}; };
export const createHttpServer = async (flecks) => { export const createHttpServer = async (flecks) => {
@ -36,10 +36,10 @@ export const createHttpServer = async (flecks) => {
// 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.
app.use(flecks.makeMiddleware('@flecks/http/server/request.socket')); app.use(flecks.makeMiddleware('@flecks/http/server.request.socket'));
// Routes. // Routes.
const routeMiddleware = flecks.makeMiddleware('@flecks/http/server/request.route'); const routeMiddleware = flecks.makeMiddleware('@flecks/http/server.request.route');
const routes = flatten(flecks.invokeFlat('@flecks/http/routes')); const routes = flatten(flecks.invokeFlat('@flecks/http.routes'));
routes.forEach(({method, path, middleware}) => app[method](path, routeMiddleware, middleware)); routes.forEach(({method, path, middleware}) => app[method](path, routeMiddleware, middleware));
// In development mode, create a proxy to the webpack-dev-server. // In development mode, create a proxy to the webpack-dev-server.
if ('production' !== NODE_ENV) { if ('production' !== NODE_ENV) {
@ -117,7 +117,7 @@ export const createHttpServer = async (flecks) => {
reject(error); reject(error);
return; return;
} }
await Promise.all(flecks.invokeFlat('@flecks/http/server/up', httpServer)); await Promise.all(flecks.invokeFlat('@flecks/http/server.up', httpServer));
debug('HTTP server up @ %s!', [host, port].filter((e) => !!e).join(':')); debug('HTTP server up @ %s!', [host, port].filter((e) => !!e).join(':'));
resolve(); resolve();
}); });

View File

@ -8,7 +8,7 @@ const debug = D('@flecks/http/server');
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/build/alter': (neutrinoConfigs, flecks) => { '@flecks/core.build.alter': (neutrinoConfigs, flecks) => {
// Bail if there's no http build. // Bail if there's no http build.
if (!neutrinoConfigs.http) { if (!neutrinoConfigs.http) {
return; return;
@ -36,7 +36,7 @@ export default {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
delete neutrinoConfigs.http; delete neutrinoConfigs.http;
}, },
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
devHost: 'localhost', devHost: 'localhost',
devPort: undefined, devPort: undefined,
devPublic: undefined, devPublic: undefined,
@ -44,20 +44,18 @@ export default {
host: '0.0.0.0', host: '0.0.0.0',
output: 'http', output: 'http',
port: 32340, port: 32340,
'stream.html': ['...'],
'request.route': [], 'request.route': [],
'request.socket': [], 'request.socket': [],
trust: false, trust: false,
up: ['...'],
}), }),
'@flecks/core/starting': (flecks) => { '@flecks/core.starting': (flecks) => {
debug('bootstrapping flecks...'); debug('bootstrapping flecks...');
const httpFlecks = Flecks.bootstrap({platforms: ['client'], without: ['server']}); const httpFlecks = Flecks.bootstrap({platforms: ['client'], without: ['server']});
debug('bootstrapped'); debug('bootstrapped');
flecks.set('$flecks/http.flecks', httpFlecks); flecks.set('$flecks/http.flecks', httpFlecks);
}, },
'@flecks/core/targets': () => ['http'], '@flecks/core.targets': () => ['http'],
'@flecks/http/routes': (flecks) => [ '@flecks/http.routes': (flecks) => [
{ {
method: 'get', method: 'get',
path: '/flecks.config.js', path: '/flecks.config.js',
@ -67,9 +65,9 @@ export default {
}, },
}, },
], ],
'@flecks/http/server/stream.html': inlineConfig, '@flecks/http/server.stream.html': inlineConfig,
'@flecks/server/up': (flecks) => createHttpServer(flecks), '@flecks/server.up': (flecks) => createHttpServer(flecks),
'@flecks/repl/context': (flecks) => ({ '@flecks/repl.context': (flecks) => ({
httpServer: flecks.get('$flecks/http/server.instance'), httpServer: flecks.get('$flecks/http/server.instance'),
}), }),
}, },

View File

@ -8,7 +8,7 @@ export default {
* Note: `req` will be only be defined when server-side rendering. * Note: `req` will be only be defined when server-side rendering.
* @param {http.ClientRequest} req The HTTP request object. * @param {http.ClientRequest} req The HTTP request object.
*/ */
'@flecks/react/providers': (req) => { '@flecks/react.providers': (req) => {
// Generally it makes more sense to separate client and server concerns using platform // Generally it makes more sense to separate client and server concerns using platform
// naming conventions, but this is just a small contrived example. // naming conventions, but this is just a small contrived example.
return req ? serverSideProvider(req) : clientSideProvider(); return req ? serverSideProvider(req) : clientSideProvider();
@ -18,7 +18,7 @@ export default {
* Note: `req` will be only be defined when server-side rendering. * Note: `req` will be only be defined when server-side rendering.
* @param {http.ClientRequest} req The HTTP request object. * @param {http.ClientRequest} req The HTTP request object.
*/ */
'@flecks/react/roots': (req) => { '@flecks/react.roots': (req) => {
// Note that we're not returning `<Component />`, but `Component`. // Note that we're not returning `<Component />`, but `Component`.
return Component; return Component;
}, },

View File

@ -12,7 +12,7 @@ export {FlecksContext};
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/http/client/up': async (flecks) => { '@flecks/http/client.up': async (flecks) => {
const {ssr} = flecks.get('@flecks/react'); const {ssr} = flecks.get('@flecks/react');
debug('%sing...', ssr ? 'hydrat' : 'render'); debug('%sing...', ssr ? 'hydrat' : 'render');
(ssr ? hydrate : render)( (ssr ? hydrate : render)(

View File

@ -7,10 +7,10 @@ export default () => {
const flecks = useContext(FlecksContext); const flecks = useContext(FlecksContext);
// Hack... force flecks update on HMR. // Hack... force flecks update on HMR.
useEffect(() => { useEffect(() => {
if (!flecks.hooks['@flecks/core/hmr']) { if (!flecks.hooks['@flecks/core.hmr']) {
flecks.hooks['@flecks/core/hmr'] = []; flecks.hooks['@flecks/core.hmr'] = [];
} }
flecks.hooks['@flecks/core/hmr'].push({ flecks.hooks['@flecks/core.hmr'].push({
plugin: '@flecks/react/hmr', plugin: '@flecks/react/hmr',
fn: () => { fn: () => {
setId(Math.random()); setId(Math.random());

View File

@ -15,8 +15,7 @@ export {default as usePrevious} from './hooks/use-previous';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
providers: ['...'],
ssr: true, ssr: true,
}), }),
}, },

View File

@ -7,9 +7,9 @@ import FlecksContext from '@flecks/react/context';
const debug = D('@flecks/react/root'); const debug = D('@flecks/react/root');
export default async (flecks, req) => { export default async (flecks, req) => {
const Roots = flecks.invoke('@flecks/react/roots', req); const Roots = flecks.invoke('@flecks/react.roots', req);
debug('roots: %O', Object.keys(Roots)); debug('roots: %O', Object.keys(Roots));
const Providers = await flecks.invokeSequentialAsync('@flecks/react/providers', req); const Providers = await flecks.invokeSequentialAsync('@flecks/react.providers', req);
const FlattenedProviders = []; const FlattenedProviders = [];
for (let i = 0; i < Providers.length; i++) { for (let i = 0; i < Providers.length; i++) {
const Provider = Providers[i]; const Provider = Providers[i];

View File

@ -6,7 +6,7 @@ import {HistoryRouter as ReduxHistoryRouter} from 'redux-first-history/rr6';
export default { export default {
[Hooks]: { [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.get('$flecks/redux/store'))}]
: [HistoryRouter, {history}] : [HistoryRouter, {history}]

View File

@ -7,10 +7,10 @@ export * from 'redux-first-history';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/redux/slices': () => ({ '@flecks/redux.slices': () => ({
router: routerReducer, router: routerReducer,
}), }),
'@flecks/redux/store': (options) => { '@flecks/redux.store': (options) => {
options.middleware.push(routerMiddleware); options.middleware.push(routerMiddleware);
}, },
}, },

View File

@ -3,7 +3,7 @@ import {StaticRouter} from 'react-router-dom/server';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/react/providers': (req, flecks) => ( '@flecks/react.providers': (req, flecks) => (
flecks.get('@flecks/react.ssr') ? [StaticRouter, {location: req.url}] : [] flecks.get('@flecks/react.ssr') ? [StaticRouter, {location: req.url}] : []
), ),
}, },

View File

@ -5,7 +5,7 @@ import ssr from './ssr';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/http/server/compiler': (flecks) => ( '@flecks/http/server.compiler': (flecks) => (
react({ react({
clean: false, clean: false,
hot: false, hot: false,
@ -23,7 +23,7 @@ export default {
}, },
}) })
), ),
'@flecks/http/server/stream.html': (stream, req, flecks) => ( '@flecks/http/server.stream.html': (stream, req, flecks) => (
flecks.get('@flecks/react.ssr') ? ssr(stream, req, flecks) : stream flecks.get('@flecks/react.ssr') ? ssr(stream, req, flecks) : stream
), ),
}, },

View File

@ -29,12 +29,12 @@ export const keys = (client, pattern) => safeKeys(client, pattern, 0);
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
host: 'localhost', host: 'localhost',
port: 6379, port: 6379,
}), }),
'@flecks/docker/containers': containers, '@flecks/docker.containers': containers,
'@flecks/repl/context': (flecks) => ({ '@flecks/repl.context': (flecks) => ({
redisClient: createClient(flecks), redisClient: createClient(flecks),
}), }),
}, },

View File

@ -11,14 +11,14 @@ const RedisStore = ConnectRedis(session);
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/user/session': async (flecks) => { '@flecks/user.session': async (flecks) => {
const client = createClient(flecks, {legacyMode: true}); const client = createClient(flecks, {legacyMode: true});
await client.connect(); await client.connect();
return { return {
store: new RedisStore({client}), store: new RedisStore({client}),
}; };
}, },
'@flecks/socket/server': async (flecks) => { '@flecks/socket.server': async (flecks) => {
const pubClient = createClient(flecks); const pubClient = createClient(flecks);
const subClient = createClient(flecks); const subClient = createClient(flecks);
await Promise.all([pubClient.connect(), subClient.connect()]); await Promise.all([pubClient.connect(), subClient.connect()]);

View File

@ -5,7 +5,7 @@ export default {
/** /**
* Define side-effects to run against Redux actions. * Define side-effects to run against Redux actions.
*/ */
'@flecks/redux/effects': () => ({ '@flecks/redux.effects': () => ({
someActionName: (store, action, flecks) => { someActionName: (store, action, flecks) => {
// Runs when `someActionName` actions are dispatched. // Runs when `someActionName` actions are dispatched.
}, },
@ -13,7 +13,7 @@ export default {
/** /**
* Define root-level reducers for the Redux store. * Define root-level reducers for the Redux store.
*/ */
'@flecks/redux/reducers': () => { '@flecks/redux.reducers': () => {
return (state, action) => { return (state, action) => {
// Whatever you'd like. // Whatever you'd like.
return state; return state;
@ -24,7 +24,7 @@ export default {
* *
* See: https://redux-toolkit.js.org/api/createSlice * See: https://redux-toolkit.js.org/api/createSlice
*/ */
'@flecks/redux/slices': () => { '@flecks/redux.slices': () => {
const something = createSlice( const something = createSlice(
// ... // ...
); );
@ -36,7 +36,7 @@ export default {
* Modify Redux store configuration. * Modify Redux store configuration.
* @param {Object} options A mutable object with keys for enhancers and middleware. * @param {Object} options A mutable object with keys for enhancers and middleware.
*/ */
'@flecks/redux/store': (options) => { '@flecks/redux.store': (options) => {
options.enhancers.splice(someIndex, 1); options.enhancers.splice(someIndex, 1);
options.middleware.push(mySpecialMiddleware); options.middleware.push(mySpecialMiddleware);
}, },

View File

@ -4,4 +4,4 @@ export const hydrateServer = createAction('@flecks/redux/hydrate.server');
export const hydrateLocalStorage = createAction('@flecks/redux/hydrate.localStorage'); export const hydrateLocalStorage = createAction('@flecks/redux/hydrate.localStorage');
export const storeLocalStorage = createAction('@flecks/redux/store.localStorage'); export const storeLocalStorage = createAction('@flecks/redux.store.localStorage');

View File

@ -6,8 +6,8 @@ import localStorageEnhancer from './local-storage';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/react/providers': async (req, flecks) => { '@flecks/react.providers': async (req, flecks) => {
const slices = await ensureUniqueReduction(flecks, '@flecks/redux/slices'); const slices = await ensureUniqueReduction(flecks, '@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');
@ -15,11 +15,11 @@ export default {
flecks.set('$flecks/redux/store', store); flecks.set('$flecks/redux/store', store);
return [Provider, {store}]; return [Provider, {store}];
}, },
'@flecks/redux/store': ({enhancers}) => { '@flecks/redux.store': ({enhancers}) => {
// Hydrate from and subscribe to localStorage. // Hydrate from and subscribe to localStorage.
enhancers.push(localStorageEnhancer); enhancers.push(localStorageEnhancer);
}, },
'@flecks/socket/packets.decorate': ( '@flecks/socket.packets.decorate': (
Flecks.decorate(require.context('./packets/decorators', false, /\.js$/)) Flecks.decorate(require.context('./packets/decorators', false, /\.js$/))
), ),
}, },

View File

@ -7,6 +7,6 @@ export * from './actions';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/socket/packets': Flecks.provide(require.context('./packets', false, /\.js$/)), '@flecks/socket.packets': Flecks.provide(require.context('./packets', false, /\.js$/)),
}, },
}; };

View File

@ -9,8 +9,8 @@ const debug = D('@flecks/redux/server');
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/http/server/request.route': (flecks) => async (req, res, next) => { '@flecks/http/server.request.route': (flecks) => async (req, res, next) => {
const slices = await ensureUniqueReduction(flecks, '@flecks/redux/slices'); const slices = await ensureUniqueReduction(flecks, '@flecks/redux.slices');
const reducer = createReducer(flecks, slices); const reducer = createReducer(flecks, slices);
const preloadedState = reducer(undefined, hydrateServer({flecks, req})); const preloadedState = reducer(undefined, hydrateServer({flecks, req}));
debug( debug(
@ -21,11 +21,11 @@ export default {
req.redux = await configureStore(flecks, reducer, {preloadedState}); req.redux = await configureStore(flecks, reducer, {preloadedState});
next(); next();
}, },
'@flecks/http/config': async (req) => ({ '@flecks/http.config': async (req) => ({
'@flecks/redux/client': { '@flecks/redux/client': {
preloadedState: req.redux.getState(), preloadedState: req.redux.getState(),
}, },
}), }),
'@flecks/react/providers': (req) => [Provider, {store: req.redux}], '@flecks/react.providers': (req) => [Provider, {store: req.redux}],
}, },
}; };

View File

@ -2,7 +2,7 @@ import {combineReducers} from '@reduxjs/toolkit';
import reduceReducers from 'reduce-reducers'; import reduceReducers from 'reduce-reducers';
export default (flecks, slices) => { export default (flecks, slices) => {
let reducers = flecks.invokeFlat('@flecks/redux/reducers'); let reducers = flecks.invokeFlat('@flecks/redux.reducers');
if (Object.keys(slices).length > 0) { if (Object.keys(slices).length > 0) {
reducers = reducers.concat(combineReducers(slices)); reducers = reducers.concat(combineReducers(slices));
} }

View File

@ -14,7 +14,7 @@ export default async function configureStore(flecks, reducer, {preloadedState})
effectsMiddleware(flecks), effectsMiddleware(flecks),
], ],
}; };
flecks.invokeFlat('@flecks/redux/store', options); flecks.invokeFlat('@flecks/redux.store', options);
return configureStoreR({ return configureStoreR({
enhancers: (defaultEnhancers) => { enhancers: (defaultEnhancers) => {
const index = options.enhancers.indexOf('@flecks/redux/defaultEnhancers'); const index = options.enhancers.indexOf('@flecks/redux/defaultEnhancers');

View File

@ -1,5 +1,5 @@
export default (flecks) => { export default (flecks) => {
const effects = flecks.invokeFlat('@flecks/redux/effects'); const effects = flecks.invokeFlat('@flecks/redux.effects');
const effect = (store, action) => { const effect = (store, action) => {
effects.forEach((map) => { effects.forEach((map) => {
if (map[action.type]) { if (map[action.type]) {

View File

@ -7,7 +7,7 @@ export default {
* *
* Note: commands will be prefixed with a period in the Node REPL. * Note: commands will be prefixed with a period in the Node REPL.
*/ */
'@flecks/repl/commands': () => ({ '@flecks/repl.commands': () => ({
someCommand: (...args) => { someCommand: (...args) => {
// args are passed from the Node REPL. So, you could invoke it like: // args are passed from the Node REPL. So, you could invoke it like:
// .someCommand foo bar // .someCommand foo bar
@ -17,7 +17,7 @@ export default {
/** /**
* Provide global context to the REPL. * Provide global context to the REPL.
*/ */
'@flecks/repl/context': () => { '@flecks/repl.context': () => {
// Now you'd be able to do like: // Now you'd be able to do like:
// `node> someValue;` // `node> someValue;`
// and the REPL would evaluate it to `'foobar'`. // and the REPL would evaluate it to `'foobar'`.

View File

@ -10,7 +10,7 @@ const debug = D('@flecks/repl');
export async function createReplServer(flecks) { export async function createReplServer(flecks) {
const {id} = flecks.get('@flecks/core'); const {id} = flecks.get('@flecks/core');
const context = flecks.invokeFlat('@flecks/repl/context') const context = flecks.invokeFlat('@flecks/repl.context')
.reduce((r, vars) => ({...r, ...vars}), {flecks}); .reduce((r, vars) => ({...r, ...vars}), {flecks});
debug( debug(
'context = %O', 'context = %O',
@ -18,7 +18,7 @@ export async function createReplServer(flecks) {
); );
const commands = {}; const commands = {};
Object.entries( Object.entries(
flecks.invokeFlat('@flecks/repl/commands').reduce((r, commands) => ({...r, ...commands}), {}), flecks.invokeFlat('@flecks/repl.commands').reduce((r, commands) => ({...r, ...commands}), {}),
).forEach(([key, value]) => { ).forEach(([key, value]) => {
commands[key] = value; commands[key] = value;
debug('registered command: %s', key); debug('registered command: %s', key);

View File

@ -5,7 +5,7 @@ import {createReplServer} from './repl';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/commands': commands, '@flecks/core.commands': commands,
'@flecks/server/up': (flecks) => createReplServer(flecks), '@flecks/server.up': (flecks) => createReplServer(flecks),
}, },
}; };

View File

@ -5,13 +5,13 @@ export default {
/** /**
* Define neutrino compilation middleware (e.g. @neutrinojs/react). * Define neutrino compilation middleware (e.g. @neutrinojs/react).
*/ */
'@flecks/server/compiler': () => { '@flecks/server.compiler': () => {
return require('@neutrinojs/node'); return require('@neutrinojs/node');
}, },
/** /**
* Define sequential actions to run when the server comes up. * Define sequential actions to run when the server comes up.
*/ */
'@flecks/server/up': async () => { '@flecks/server.up': async () => {
await youCanDoAsyncThingsHere(); await youCanDoAsyncThingsHere();
}, },
}, },

View File

@ -24,7 +24,7 @@ const {version} = require('../package.json');
const flecks = new Flecks(runtime); const flecks = new Flecks(runtime);
global.flecks = flecks; global.flecks = flecks;
try { try {
await flecks.up('@flecks/server/up'); await flecks.up('@flecks/server.up');
debug('up!'); debug('up!');
} }
catch (error) { catch (error) {

View File

@ -2,12 +2,11 @@ import {Hooks} from '@flecks/core';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
hot: false, hot: false,
inspect: false, inspect: false,
profile: false, profile: false,
start: false, start: false,
up: ['...'],
}), }),
}, },
}; };

View File

@ -44,7 +44,7 @@ module.exports = async (flecks) => {
paths.forEach((path) => { paths.forEach((path) => {
source.push(` module.hot.accept('${path}', async () => {`); source.push(` module.hot.accept('${path}', async () => {`);
source.push(` global.flecks.refresh('${path}', require('${path}'));`); source.push(` global.flecks.refresh('${path}', require('${path}'));`);
source.push(` global.flecks.invoke('@flecks/core/hmr', '${path}');`); source.push(` global.flecks.invoke('@flecks/core.hmr', '${path}');`);
source.push(' });'); source.push(' });');
}); });
source.push('}'); source.push('}');

View File

@ -64,7 +64,7 @@ module.exports = (async () => {
}; };
const compiler = flecks.invokeFleck( const compiler = flecks.invokeFleck(
'@flecks/server/compiler', '@flecks/server.compiler',
flecks.get('@flecks/server.compiler'), flecks.get('@flecks/server.compiler'),
); );

View File

@ -2,6 +2,6 @@ import {Hooks} from '@flecks/core';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/targets': () => ['server'], '@flecks/core.targets': () => ['server'],
}, },
}; };

View File

@ -7,13 +7,13 @@ export default {
* *
* See: https://socket.io/docs/v4/client-options/ * See: https://socket.io/docs/v4/client-options/
*/ */
'@flecks/socket/client': () => ({ '@flecks/socket.client': () => ({
timeout: Infinity, timeout: Infinity,
}), }),
/** /**
* Define server-side intercom channels. * Define server-side intercom channels.
*/ */
'@flecks/socket/intercom': (req) => ({ '@flecks/socket.intercom': (req) => ({
// This would have been called like: // This would have been called like:
// `const result = await req.intercom('someChannel', payload)`. // `const result = await req.intercom('someChannel', payload)`.
// `result` will be an `n`-length array, where `n` is the number of server instances. Each // `result` will be an `n`-length array, where `n` is the number of server instances. Each
@ -33,7 +33,7 @@ export default {
* See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/packet.js * See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/packet.js
* See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/redirect.js * See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/redirect.js
*/ */
'@flecks/socket/packets': Flecks.provide(require.context('./packets', false, /\.js$/)), '@flecks/socket.packets': Flecks.provide(require.context('./packets', false, /\.js$/)),
/** /**
* Decorate database models. * Decorate database models.
* *
@ -41,7 +41,7 @@ export default {
* decorator would be defined in its own file. * decorator would be defined in its own file.
* @param {constructor} Packet The packet to decorate. * @param {constructor} Packet The packet to decorate.
*/ */
'@flecks/socket/packets.decorate': ( '@flecks/socket.packets.decorate': (
Flecks.decorate(require.context('./packets/decorators', false, /\.js$/)) Flecks.decorate(require.context('./packets/decorators', false, /\.js$/))
), ),
@ -50,13 +50,13 @@ export default {
* *
* See: https://socket.io/docs/v4/server-options/ * See: https://socket.io/docs/v4/server-options/
*/ */
'@flecks/socket/server': () => ({ '@flecks/socket.server': () => ({
pingTimeout: Infinity, pingTimeout: Infinity,
}), }),
/** /**
* Define middleware to run when a socket connection is established. * Define middleware to run when a socket connection is established.
*/ */
'@flecks/socket/server/request.socket': () => (socket, next) => { '@flecks/socket/server.request.socket': () => (socket, next) => {
// Express-style route middleware... // Express-style route middleware...
next(); next();
}, },

View File

@ -4,13 +4,13 @@ import SocketClient from './socket';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/http/client/up': (flecks) => { '@flecks/http/client.up': (flecks) => {
const socket = new SocketClient(flecks); const socket = new SocketClient(flecks);
flecks.set('$flecks/socket.socket', socket); flecks.set('$flecks/socket.socket', socket);
socket.connect(); socket.connect();
socket.listen(); socket.listen();
}, },
'@flecks/socket/client': ({config: {'@flecks/core': {id}}}) => ({ '@flecks/socket.client': ({config: {'@flecks/core': {id}}}) => ({
cors: { cors: {
origin: false, origin: false,
}, },

View File

@ -30,7 +30,7 @@ export default class SocketClient extends decorate(Socket) {
{ {
reconnectionDelay: 'production' === process.env.NODE_ENV ? 1000 : 100, reconnectionDelay: 'production' === process.env.NODE_ENV ? 1000 : 100,
reconnectionDelayMax: 'production' === process.env.NODE_ENV ? 5000 : 500, reconnectionDelayMax: 'production' === process.env.NODE_ENV ? 5000 : 500,
...this.flecks.invokeMerge('@flecks/socket/client'), ...this.flecks.invokeMerge('@flecks/socket.client'),
}, },
); );
this.socket.emitPromise = promisify(this.socket.emit.bind(this.socket)); this.socket.emitPromise = promisify(this.socket.emit.bind(this.socket));

View File

@ -10,16 +10,13 @@ export {default as Packet, Packer, ValidationError} from './packet';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.starting': (flecks) => {
'packets.decorate': ['...'],
}),
'@flecks/core/starting': (flecks) => {
flecks.set('$flecks/socket.packets', flecks.gather( flecks.set('$flecks/socket.packets', flecks.gather(
'@flecks/socket/packets', '@flecks/socket.packets',
{check: badPacketsCheck}, {check: badPacketsCheck},
)); ));
}, },
'@flecks/http/config': async ( '@flecks/http.config': async (
req, req,
{config: {'@flecks/socket': {'packets.decorate': decorators}}}, {config: {'@flecks/socket': {'packets.decorate': decorators}}},
) => ({ ) => ({
@ -29,7 +26,7 @@ export default {
), ),
}, },
}), }),
'@flecks/socket/packets': (flecks) => ({ '@flecks/socket.packets': (flecks) => ({
Bundle: Bundle(flecks), Bundle: Bundle(flecks),
Redirect, Redirect,
Refresh, Refresh,

View File

@ -7,7 +7,7 @@ export default function createIntercom(sockets, transport) {
debug('@flecks/socket.s: %s(%o)', transport, type, payload); debug('@flecks/socket.s: %s(%o)', transport, type, payload);
const responses = await new Promise((resolve, reject) => { const responses = await new Promise((resolve, reject) => {
sockets.io.serverSideEmit( sockets.io.serverSideEmit(
'@flecks/socket/intercom', '@flecks/socket.intercom',
{payload, type}, {payload, type},
(error, responses) => (error ? reject(error) : resolve(responses)), (error, responses) => (error ? reject(error) : resolve(responses)),
); );

View File

@ -5,24 +5,24 @@ import Sockets from './sockets';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
connect: [], connect: [],
'request.socket': [], 'request.socket': [],
}), }),
'@flecks/http/server/request.socket': ({config: {'$flecks/socket.sockets': sockets}}) => (req, res, next) => { '@flecks/http/server.request.socket': ({config: {'$flecks/socket.sockets': sockets}}) => (req, res, next) => {
req.intercom = createIntercom(sockets, 'http'); req.intercom = createIntercom(sockets, 'http');
next(); next();
}, },
'@flecks/http/server/up': async (httpServer, flecks) => { '@flecks/http/server.up': async (httpServer, flecks) => {
const sockets = new Sockets(httpServer, flecks); const sockets = new Sockets(httpServer, flecks);
await sockets.connect(); await sockets.connect();
flecks.set('$flecks/socket.sockets', sockets); flecks.set('$flecks/socket.sockets', sockets);
}, },
'@flecks/repl/context': (flecks) => ({ '@flecks/repl.context': (flecks) => ({
Packets: flecks.get('$flecks/socket.packets'), Packets: flecks.get('$flecks/socket.packets'),
sockets: flecks.get('$flecks/socket.sockets'), sockets: flecks.get('$flecks/socket.sockets'),
}), }),
'@flecks/socket/server': ({config: {'@flecks/core': {id}}}) => ({ '@flecks/socket.server': ({config: {'@flecks/core': {id}}}) => ({
path: `/${id}/socket.io`, path: `/${id}/socket.io`,
}), }),
}, },

View File

@ -14,7 +14,7 @@ export default class SocketServer {
this.onConnect = this.onConnect.bind(this); this.onConnect = this.onConnect.bind(this);
this.flecks = flecks; this.flecks = flecks;
this.httpServer = httpServer; this.httpServer = httpServer;
const hooks = flecks.invokeMerge('@flecks/socket/intercom'); const hooks = flecks.invokeMerge('@flecks/socket.intercom');
debug('intercom hooks(%O)', hooks); debug('intercom hooks(%O)', hooks);
this.localIntercom = async ({payload, type}, fn) => { this.localIntercom = async ({payload, type}, fn) => {
debug('customHook: %s(%o)', type, payload); debug('customHook: %s(%o)', type, payload);
@ -31,13 +31,13 @@ export default class SocketServer {
async connect() { async connect() {
this.io = SocketIoServer(this.httpServer, { this.io = SocketIoServer(this.httpServer, {
...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.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);
this.io.on('connect', this.onConnect); this.io.on('connect', this.onConnect);
} }
@ -47,7 +47,7 @@ export default class SocketServer {
makeSocketMiddleware() { makeSocketMiddleware() {
const {app} = this.httpServer; const {app} = this.httpServer;
const middleware = this.flecks.makeMiddleware('@flecks/socket/server/request.socket'); const middleware = this.flecks.makeMiddleware('@flecks/socket/server.request.socket');
return async (socket, next) => { return async (socket, next) => {
Object.defineProperty(socket.handshake, 'ip', { Object.defineProperty(socket.handshake, 'ip', {
configurable: true, configurable: true,
@ -72,7 +72,7 @@ export default class SocketServer {
req.flecks = this.flecks; req.flecks = this.flecks;
req.intercom = createIntercom(this, 'socket'); req.intercom = createIntercom(this, 'socket');
req.sockets = this; req.sockets = this;
this.flecks.invokeSequentialAsync('@flecks/socket/server/connect', serverSocket); this.flecks.invokeSequentialAsync('@flecks/socket/server.connect', serverSocket);
} }
static send(flecks, nsp, packetOrDehydrated) { static send(flecks, nsp, packetOrDehydrated) {

View File

@ -7,7 +7,7 @@ export default {
* *
* See: https://www.npmjs.com/package/express-session * See: https://www.npmjs.com/package/express-session
*/ */
'@flecks/user/session': () => ({ '@flecks/user.session': () => ({
saveUninitialized: true, saveUninitialized: true,
}), }),
}, },

View File

@ -10,11 +10,11 @@ export * from './state/users';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/redux/slices': () => ({ '@flecks/redux.slices': () => ({
user, user,
users, users,
}), }),
'@flecks/socket/packets': (flecks) => ({ '@flecks/socket.packets': (flecks) => ({
Logout: Logout(flecks), Logout: Logout(flecks),
}), }),
}, },

View File

@ -6,14 +6,14 @@ import LocalStrategy from 'passport-local';
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
failureRedirect: '/', failureRedirect: '/',
successRedirect: '/', successRedirect: '/',
}), }),
'@flecks/db/server/models.decorate': ( '@flecks/db/server.models.decorate': (
Flecks.decorate(require.context('./models/decorators', false, /\.js$/)) Flecks.decorate(require.context('./models/decorators', false, /\.js$/))
), ),
'@flecks/http/routes': (flecks) => { '@flecks/http.routes': (flecks) => {
const {failureRedirect, successRedirect} = flecks.get('@flecks/user/local/server'); const {failureRedirect, successRedirect} = flecks.get('@flecks/user/local/server');
return [ return [
{ {
@ -23,7 +23,7 @@ export default {
}, },
]; ];
}, },
'@flecks/repl/commands': (flecks) => { '@flecks/repl.commands': (flecks) => {
const {User} = flecks.get('$flecks/db.models'); const {User} = flecks.get('$flecks/db.models');
return { return {
createUser: async (spec) => { createUser: async (spec) => {
@ -45,7 +45,7 @@ export default {
}, },
}; };
}, },
'@flecks/server/up': (flecks) => { '@flecks/server.up': (flecks) => {
passport.use(new LocalStrategy( passport.use(new LocalStrategy(
{usernameField: 'email'}, {usernameField: 'email'},
async (email, password, fn) => { async (email, password, fn) => {

View File

@ -6,11 +6,11 @@ const debug = D('@flecks/user/passport');
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/db/server/models': Flecks.provide(require.context('./models', false, /\.js$/)), '@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
'@flecks/http/server/request.route': (flecks) => (req, res, next) => { '@flecks/http/server.request.route': (flecks) => (req, res, next) => {
debug('@flecks/http/server/request.route: passport.initialize()'); debug('@flecks/http/server.request.route: passport.initialize()');
passport.initialize()(req, res, () => { passport.initialize()(req, res, () => {
debug('@flecks/http/server/request.route: passport.session()'); debug('@flecks/http/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.get('$flecks/db.models');
@ -21,7 +21,7 @@ export default {
}); });
}); });
}, },
'@flecks/http/routes': () => [ '@flecks/http.routes': () => [
{ {
method: 'get', method: 'get',
path: '/auth/logout', path: '/auth/logout',
@ -31,7 +31,7 @@ export default {
}, },
}, },
], ],
'@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.get('$flecks/db.models');
@ -43,7 +43,7 @@ export default {
} }
}); });
}, },
'@flecks/socket/intercom': () => ({ '@flecks/socket.intercom': () => ({
'@flecks/user/users': async (sids, server) => { '@flecks/user/users': async (sids, server) => {
const sockets = await server.sockets(); const sockets = await server.sockets();
return sids return sids
@ -57,10 +57,10 @@ export default {
); );
}, },
}), }),
'@flecks/socket/server/request.socket': (flecks) => (socket, next) => { '@flecks/socket/server.request.socket': (flecks) => (socket, next) => {
debug('@flecks/socket/server/request.socket: passport.initialize()'); debug('@flecks/socket/server.request.socket: passport.initialize()');
passport.initialize()(socket.handshake, undefined, () => { passport.initialize()(socket.handshake, undefined, () => {
debug('@flecks/socket/server/request.socket: passport.session()'); debug('@flecks/socket/server.request.socket: passport.session()');
passport.session()(socket.handshake, undefined, async () => { passport.session()(socket.handshake, undefined, async () => {
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
if (!socket.handshake.user) { if (!socket.handshake.user) {

View File

@ -6,21 +6,21 @@ const debug = D('@flecks/user/session');
export default { export default {
[Hooks]: { [Hooks]: {
'@flecks/core/config': () => ({ '@flecks/core.config': () => ({
cookieSecret: ( cookieSecret: (
'Set the FLECKS_ENV_FLECKS_USER_SESSION_SERVER_cookieSecret environment variable!' 'Set the FLECKS_ENV_FLECKS_USER_SESSION_SERVER_cookieSecret environment variable!'
), ),
}), }),
'@flecks/http/server/request.route': (flecks) => { '@flecks/http/server.request.route': (flecks) => {
const urle = express.urlencoded({extended: true}); const urle = express.urlencoded({extended: true});
return (req, res, next) => { return (req, res, next) => {
debug('@flecks/http/server/request.route: express.urlencoded()'); debug('@flecks/http/server.request.route: express.urlencoded()');
urle(req, res, (error) => { urle(req, res, (error) => {
if (error) { if (error) {
next(error); next(error);
return; return;
} }
debug('@flecks/http/server/request.route: session()'); debug('@flecks/http/server.request.route: session()');
flecks.get('$flecks/user.session')(req, res, (error) => { flecks.get('$flecks/user.session')(req, res, (error) => {
if (error) { if (error) {
next(error); next(error);
@ -32,17 +32,17 @@ export default {
}); });
}; };
}, },
'@flecks/server/up': async (flecks) => { '@flecks/server.up': async (flecks) => {
flecks.set('$flecks/user.session', expressSession({ flecks.set('$flecks/user.session', expressSession({
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) => {
debug('@flecks/socket/server/request.socket: session()'); debug('@flecks/socket/server.request.socket: session()');
flecks.get('$flecks/user.session')(socket.handshake, {}, () => { flecks.get('$flecks/user.session')(socket.handshake, {}, () => {
const id = socket.handshake.session?.id; const id = socket.handshake.session?.id;
socket.join(id); socket.join(id);