Add svelte as a view engine to swaf #33
@ -10,9 +10,11 @@ module.exports = {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: [
|
||||
'./tsconfig.json',
|
||||
'./tsconfig.test.json',
|
||||
'./tsconfig.frontend.json',
|
||||
'./src/tsconfig.json',
|
||||
'./src/common/tsconfig.json',
|
||||
'./src/assets/ts/tsconfig.json',
|
||||
'./src/assets/views/tsconfig.json',
|
||||
]
|
||||
},
|
||||
extends: [
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,8 +1,10 @@
|
||||
.idea
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
intermediates
|
||||
public
|
||||
yarn-error.log
|
||||
|
||||
config/local.*
|
||||
|
||||
tsconfig.tsbuildinfo
|
||||
|
@ -1,112 +0,0 @@
|
||||
{% extends 'layouts/base.njk' %}
|
||||
{% import 'macros.njk' as macros %}
|
||||
|
||||
{% set title = 'Authentication / Registration' %}
|
||||
{% set decription = 'Join ' + app.name + ' and share your files!' %}
|
||||
{% set h1 = 'Authentication and registration' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
{% set queryStr = '' %}
|
||||
{% set previousUrl = getPreviousUrl() %}
|
||||
{% if query.redirect_uri | length %}
|
||||
{% set queryStr = '?' + querystring.stringify({redirect_uri: query.redirect_uri}) %}
|
||||
{% elif previousUrl | length %}
|
||||
{% set queryStr = '?' + querystring.stringify({redirect_uri: previousUrl}) %}
|
||||
{% endif %}
|
||||
|
||||
<section class="panel">
|
||||
<h2><i data-feather="log-in"></i> Log in</h2>
|
||||
|
||||
{{ setFormPrefix('login-') }}
|
||||
<form action="{{ route('login') + queryStr }}" method="POST" id="login-form">
|
||||
{{ macros.field(_locals, 'text', 'identifier', query.identifier or '', 'Your email address or username', null, 'required') }}
|
||||
|
||||
{{ macros.field(_locals, 'password', 'password', null, 'Your password', 'Do not fill to log in via magic link.') }}
|
||||
|
||||
{{ macros.field(_locals, 'checkbox', 'persist_session', null, 'Stay logged in on this computer.') }}
|
||||
|
||||
<button type="submit">Authenticate</button>
|
||||
|
||||
{{ macros.csrf(getCsrfToken) }}
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2><i data-feather="user-plus"></i> Register</h2>
|
||||
|
||||
{{ setFormPrefix('register-') }}
|
||||
<form action="{{ route('register') + queryStr }}" method="POST" id="register-form">
|
||||
<input type="hidden" name="auth_method" value="magic_link">
|
||||
{{ macros.csrf(getCsrfToken) }}
|
||||
|
||||
{% if has_username %}
|
||||
{{ macros.field(_locals, 'text', 'name', null, 'Choose your username', 'This cannot be changed later.', 'pattern="[0-9a-z_-]+" required') }}
|
||||
{% endif %}
|
||||
|
||||
<div id="register-magic_link_method_fields">
|
||||
{{ macros.field(_locals, 'email', 'identifier', null, 'Your email address', null, 'required') }}
|
||||
<a href="javascript: void(0);">Use password instead</a>
|
||||
</div>
|
||||
|
||||
<div id="register-password_method_fields" class="hidden">
|
||||
{{ macros.field(_locals, 'password', 'password', null, 'Choose a password', null, 'required disabled') }}
|
||||
{{ macros.field(_locals, 'password', 'password_confirmation', null, 'Confirm your password', null, 'required disabled') }}
|
||||
<a href="javascript: void(0);">Use email address instead</a>
|
||||
</div>
|
||||
|
||||
{{ macros.field(_locals, 'checkbox', 'terms', null, 'I accept the <a href="/terms-of-services" target="_blank">Terms Of Services</a>.' | safe, null, 'required') }}
|
||||
|
||||
<button type="submit" class="primary">Register</button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Register form dynamics
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('register-form');
|
||||
const authMethodField = form.querySelector('input[name=auth_method]');
|
||||
const usernameField = form.querySelector('input[name=name]');
|
||||
const magicLinkFields = document.getElementById('register-magic_link_method_fields');
|
||||
const passwordFields = document.getElementById('register-password_method_fields');
|
||||
|
||||
let switchToPassword;
|
||||
magicLinkFields.querySelector('a').addEventListener('click', switchToPassword = () => {
|
||||
authMethodField.value = 'password';
|
||||
usernameField.name = 'identifier';
|
||||
|
||||
magicLinkFields.classList.add('hidden');
|
||||
magicLinkFields.querySelectorAll('input').forEach(el => {
|
||||
el.disabled = true;
|
||||
});
|
||||
|
||||
passwordFields.classList.remove('hidden');
|
||||
passwordFields.querySelectorAll('input').forEach(el => {
|
||||
el.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
passwordFields.querySelector('a').addEventListener('click', () => {
|
||||
authMethodField.value = 'magic_link';
|
||||
usernameField.name = 'name';
|
||||
|
||||
magicLinkFields.classList.remove('hidden');
|
||||
magicLinkFields.querySelectorAll('input').forEach(el => {
|
||||
el.disabled = false;
|
||||
});
|
||||
|
||||
passwordFields.classList.add('hidden');
|
||||
passwordFields.querySelectorAll('input').forEach(el => {
|
||||
el.disabled = true;
|
||||
});
|
||||
});
|
||||
|
||||
if (`{{ _locals.previousFormData()['auth_method'] | default('') }}` === 'password') {
|
||||
switchToPassword();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
@ -1,185 +0,0 @@
|
||||
{% macro message(type, content, raw=false, discreet=false) %}
|
||||
<div class="message{{ ' message-discreet' if discreet }}" data-type="{{ type }}">
|
||||
<i class="icon"></i>
|
||||
<span class="content">
|
||||
{{ content|safe if raw else content }}
|
||||
</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro messages(flash) %}
|
||||
{% set flashed = flash() %}
|
||||
{% set display = 0 %}
|
||||
|
||||
{% for type, bag in flashed %}
|
||||
{% if bag|length %}
|
||||
{% set display = 1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if display %}
|
||||
<div class="messages">
|
||||
{% for type, bag in flashed %}
|
||||
{% for content in bag %}
|
||||
{{ message(type, content) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro csrf(getCsrfToken) %}
|
||||
<input type="hidden" name="csrf" value="{{ getCsrfToken() }}">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro field(_locals, type, name, value, placeholder, hint, validation_attributes='', extraData='', icon=null) %}
|
||||
{% set validation = _locals.validation() %}
|
||||
{% set validation = validation[name] if validation[name] or null %}
|
||||
{% set previousFormData = _locals.previousFormData() %}
|
||||
{% set value = previousFormData[name] or value or validation.value or '' %}
|
||||
{% set prefix = _locals.getFormPrefix() | default('') %}
|
||||
|
||||
{% if type == 'hidden' %}
|
||||
{% if validation %}
|
||||
{{ message('error', validation.message) }}
|
||||
{% endif %}
|
||||
<input type="hidden" name="{{ name }}" value="{{ value }}">
|
||||
{% else %}
|
||||
<div class="form-field{{ ' inline' if type == 'checkbox' }}">
|
||||
<div class="control">
|
||||
{% if icon != null %}
|
||||
{% if icon.startsWith('fa') %}
|
||||
<i class="{{ icon }} feather icon"></i>
|
||||
{% else %}
|
||||
<i data-feather="{{ icon }}" class="icon"></i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if type == 'duration' %}
|
||||
<div class="input-group">
|
||||
{% for f in extraData %}
|
||||
<div class="time-input">
|
||||
{% if previousFormData[name] %}
|
||||
{% set v = value[f] %}
|
||||
{% else %}
|
||||
{% set v = (value % 60) if f == 's' else (((value - value % 60) / 60 % 60) if f == 'm' else ((value - value % 3600) / 3600 if f == 'h')) %}
|
||||
{% endif %}
|
||||
<input type="number" name="{{ name }}[{{ f }}]" id="field-{{ prefix }}{{ name }}-{{ f }}"
|
||||
value="{{ v }}"
|
||||
min="0" {{ 'max=60' if (f == 's' or f == 'm') }}
|
||||
{{ validation_attributes }}>
|
||||
<label for="field-{{ prefix }}{{ name }}-{{ f }}">{{ f }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% elseif type == 'select' %}
|
||||
<select name="{{ name }}" id="field-{{ prefix }}{{ name }}" {{ validation_attributes|safe }}>
|
||||
{% for option in extraData %}
|
||||
<option value="{% if option.display === undefined or option.value !== undefined %}{{ option.value | default(option) }}{% endif %}"
|
||||
{{ 'selected' if value == (option.value | default(option)) }}>{{ option.display | default(option) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<i data-feather="chevron-down"></i>
|
||||
{% elseif type == 'textarea' %}
|
||||
<textarea name="{{ name }}" id="field-{{ prefix }}{{ name }}"
|
||||
{{ validation_attributes|safe }} value="{{ value }}">{{ value }}</textarea>
|
||||
{% else %}
|
||||
<input type="{{ type }}" name="{{ name }}" id="field-{{ prefix }}{{ name }}"
|
||||
{% if type != 'checkbox' %} value="{{ value }}" {% endif %}
|
||||
{{ 'checked' if (type == 'checkbox' and value == 'on') }}
|
||||
{{ validation_attributes|safe }}>
|
||||
{% endif %}
|
||||
|
||||
<label for="field-{{ prefix }}{{ name }}{{ '-' + extraData[0] if type == 'duration' }}">{{ placeholder }}</label>
|
||||
</div>
|
||||
|
||||
{{ fieldError(_locals, name) }}
|
||||
{% if hint %}
|
||||
<div class="hint"><i data-feather="info"></i> {{ hint }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro fieldError(_locals, name) %}
|
||||
{% set validation = _locals.validation() %}
|
||||
{% set validation = validation[name] if validation[name] or null %}
|
||||
{% if validation %}
|
||||
<div class="error"><i data-feather="x-circle"></i> {{ validation.message }}</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro websocket(websocketUrl, listener, reconnectOnClose = 1, checkFunction = 0) %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
{% if checkFunction %}
|
||||
if (!{{ checkFunction }}()) return;
|
||||
{% endif %}
|
||||
|
||||
const run = () => {
|
||||
const websocket = new WebSocket('{{ websocketUrl }}');
|
||||
websocket.onopen = (e) => {
|
||||
console.debug('Websocket connected');
|
||||
};
|
||||
websocket.onmessage = (e) => {
|
||||
{{ listener }}(websocket, e);
|
||||
};
|
||||
websocket.onerror = (e) => {
|
||||
console.error('Websocket error', e);
|
||||
};
|
||||
websocket.onclose = (e) => {
|
||||
console.debug('Websocket closed', e.code, e.reason);
|
||||
|
||||
{% if reconnectOnClose %}
|
||||
setTimeout(run, 1000);
|
||||
{% endif %}
|
||||
};
|
||||
};
|
||||
|
||||
run();
|
||||
});
|
||||
</script>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro paginate(pagination, routeName, contextSize) %}
|
||||
{% if pagination.hasPrevious() or pagination.hasNext() %}
|
||||
<nav class="pagination">
|
||||
<ul>
|
||||
{% if pagination.hasPrevious() %}
|
||||
<li><a href="{{ route(routeName, {page: pagination.page - 1}) }}"><i data-feather="chevron-left"></i> Previous</a></li>
|
||||
{% for i in pagination.previousPages(contextSize) %}
|
||||
{% if i == -1 %}
|
||||
<li class="ellipsis">...</li>
|
||||
{% else %}
|
||||
<li><a href="{{ route(routeName, {page: i}) }}">{{ i }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<li class="active"><span>{{ pagination.page }}</span></li>
|
||||
|
||||
{% if pagination.hasNext() %}
|
||||
{% for i in pagination.nextPages(contextSize) %}
|
||||
{% if i == -1 %}
|
||||
<li class="ellipsis">...</li>
|
||||
{% else %}
|
||||
<li><a href="{{ route(routeName, {page: i}) }}">{{ i }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><a href="{{ route(routeName, {page: pagination.page + 1}) }}">Next <i data-feather="chevron-right"></i></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro breadcrumb(currentPageTitle, pages=[]) %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
{% for page in pages %}
|
||||
<li><a href="{{ page.link }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
<li class="active" aria-current="page">{{ currentPageTitle }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
{% endmacro %}
|
@ -1,57 +0,0 @@
|
||||
{% extends 'layouts/base.njk' %}
|
||||
|
||||
{% set h1 = 'Authentication lobby' %}
|
||||
{% set title = app.name + ' ' + h1 %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="panel">
|
||||
{{ macros.message('success', 'We sent a link to ' + email + '. To authenticate, open it from any device.') }}
|
||||
{{ macros.message('info', 'This link will be valid for <span id="countdown"></span> and can only be used once.', true, true) }}
|
||||
|
||||
<p class="center">Waiting for you to open the link...</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
const validUntil = {{ validUntil }}.0;
|
||||
|
||||
function isValid() {
|
||||
return new Date().getTime() < validUntil;
|
||||
}
|
||||
|
||||
function websocketListen(websocket, e) {
|
||||
if (e.data === 'refresh') {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const countdown = document.getElementById('countdown');
|
||||
|
||||
if (!isValid()) return;
|
||||
|
||||
function animateCountdown() {
|
||||
requestAnimationFrame(() => {
|
||||
let diff = Math.max(0, validUntil - new Date().getTime());
|
||||
if (diff === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
diff /= 1000;
|
||||
const seconds = Math.floor(diff % 60).toFixed(0);
|
||||
const minutes = Math.floor((diff - seconds) / 60).toFixed(0);
|
||||
|
||||
countdown.innerText = `${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||||
animateCountdown();
|
||||
});
|
||||
}
|
||||
|
||||
animateCountdown();
|
||||
});
|
||||
</script>
|
||||
|
||||
{{ macros.websocket(websocketUrl, 'websocketListen', 1, 'isValid') }}
|
||||
{% endblock %}
|
@ -17,10 +17,10 @@
|
||||
"test": "jest --verbose --runInBand",
|
||||
"clean": "node scripts/clean.js",
|
||||
"prepare-sources": "node scripts/prepare-sources.js",
|
||||
"compile": "yarn clean && tsc",
|
||||
"build": "yarn prepare-sources && yarn compile && node . pre-compile-views && node scripts/dist.js",
|
||||
"compile": "yarn clean && yarn prepare-sources && tsc --build",
|
||||
"build": "yarn compile && node . pre-compile-views && node scripts/dist.js",
|
||||
"build-production": "NODE_ENV=production yarn build",
|
||||
"dev": "yarn compile && yarn prepare-sources && concurrently -k -n \"Maildev,Typescript,ViewPreCompile,Node\" -p \"[{name}]\" -c \"yellow,blue,red,green\" \"maildev\" \"tsc --watch\" \"nodemon -i public -i build -- pre-compile-views --watch\" \"nodemon -i public -i build\"",
|
||||
"dev": "yarn compile && concurrently -k -n \"Maildev,Typescript,ViewPreCompile,Node\" -p \"[{name}]\" -c \"yellow,blue,red,green\" \"maildev\" \"tsc --build --watch\" \"nodemon -i public -i intermediates -- pre-compile-views --watch\" \"nodemon -i public -i intermediates\"",
|
||||
"lint": "eslint .",
|
||||
"release": "yarn build && yarn lint && yarn test && cd dist && yarn publish"
|
||||
},
|
||||
|
18
scripts/_functions.js
Normal file
18
scripts/_functions.js
Normal file
@ -0,0 +1,18 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export function copyRecursively(file, destination) {
|
||||
const target = path.join(destination, path.basename(file));
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
console.log('mkdir', target);
|
||||
|
||||
fs.mkdirSync(target, {recursive: true});
|
||||
fs.readdirSync(file).forEach(f => {
|
||||
copyRecursively(path.join(file, f), target);
|
||||
});
|
||||
} else {
|
||||
console.log('> cp ', target);
|
||||
|
||||
fs.copyFileSync(file, target);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import fs from "fs";
|
||||
|
||||
[
|
||||
'build',
|
||||
'intermediates',
|
||||
'dist',
|
||||
'public',
|
||||
].forEach(file => {
|
||||
|
@ -1,28 +1,12 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
function copyRecursively(file, destination) {
|
||||
const target = path.join(destination, path.basename(file));
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
console.log('mkdir', target);
|
||||
|
||||
fs.mkdirSync(target, {recursive: true});
|
||||
fs.readdirSync(file).forEach(f => {
|
||||
copyRecursively(path.join(file, f), target);
|
||||
});
|
||||
} else {
|
||||
console.log('> cp ', target);
|
||||
|
||||
fs.copyFileSync(file, target);
|
||||
}
|
||||
}
|
||||
import {copyRecursively} from "./_functions.js";
|
||||
|
||||
|
||||
[
|
||||
'yarn.lock',
|
||||
'README.md',
|
||||
'config/',
|
||||
'assets/',
|
||||
].forEach(file => {
|
||||
copyRecursively(file, 'dist');
|
||||
});
|
||||
|
@ -1,9 +1,24 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import {copyRecursively} from "./_functions.js";
|
||||
|
||||
// These folders must exist for nodemon not to loop indefinitely.
|
||||
[
|
||||
'build',
|
||||
'public',
|
||||
'dist',
|
||||
'intermediates',
|
||||
'intermediates/assets',
|
||||
].forEach(dir => {
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
||||
});
|
||||
|
||||
// Symlink to build/common
|
||||
const symlink = path.resolve('intermediates/common');
|
||||
if (!fs.existsSync(symlink)) {
|
||||
fs.symlinkSync(path.resolve('dist/common'), symlink);
|
||||
}
|
||||
|
||||
// Copy all source files
|
||||
fs.readdirSync('src').forEach(file => {
|
||||
copyRecursively(path.join('src', file), 'dist');
|
||||
});
|
||||
|
@ -84,7 +84,7 @@ export default class TestApp extends Application {
|
||||
this.use(new MaintenanceComponent());
|
||||
|
||||
// Dynamic views and routes
|
||||
const intermediateDirectory = 'build';
|
||||
const intermediateDirectory = 'intermediates/assets';
|
||||
this.use(new FrontendToolsComponent(
|
||||
new AssetCompiler(intermediateDirectory, 'public'),
|
||||
new CopyAssetPreCompiler(intermediateDirectory, '', 'json', ['test/assets'], false),
|
||||
@ -96,7 +96,7 @@ export default class TestApp extends Application {
|
||||
|
||||
// Services
|
||||
this.use(new MysqlComponent());
|
||||
this.use(new MailComponent(new MailViewEngine('build', 'test/assets')));
|
||||
this.use(new MailComponent(new MailViewEngine('intermediates/assets', 'test/assets')));
|
||||
|
||||
// Session
|
||||
this.use(new RedisComponent());
|
||||
|
@ -23,11 +23,11 @@
|
||||
</div>
|
||||
|
||||
{% if has_name_component %}
|
||||
{% include './name_panel.njk' %}
|
||||
{% include 'views/auth/account/name_panel.njk' %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_password_component %}
|
||||
{% include './password_panel.njk' %}
|
||||
{% include 'views/auth/account/password_panel.njk' %}
|
||||
{% endif %}
|
||||
|
||||
<section class="panel">
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {locals} from "../../ts/stores";
|
||||
import {locals} from "../../ts/stores.js";
|
||||
|
||||
const previousUrl = $locals.getPreviousUrl();
|
||||
|
@ -9,13 +9,11 @@
|
||||
import * as stores from '/js/stores.js';
|
||||
const localStore = stores[Object.keys(stores)[0]].locals;
|
||||
|
||||
const locals = %locals%;
|
||||
const localMap = %locals%;
|
||||
localStore.set((key, args) => {
|
||||
const localKey = args ?
|
||||
return localMap[args ?
|
||||
`'${key}', \`${args}\``
|
||||
: `'${key}'`;
|
||||
// console.debug(localKey + '=' + locals[localKey])
|
||||
return locals[localKey];
|
||||
: `'${key}'`];
|
||||
});
|
||||
|
||||
new View({
|
15
src/assets/views/tsconfig.json
Normal file
15
src/assets/views/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "public/js",
|
||||
"rootDir": "../../../intermediates/assets",
|
||||
},
|
||||
"include": [
|
||||
"src/assets/ts/**/*"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../common"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import config from "config";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
import Time from "../common/Time.js";
|
||||
import Controller from "../Controller.js";
|
||||
import ModelFactory from "../db/ModelFactory.js";
|
||||
import Validator, {EMAIL_REGEX, InvalidFormatValidationError} from "../db/Validator.js";
|
||||
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "../HttpError.js";
|
||||
import MailTemplate from "../mail/MailTemplate.js";
|
||||
import {ADD_EMAIL_MAIL_TEMPLATE, REMOVE_PASSWORD_MAIL_TEMPLATE} from "../Mails.js";
|
||||
import Time from "../Time.js";
|
||||
import {RequireAuthMiddleware} from "./AuthComponent.js";
|
||||
import AuthMagicLinkActionType from "./magic_link/AuthMagicLinkActionType.js";
|
||||
import MagicLinkController from "./magic_link/MagicLinkController.js";
|
||||
|
3
src/common/package.json
Normal file
3
src/common/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
20
src/common/tsconfig.json
Normal file
20
src/common/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
|
||||
"module": "CommonJS",
|
||||
|
||||
"baseUrl": "../../dist/common",
|
||||
"rootDir": "./",
|
||||
"sourceRoot": "./",
|
||||
"outDir": "../../dist/common",
|
||||
|
||||
"typeRoots": [
|
||||
"src/types"
|
||||
],
|
||||
},
|
||||
"include": [
|
||||
"./**/*"
|
||||
]
|
||||
}
|
@ -34,7 +34,7 @@ export default abstract class AssetPreCompiler {
|
||||
) {
|
||||
this.assetPaths = [
|
||||
...additionalFallbackAssetPaths,
|
||||
'assets',
|
||||
'src/assets',
|
||||
'node_modules/swaf/assets',
|
||||
].map(p => path.resolve(p, assetType))
|
||||
.filter(dir => existsSync(dir));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "../../node_modules/svelte/register.js";
|
||||
import "./register_svelte/register_svelte.js";
|
||||
|
||||
import clearModule from "clear-module";
|
||||
import config from "config";
|
||||
@ -176,7 +176,7 @@ export default class SvelteViewEngine extends ViewEngine {
|
||||
replacedBackendCalls.code,
|
||||
sveltePreprocess({
|
||||
typescript: {
|
||||
tsconfigFile: 'tsconfig.svelte.json',
|
||||
tsconfigFile: 'src/assets/views/tsconfig.json',
|
||||
},
|
||||
}),
|
||||
{
|
||||
@ -276,7 +276,7 @@ export default class SvelteViewEngine extends ViewEngine {
|
||||
});
|
||||
|
||||
// Load locals into locals store
|
||||
const localsModulePath = "../../build/ts/stores.js";
|
||||
const localsModulePath = "../../intermediates/assets/ts/stores.js";
|
||||
const localsModule = await import(localsModulePath);
|
||||
const locals = this.getGlobals().get();
|
||||
const localMap = this.compileBackendCalls(backendCalls, locals, true);
|
||||
|
@ -12,7 +12,7 @@ export default class TypeScriptPreCompiler extends CopyAssetPreCompiler {
|
||||
|
||||
this.onPreCompile(async _watch => {
|
||||
logger.info('Building ts assets...');
|
||||
await child_process.execSync(`yarn tsc -b tsconfig.frontend.json`, {stdio: [process.stdin, process.stdout, process.stderr]});
|
||||
await child_process.execSync(`yarn tsc -b src/assets/ts/tsconfig.json`, {stdio: [process.stdin, process.stdout, process.stderr]});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
3
src/frontend/register_svelte/package.json
Normal file
3
src/frontend/register_svelte/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
1
src/frontend/register_svelte/register_svelte.js
Normal file
1
src/frontend/register_svelte/register_svelte.js
Normal file
@ -0,0 +1 @@
|
||||
require("svelte/register");
|
27
src/tsconfig.json
Normal file
27
src/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
|
||||
"baseUrl": "../dist",
|
||||
"rootDir": "./",
|
||||
"sourceRoot": "./",
|
||||
"outDir": "../dist",
|
||||
|
||||
"typeRoots": [
|
||||
"src/types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"./assets/**/*",
|
||||
"./common/**/*"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./common"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "CommonJS",
|
||||
"baseUrl": "build",
|
||||
"rootDir": "build/ts-source",
|
||||
"sourceRoot": "build/ts-source",
|
||||
"outDir": "build/ts",
|
||||
"declaration": false,
|
||||
|
||||
"typeRoots": [],
|
||||
"resolveJsonModule": false
|
||||
},
|
||||
"include": [
|
||||
"build/ts-source/**/*"
|
||||
]
|
||||
}
|
@ -7,12 +7,11 @@
|
||||
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
"moduleResolution": "Node",
|
||||
"esModuleInterop": true,
|
||||
"baseUrl": "dist",
|
||||
"rootDir": "src",
|
||||
"sourceRoot": "src",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"outDir": "dist",
|
||||
@ -25,9 +24,19 @@
|
||||
"es2020"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "src",
|
||||
},
|
||||
{
|
||||
"path": "src/assets/ts",
|
||||
},
|
||||
{
|
||||
"path": "src/assets/views",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "public/js",
|
||||
"rootDir": "build",
|
||||
},
|
||||
"include": [
|
||||
"assets/ts/**/*"
|
||||
],
|
||||
}
|
Loading…
Reference in New Issue
Block a user