-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add 'config' hook, upgrade runtime-compat, show http vs https
- Loading branch information
Showing
6 changed files
with
130 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,5 @@ | ||
import crypto from "runtime-compat/crypto"; | ||
import {is} from "runtime-compat/dyndef"; | ||
import {File, Path} from "runtime-compat/fs"; | ||
import cache from "./cache.js"; | ||
import extend from "./extend.js"; | ||
import defaults from "./primate.config.js"; | ||
import {colors, print, default as Logger} from "./Logger.js"; | ||
import * as handlers from "./handlers/exports.js"; | ||
const filter = (key, array) => array?.flatMap(m => m[key] ?? []) ?? []; | ||
|
||
const qualify = (root, paths) => | ||
Object.keys(paths).reduce((sofar, key) => { | ||
const value = paths[key]; | ||
sofar[key] = typeof value === "string" | ||
? new Path(root, value) | ||
: qualify(`${root}/${key}`, value); | ||
return sofar; | ||
}, {}); | ||
|
||
const getConfig = async (root, filename) => { | ||
try { | ||
return extend(defaults, (await import(root.join(filename))).default); | ||
} catch (error) { | ||
return defaults; | ||
} | ||
}; | ||
|
||
const getRoot = async () => { | ||
try { | ||
// use module root if possible | ||
return await Path.root(); | ||
} catch (error) { | ||
// fall back to current directory | ||
return Path.resolve(); | ||
} | ||
}; | ||
|
||
const index = async env => { | ||
const name = "index.html"; | ||
try { | ||
// user-provided file | ||
return await File.read(`${env.paths.static.join(name)}`); | ||
} catch (error) { | ||
// fallback | ||
return new Path(import.meta.url).directory.join(name).file.read(); | ||
} | ||
}; | ||
|
||
const hash = async (string, algorithm = "sha-384") => { | ||
const encoder = new TextEncoder(); | ||
const bytes = await crypto.subtle.digest(algorithm, encoder.encode(string)); | ||
const algo = algorithm.replace("-", () => ""); | ||
return `${algo}-${btoa(String.fromCharCode(...new Uint8Array(bytes)))}`; | ||
}; | ||
|
||
export default async (filename = "primate.config.js") => { | ||
is(filename).string(); | ||
const root = await getRoot(); | ||
const config = await getConfig(root, filename); | ||
|
||
const {name, version} = JSON.parse(await new Path(import.meta.url) | ||
.directory.directory.join("package.json").file.read()); | ||
|
||
const env = { | ||
...config, | ||
name, version, | ||
resources: [], | ||
entrypoints: [], | ||
paths: qualify(root, config.paths), | ||
root, | ||
log: new Logger(config.logger), | ||
register: (name, handler) => { | ||
env.handlers[name] = handler; | ||
}, | ||
handlers: {...handlers}, | ||
render: async ({body = "", head = ""} = {}) => { | ||
const html = await index(env); | ||
const heads = env.resources.map(({src, code, type, inline, integrity}) => { | ||
const tag = type === "style" ? "link" : "script"; | ||
const pre = type === "style" | ||
? `<${tag} rel="stylesheet" integrity="${integrity}"` | ||
: `<${tag} type="${type}" integrity="${integrity}"`; | ||
const middle = type === "style" | ||
? ` href="${src}">` | ||
: ` src="${src}">`; | ||
const post = type === "style" ? "" : `</${tag}>`; | ||
return inline ? `${pre}>${code}${post}` : `${pre}${middle}${post}`; | ||
}).join("\n"); | ||
return html | ||
.replace("%body%", () => body) | ||
.replace("%head%", () => `${head}${heads}`); | ||
}, | ||
publish: async ({src, code, type = "", inline = false}) => { | ||
const integrity = await hash(code); | ||
env.resources.push({src, code, type, inline, integrity}); | ||
return integrity; | ||
}, | ||
bootstrap: ({type, code}) => { | ||
env.entrypoints.push({type, code}); | ||
}, | ||
}; | ||
print(colors.blue(colors.bold(name)), colors.blue(version), ""); | ||
print(colors.gray(`at http://${config.http.host}:${config.http.port}`), "\n"); | ||
const {modules} = config; | ||
// modules may load other modules | ||
const loads = await Promise.all(modules | ||
.filter(module => module.load !== undefined) | ||
.map(module => module.load())); | ||
|
||
return cache("config", filename, () => ({...env, | ||
modules: modules.concat(loads.flat())})); | ||
}; | ||
export default async env => | ||
[...filter("config", env.modules), _ => _].reduceRight((acc, handler) => | ||
input => handler(input, acc))(env); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import crypto from "runtime-compat/crypto"; | ||
import {is} from "runtime-compat/dyndef"; | ||
import {File, Path} from "runtime-compat/fs"; | ||
import cache from "./cache.js"; | ||
import extend from "./extend.js"; | ||
import defaults from "./primate.config.js"; | ||
import {colors, print, default as Logger} from "./Logger.js"; | ||
import * as handlers from "./handlers/exports.js"; | ||
|
||
const qualify = (root, paths) => | ||
Object.keys(paths).reduce((sofar, key) => { | ||
const value = paths[key]; | ||
sofar[key] = typeof value === "string" | ||
? new Path(root, value) | ||
: qualify(`${root}/${key}`, value); | ||
return sofar; | ||
}, {}); | ||
|
||
const getConfig = async (root, filename) => { | ||
try { | ||
return extend(defaults, (await import(root.join(filename))).default); | ||
} catch (error) { | ||
return defaults; | ||
} | ||
}; | ||
|
||
const getRoot = async () => { | ||
try { | ||
// use module root if possible | ||
return await Path.root(); | ||
} catch (error) { | ||
// fall back to current directory | ||
return Path.resolve(); | ||
} | ||
}; | ||
|
||
const index = async env => { | ||
const name = "index.html"; | ||
try { | ||
// user-provided file | ||
return await File.read(`${env.paths.static.join(name)}`); | ||
} catch (error) { | ||
// fallback | ||
return new Path(import.meta.url).directory.join(name).file.read(); | ||
} | ||
}; | ||
|
||
const hash = async (string, algorithm = "sha-384") => { | ||
const encoder = new TextEncoder(); | ||
const bytes = await crypto.subtle.digest(algorithm, encoder.encode(string)); | ||
const algo = algorithm.replace("-", () => ""); | ||
return `${algo}-${btoa(String.fromCharCode(...new Uint8Array(bytes)))}`; | ||
}; | ||
|
||
export default async (filename = "primate.config.js") => { | ||
is(filename).string(); | ||
const root = await getRoot(); | ||
const config = await getConfig(root, filename); | ||
|
||
const {name, version} = JSON.parse(await new Path(import.meta.url) | ||
.directory.directory.join("package.json").file.read()); | ||
|
||
// if ssl activated, resolve key and cert early | ||
if (config.http.ssl) { | ||
config.http.ssl.key = root.join(config.http.ssl.key); | ||
config.http.ssl.cert = root.join(config.http.ssl.cert); | ||
config.secure = true; | ||
} | ||
|
||
const env = { | ||
...config, | ||
name, version, | ||
resources: [], | ||
entrypoints: [], | ||
paths: qualify(root, config.paths), | ||
root, | ||
log: new Logger(config.logger), | ||
register: (name, handler) => { | ||
env.handlers[name] = handler; | ||
}, | ||
handlers: {...handlers}, | ||
render: async ({body = "", head = ""} = {}) => { | ||
const html = await index(env); | ||
const heads = env.resources.map(({src, code, type, inline, integrity}) => { | ||
const tag = type === "style" ? "link" : "script"; | ||
const pre = type === "style" | ||
? `<${tag} rel="stylesheet" integrity="${integrity}"` | ||
: `<${tag} type="${type}" integrity="${integrity}"`; | ||
const middle = type === "style" | ||
? ` href="${src}">` | ||
: ` src="${src}">`; | ||
const post = type === "style" ? "" : `</${tag}>`; | ||
return inline ? `${pre}>${code}${post}` : `${pre}${middle}${post}`; | ||
}).join("\n"); | ||
return html | ||
.replace("%body%", () => body) | ||
.replace("%head%", () => `${head}${heads}`); | ||
}, | ||
publish: async ({src, code, type = "", inline = false}) => { | ||
const integrity = await hash(code); | ||
env.resources.push({src, code, type, inline, integrity}); | ||
return integrity; | ||
}, | ||
bootstrap: ({type, code}) => { | ||
env.entrypoints.push({type, code}); | ||
}, | ||
}; | ||
print(colors.blue(colors.bold(name)), colors.blue(version), ""); | ||
const type = env.secure ? "https" : "http"; | ||
const address = `${type}://${config.http.host}:${config.http.port}`; | ||
print(colors.gray(`at ${address}`), "\n"); | ||
const {modules} = config; | ||
// modules may load other modules | ||
const loads = await Promise.all(modules | ||
.filter(module => module.load !== undefined) | ||
.map(module => module.load())); | ||
|
||
return cache("config", filename, () => ({...env, | ||
modules: modules.concat(loads.flat())})); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import config from "./config.js"; | ||
import env from "./env.js"; | ||
import command from "./commands/exports.js"; | ||
|
||
export default async name => command(name)(await config()); | ||
export default async name => command(name)(await env()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters