Working runtime with ESM compatibility. Now for the tests...
This commit is contained in:
parent
4a2baa8dcd
commit
46e70efcb3
2
package-lock.json
generated
2
package-lock.json
generated
@ -50,7 +50,7 @@
|
||||
"prettier": "^2.2.1",
|
||||
"ts-loader": "^8.0.14",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.1.3"
|
||||
"typescript": "^4.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=17.0.0"
|
||||
|
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "./dist/back/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "docker-compose up -d db && node .",
|
||||
"typecheck:back": "npx tsc --noEmit --target es6 --lib es2015,dom -p src/back",
|
||||
@ -32,7 +33,7 @@
|
||||
"@hotwired/turbo": "^7.1.0",
|
||||
"@koa/router": "^12.0.1",
|
||||
"@playwright/test": "^1.36.1",
|
||||
"@sealcode/sealgen": "^0.8.52",
|
||||
"@sealcode/sealgen": "^0.9.0",
|
||||
"@sealcode/ts-predicates": "^0.4.3",
|
||||
"@types/kill-port": "^2.0.0",
|
||||
"hint": "^7.0.1",
|
||||
@ -68,7 +69,7 @@
|
||||
"prettier": "^2.2.1",
|
||||
"ts-loader": "^8.0.14",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.1.3"
|
||||
"typescript": "^4.7"
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "@istanbuljs/nyc-config-typescript",
|
||||
|
@ -1,9 +1,10 @@
|
||||
import _locreq from "locreq";
|
||||
import { default as Sealious, App, LoggerMailer, SMTPMailer } from "sealious";
|
||||
import { LoggerLevel } from "sealious/@types/src/app/logger";
|
||||
import { collections } from "./collections/collections";
|
||||
import ADMIN_CREDENTIALS from "./default-admin-credentials";
|
||||
const locreq = _locreq(__dirname);
|
||||
import Sealious, { App, LoggerMailer, SMTPMailer } from "sealious";
|
||||
import type { LoggerLevel } from "sealious/@types/src/app/logger.js";
|
||||
import { collections } from "./collections/collections.js";
|
||||
import ADMIN_CREDENTIALS from "./default-admin-credentials.js";
|
||||
import { module_dirname } from "./util.js";
|
||||
const locreq = _locreq.default(module_dirname(import.meta.url));
|
||||
|
||||
const PORT = process.env.SEALIOUS_PORT ? parseInt(process.env.SEALIOUS_PORT) : 8080;
|
||||
const base_url = process.env.SEALIOUS_BASE_URL || `http://localhost:${PORT}`;
|
||||
|
@ -1,13 +1,13 @@
|
||||
// DO NOT EDIT! This file is generated automaticaly with 'npm run generate-collections'
|
||||
import { App } from "sealious";
|
||||
|
||||
import _GroupsToUsers from "./groups-to-users";
|
||||
import _Groups from "./groups";
|
||||
import _PasswordResetIntents from "./password-reset-intents";
|
||||
import _Secrets from "./secrets";
|
||||
import _Tasks from "./tasks";
|
||||
import _UserRoles from "./user-roles";
|
||||
import _Users from "./users";
|
||||
import _GroupsToUsers from "./groups-to-users.js";
|
||||
import _Groups from "./groups.js";
|
||||
import _PasswordResetIntents from "./password-reset-intents.js";
|
||||
import _Secrets from "./secrets.js";
|
||||
import _Tasks from "./tasks.js";
|
||||
import _UserRoles from "./user-roles.js";
|
||||
import _Users from "./users.js";
|
||||
|
||||
export const GroupsToUsers = new _GroupsToUsers();
|
||||
export const Groups = new _Groups();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Collection, FieldTypes, Policies } from "sealious";
|
||||
import { Roles } from "../policy-types/roles";
|
||||
import { Roles } from "../policy-types/roles.js";
|
||||
|
||||
export default class GroupsToUsers extends Collection {
|
||||
fields = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Collection, FieldTypes, Policies } from "sealious";
|
||||
import { Roles } from "../policy-types/roles";
|
||||
import { Roles } from "../policy-types/roles.js";
|
||||
|
||||
export default class Groups extends Collection {
|
||||
fields = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import assert from "assert";
|
||||
import TheApp from "../app";
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import TheApp from "../app.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
|
||||
describe("password-reset-intents", function () {
|
||||
//ts-ignore
|
||||
@ -18,7 +18,7 @@ describe("password-reset-intents", function () {
|
||||
return withProdApp(async ({ app, base_url }) => {
|
||||
const email = "fake@example.com";
|
||||
try {
|
||||
await axios.post(
|
||||
await axios.default.post(
|
||||
`${base_url}/api/v1/collections/password-reset-intents`,
|
||||
{
|
||||
email: email,
|
||||
@ -39,7 +39,7 @@ describe("password-reset-intents", function () {
|
||||
withProdApp(async ({ app, base_url }) => {
|
||||
await createAUser(app);
|
||||
const { email, token } = (
|
||||
await axios.post(
|
||||
await axios.default.post(
|
||||
`${base_url}/api/v1/collections/password-reset-intents`,
|
||||
{
|
||||
email: "user@example.com",
|
||||
@ -59,7 +59,7 @@ describe("password-reset-intents", function () {
|
||||
withProdApp(async ({ app, base_url }) => {
|
||||
const email = "incorrect-address";
|
||||
try {
|
||||
await axios.post(
|
||||
await axios.default.post(
|
||||
`${base_url}/api/v1/collections/password-reset-intents`,
|
||||
{
|
||||
email: email,
|
||||
@ -78,9 +78,12 @@ describe("password-reset-intents", function () {
|
||||
it("sends an email with the reset password link", async () =>
|
||||
withProdApp(async ({ app, base_url, mail_api }) => {
|
||||
await createAUser(app);
|
||||
await axios.post(`${base_url}/api/v1/collections/password-reset-intents`, {
|
||||
await axios.default.post(
|
||||
`${base_url}/api/v1/collections/password-reset-intents`,
|
||||
{
|
||||
email: "user@example.com",
|
||||
});
|
||||
}
|
||||
);
|
||||
const messages = (await mail_api.getMessages()).filter(
|
||||
(message) => message.recipients[0] == "<user@example.com>"
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { App, Collection, CollectionItem, Context, FieldTypes, Policies } from "sealious";
|
||||
import assert from "assert";
|
||||
import PasswordResetTemplate from "../email-templates/password-reset";
|
||||
import TheApp from "../app";
|
||||
import PasswordResetTemplate from "../email-templates/password-reset.js";
|
||||
import TheApp from "../app.js";
|
||||
import { assertType, predicates } from "@sealcode/ts-predicates";
|
||||
|
||||
export default class PasswordResetIntents extends Collection {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Collection, FieldTypes } from "sealious";
|
||||
import { Roles } from "../policy-types/roles";
|
||||
import { Roles } from "../policy-types/roles.js";
|
||||
|
||||
/* For testing the Roles policy */
|
||||
export default class Secrets extends Collection {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import assert from "assert";
|
||||
import axios from "axios";
|
||||
import { Context, TestUtils } from "sealious";
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { createAdmin, createAUser } from "../test_utils/users";
|
||||
import Users from "./users";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { createAdmin, createAUser } from "../test_utils/users.js";
|
||||
import Users from "./users.js";
|
||||
|
||||
describe("user-roles", () => {
|
||||
it("rejects when given an empty role", async () =>
|
||||
@ -31,7 +31,7 @@ describe("user-roles", () => {
|
||||
it("accepts correct dataset", async () =>
|
||||
withProdApp(async ({ app, base_url, rest_api }) => {
|
||||
const [user, session] = await createAdmin(app, rest_api);
|
||||
const response = await axios.post(
|
||||
const response = await axios.default.post(
|
||||
`${base_url}/api/v1/collections/user-roles`,
|
||||
{
|
||||
user: user.id,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { App, Collection, FieldTypes, Policies, Policy } from "sealious";
|
||||
import { Roles } from "../policy-types/roles";
|
||||
import { Roles } from "../policy-types/roles.js";
|
||||
|
||||
export default class UserRoles extends Collection {
|
||||
name = "user-roles";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { App, Collections, Context, FieldTypes, Policies } from "sealious";
|
||||
import assert from "assert";
|
||||
import TheApp from "../app";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials";
|
||||
import TheApp from "../app.js";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials.js";
|
||||
|
||||
export default class Users extends Collections.users {
|
||||
fields = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EmailTemplates, Errors } from "sealious";
|
||||
import TheApp from "../app";
|
||||
import TheApp from "../app.js";
|
||||
|
||||
export default async function PasswordResetTemplate(
|
||||
app: TheApp,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Templatable, tempstream } from "tempstream";
|
||||
import { Readable } from "stream";
|
||||
import { BaseContext } from "koa";
|
||||
import navbar from "./routes/common/navbar";
|
||||
import navbar from "./routes/common/navbar.js";
|
||||
|
||||
export const defaultHead = (ctx: BaseContext, title: string) => /* HTML */ `<title>
|
||||
${title} · ${ctx.$app.manifest.name}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import kill from "kill-port";
|
||||
import _locreq from "locreq";
|
||||
import TheApp from "./app";
|
||||
import { mainRouter } from "./routes";
|
||||
const locreq = _locreq(__dirname);
|
||||
import TheApp from "./app.js";
|
||||
import { mainRouter } from "./routes/index.js";
|
||||
import { module_dirname } from "./util.js";
|
||||
const locreq = _locreq.default(module_dirname(import.meta.url));
|
||||
|
||||
const app = new TheApp();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
|
||||
describe("roles", () => {
|
||||
it("allows access to users with designated role and denies access to users without it", async () =>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import html from "../../html";
|
||||
import html from "../../html.js";
|
||||
import { BaseContext } from "koa";
|
||||
import { Readable } from "stream";
|
||||
import { tempstream } from "tempstream";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { BaseContext } from "koa";
|
||||
import { SignUpURL, SignInURL, TodoURL, LogoutURL } from "../urls";
|
||||
import { SignUpURL, SignInURL, TodoURL, LogoutURL } from "../urls.js";
|
||||
|
||||
export default async function navbar(ctx: BaseContext) {
|
||||
const isLoggedIn = !!ctx.$context.session_id;
|
||||
@ -17,7 +17,7 @@ export default async function navbar(ctx: BaseContext) {
|
||||
const linksHTML = linkData
|
||||
.map((link) =>
|
||||
link.url === new URL(ctx.url, "https://a.com").pathname
|
||||
? `<li>${link.text}</li>`
|
||||
? `<li class="active"><span>${link.text}</span></li>`
|
||||
: /* HTML */ `<li><a href="${link.url}">${link.text}</a></li>`
|
||||
)
|
||||
.join("\n");
|
||||
@ -30,7 +30,7 @@ export default async function navbar(ctx: BaseContext) {
|
||||
width="50"
|
||||
height="50"
|
||||
/>
|
||||
Sealious App
|
||||
${ctx.$app.manifest.name}
|
||||
</a>
|
||||
<ul>
|
||||
${linksHTML}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseContext } from "koa";
|
||||
import { CollectionItem } from "sealious";
|
||||
import frame from "../../frame";
|
||||
import { Tasks } from "../../collections/collections";
|
||||
import frame from "../../frame.js";
|
||||
import { Tasks } from "../../collections/collections.js";
|
||||
|
||||
export function Task(task: CollectionItem<typeof Tasks>) {
|
||||
return frame(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint";
|
||||
import { HelloURL } from "./urls";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { HelloURL } from "./urls.js";
|
||||
|
||||
describe("Hello", () => {
|
||||
it("doesn't crash", async function () {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint";
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
|
||||
describe("homepage", function () {
|
||||
this.timeout(VERY_LONG_TEST_TIMEOUT);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Router from "@koa/router";
|
||||
import { Middlewares } from "sealious";
|
||||
import { MainView } from "./common/main-view";
|
||||
import mountAutoRoutes from "./routes";
|
||||
import { MainView } from "./common/main-view.js";
|
||||
import mountAutoRoutes from "./routes.js";
|
||||
|
||||
export const mainRouter = (router: Router): void => {
|
||||
router.get("/", Middlewares.extractContext(), async (ctx) => {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import assert from "assert";
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { LONG_TEST_TIMEOUT, VERY_LONG_TEST_TIMEOUT } from "../test_utils/webhint";
|
||||
import { LogoutURL, SignInURL } from "./urls";
|
||||
import { Browser, BrowserContext, Page } from "@playwright/test";
|
||||
import { getBrowser } from "../test_utils/browser-creator";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials.js";
|
||||
import { getBrowser } from "../test_utils/browser-creator.js";
|
||||
import { LONG_TEST_TIMEOUT, VERY_LONG_TEST_TIMEOUT } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { LogoutURL, SignInURL } from "./urls.js";
|
||||
|
||||
describe("Logout", () => {
|
||||
let page: Page;
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
import Router from "@koa/router";
|
||||
import { mount } from "@sealcode/sealgen";
|
||||
import * as URLs from "./urls";
|
||||
import * as URLs from "./urls.js";
|
||||
|
||||
import { default as Hello } from "./hello.page";
|
||||
import { default as Logout } from "./logout.redirect";
|
||||
import { default as SignIn } from "./signIn.form";
|
||||
import { default as SignUp } from "./signUp.form";
|
||||
import { default as Todo } from "./todo.form";
|
||||
import { default as Hello } from "./hello.page.js";
|
||||
import { default as Logout } from "./logout.redirect.js";
|
||||
import { default as SignIn } from "./signIn.form.js";
|
||||
import { default as SignUp } from "./signUp.form.js";
|
||||
import { default as Todo } from "./todo.form.js";
|
||||
|
||||
export default function mountAutoRoutes(router: Router) {
|
||||
mount(router, URLs.HelloURL, Hello);
|
||||
|
@ -7,10 +7,10 @@ import {
|
||||
Controls,
|
||||
FormReaction,
|
||||
} from "@sealcode/sealgen";
|
||||
import html from "../html";
|
||||
import { Users } from "../collections/collections";
|
||||
import { FlatTemplatable, tempstream } from "tempstream";
|
||||
import { PageErrorMessage } from "@sealcode/sealgen/@types/page/mountable-with-fields";
|
||||
import { Users } from "../collections/collections.js";
|
||||
import type { PageErrorMessage } from "@sealcode/sealgen/@types/page/mountable-with-fields.js";
|
||||
import html from "../html.js";
|
||||
|
||||
export const actionName = "SignIn";
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint";
|
||||
import { SignInURL, LogoutURL } from "./urls";
|
||||
import { Browser, BrowserContext, Page } from "@playwright/test";
|
||||
import { getBrowser } from "../test_utils/browser-creator";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials.js";
|
||||
import { getBrowser } from "../test_utils/browser-creator.js";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { LogoutURL, SignInURL } from "./urls.js";
|
||||
|
||||
describe("SignIn", () => {
|
||||
let page: Page;
|
||||
|
@ -7,8 +7,8 @@ import {
|
||||
Controls,
|
||||
FormReaction,
|
||||
} from "@sealcode/sealgen";
|
||||
import html from "../html";
|
||||
import { Users } from "../collections/collections";
|
||||
import { Users } from "../collections/collections.js";
|
||||
import html from "../html.js";
|
||||
|
||||
export const actionName = "SignUp";
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint";
|
||||
import { SignUpURL, LogoutURL, SignInURL } from "./urls";
|
||||
import { Browser, BrowserContext, Page } from "@playwright/test";
|
||||
import { getBrowser } from "../test_utils/browser-creator";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials.js";
|
||||
import { getBrowser } from "../test_utils/browser-creator.js";
|
||||
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { LogoutURL, SignInURL, SignUpURL } from "./urls.js";
|
||||
|
||||
describe("SignUp", () => {
|
||||
let page: Page;
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Tasks } from "./../collections/collections";
|
||||
import { tempstream } from "tempstream";
|
||||
import { Context } from "koa";
|
||||
import { Form, FormData, FormDataValue, Fields, Controls } from "@sealcode/sealgen";
|
||||
import html from "../html";
|
||||
import { TaskList } from "./common/tasks-view";
|
||||
import { Tasks } from "../collections/collections.js";
|
||||
import html from "../html.js";
|
||||
import { TaskList } from "./common/tasks-view.js";
|
||||
|
||||
export const actionName = "Todo";
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import assert from "assert";
|
||||
import { withProdApp } from "../test_utils/with-prod-app";
|
||||
import { LONG_TEST_TIMEOUT, VERY_LONG_TEST_TIMEOUT } from "../test_utils/webhint";
|
||||
import { SignInURL, TodoURL } from "./urls";
|
||||
import { Browser, BrowserContext, Page } from "@playwright/test";
|
||||
import { getBrowser } from "../test_utils/browser-creator";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials";
|
||||
import ADMIN_CREDENTIALS from "../default-admin-credentials.js";
|
||||
import { getBrowser } from "../test_utils/browser-creator.js";
|
||||
import { LONG_TEST_TIMEOUT, VERY_LONG_TEST_TIMEOUT } from "../test_utils/webhint.js";
|
||||
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||
import { SignInURL, TodoURL } from "./urls.js";
|
||||
|
||||
describe("Todo", function () {
|
||||
let page: Page;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Users } from "../collections/collections";
|
||||
import { CollectionItem, TestUtils } from "sealious";
|
||||
import TheApp from "../app";
|
||||
import TheApp from "../app.js";
|
||||
import Users from "../collections/users.js";
|
||||
|
||||
type Unpromisify<T> = T extends Promise<infer R> ? R : T;
|
||||
|
||||
@ -16,9 +16,7 @@ export function createAUser(app: TheApp, username: string) {
|
||||
export async function createAdmin(
|
||||
app: TheApp,
|
||||
rest_api: TestUtils.MockRestApi
|
||||
): Promise<
|
||||
[CollectionItem<typeof Users>, Unpromisify<ReturnType<typeof rest_api.login>>]
|
||||
> {
|
||||
): Promise<[CollectionItem<Users>, Unpromisify<ReturnType<typeof rest_api.login>>]> {
|
||||
const user = await createAUser(app, "super_user");
|
||||
await app.collections["user-roles"].suCreate({
|
||||
user: user.id,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import _locreq from "locreq";
|
||||
const locreq = _locreq(__dirname);
|
||||
const locreq = _locreq.default(__dirname);
|
||||
import { spawn } from "child_process";
|
||||
import { hasShape, is, predicates } from "@sealcode/ts-predicates";
|
||||
import { promises as fs } from "fs";
|
||||
|
@ -1,11 +1,12 @@
|
||||
import TheApp from "../app";
|
||||
import { mainRouter } from "../routes";
|
||||
import _locreq from "locreq";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
const locreq = _locreq(__dirname);
|
||||
const locreq = _locreq.default(module_dirname(import.meta.url));
|
||||
import { SMTPMailer } from "sealious";
|
||||
import { TestUtils } from "sealious";
|
||||
import TheApp from "../app.js";
|
||||
import { mainRouter } from "../routes/index.js";
|
||||
import { module_dirname } from "../util.js";
|
||||
|
||||
export async function withProdApp(
|
||||
callback: (args: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { BaseContext } from "koa";
|
||||
import qs from "qs";
|
||||
import { dirname } from "node:path";
|
||||
|
||||
export async function sleep(time: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
@ -20,3 +21,7 @@ export function UrlWithNewParams(
|
||||
): string {
|
||||
return `${ctx.path}?${qs.stringify(query_params)}`;
|
||||
}
|
||||
|
||||
export function module_dirname(module_url: string): string {
|
||||
return dirname(module_url).replace(/^file:\/\//, "");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user