@elysiumjs/hephaestus 0.2.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +22 -6
- package/dist/assets/embedder.d.ts +38 -0
- package/dist/assets/index.d.ts +1 -0
- package/dist/builder/binary.builder.d.ts +32 -0
- package/dist/builder/index.d.ts +1 -0
- package/dist/commands/build.command.d.ts +14 -0
- package/dist/commands/docker.command.d.ts +12 -0
- package/dist/commands/docker.generator.d.ts +20 -0
- package/dist/commands/embed.command.d.ts +11 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/loader.d.ts +8 -0
- package/dist/hephaestus.module.d.ts +7 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -10
- package/dist/platform/index.d.ts +1 -0
- package/dist/platform/targets.d.ts +22 -0
- package/dist/types.d.ts +72 -0
- package/package.json +17 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# @elysiumjs/hephaestus
|
|
2
2
|
|
|
3
|
+
## 0.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`04773f2`](https://github.com/na2axl/elysiumjs/commit/04773f2acd4ab1c762a80ee903715d90f1c08e21) Thanks [@na2axl](https://github.com/na2axl)! - Ship the type declarations. The packages pointed `types` at `dist/index.d.ts` but their build never wrote it, so TypeScript projects got no types for them.
|
|
8
|
+
|
|
9
|
+
## 0.3.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`68a0cdd`](https://github.com/na2axl/elysiumjs/commit/68a0cdd8b2e4a003d6e0af2d78985623cae40428), [`2c49acd`](https://github.com/na2axl/elysiumjs/commit/2c49acd3b552aa43765d70339fa216961499e1b5), [`76ba0ff`](https://github.com/na2axl/elysiumjs/commit/76ba0ff18f3c196cebc2189426328f67cb699f46), [`4ebf029`](https://github.com/na2axl/elysiumjs/commit/4ebf029611e6d753a4f1bfdbe247a75d954d9ded), [`bacce71`](https://github.com/na2axl/elysiumjs/commit/bacce7146f667a1a46bf474dc0344fb0111ae12a)]:
|
|
14
|
+
- @elysiumjs/core@0.10.0
|
|
15
|
+
|
|
16
|
+
## 0.3.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`5fef4a7`](https://github.com/na2axl/elysiumjs/commit/5fef4a7199f502fc4fe035299e7670739459a108)]:
|
|
21
|
+
- @elysiumjs/core@0.9.0
|
|
22
|
+
|
|
23
|
+
## 0.3.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- [`8ac91ab`](https://github.com/na2axl/elysiumjs/commit/8ac91ab676b1119b4eecf0ddb3fd0a3e84017cac) Thanks [@na2axl](https://github.com/na2axl)! - Upgrade dependencies to their latest major versions: wampy 8, zod 4, commander 15, @casl/ability 7, OpenTelemetry SDK 2 (sdk-node 0.300, resources 3), @sentry/bun 11. Generated projects now use TypeScript 7.
|
|
28
|
+
|
|
29
|
+
Breaking in `@elysiumjs/mnemosyne-drizzle`: it now requires drizzle-orm 1.0 (release candidate) and generated projects use drizzle-kit 1.0. `ColumnsWithTable` is no longer re-exported. `migration:generate` writes 1.0 migration folders (`<timestamp>_<name>/migration.sql`), and `migration:run` tracks those by folder name while still running flat `*.sql` files. Existing projects can upgrade their migrations folder with `drizzle-kit up`: `migration:run` recognises the moved migrations as already applied and renames their records. The `make:model` stub now generates a `pgTable` and a `DrizzleModel` built from it.
|
|
30
|
+
|
|
31
|
+
Breaking in `@elysiumjs/core`: the deprecated `@elysiajs/swagger` plugin is replaced by `@elysiajs/openapi`, and the app option `swagger` is renamed `openapi` (typed `ElysiaOpenAPIConfig | false`). Without a `path`, the docs now live at `/openapi` instead of `/swagger`. The UI options `scalarConfig` and `swaggerOptions` are now `scalar` and `swagger`. Elysia stays on 1.4 (now `^1.4.30`) until Elysia 2 and its OpenAPI plugin are stable.
|
|
32
|
+
|
|
33
|
+
Also in `@elysiumjs/core`: the WAMP `onChallenge` callback must return a string (or a promise of one); `null` is no longer accepted. `onError` now receives the error and `onReconnectSuccess` receives wampy's details object. `WampClient` is now wampy's own `Wampy` type. `onOpen` is called by Elysium once the connection is established, since wampy 8 no longer has that callback.
|
|
34
|
+
|
|
35
|
+
- [`07236b3`](https://github.com/na2axl/elysiumjs/commit/07236b386c2506590d74e8753ce847c1e184b3ee) Thanks [@na2axl](https://github.com/na2axl)! - Introduce the module system. Modules are now the only way to register anything in an Elysium.js app. This is a breaking change with no compatibility layer.
|
|
36
|
+
|
|
37
|
+
Breaking changes:
|
|
38
|
+
|
|
39
|
+
- `@Module.register()` takes `imports`, `services`, `exports`, `controllers`, `commands`, `jobs`, `prefix` and `env`. Services are private to their module unless exported (or global). The `beforeRegister` and `afterRegister` hooks are replaced by `onInit`, `onServe` and `onDestroy`.
|
|
40
|
+
- Configurable modules are bound with `with()`, for example `HermesModule.with({ level: 'debug' })`. `with()` accepts an object or a function.
|
|
41
|
+
- Decorators only record metadata. Importing a file no longer registers commands, services or event wiring, and the side-effect imports of the packages are removed. List commands, jobs and services in the module that owns them.
|
|
42
|
+
- `@Application.register()` no longer takes `database`, `redis`, `wamp` or `'elysium:hermes'`/`'elysium:cerberus'` keys. Use `DrizzleModule`, `RedisModule`, `WampModule`, `HermesModule` and `CerberusModule`. Package plugins are replaced by modules: add `SentryModule` instead of the `plugin()` function. `plugins` still accepts plain Elysia plugin factories.
|
|
43
|
+
- Constructing an `Application` no longer runs it. Use `await App.start()`; `Application.testing()` boots a module graph for tests. The `styx` binary loads `src/app.ts` (or `index.ts`) and starts the exported application, so a project entry no longer needs to import commands.
|
|
44
|
+
- The job system of core (`Job`, `Worker`, `WorkerPool`, `commandWork`) is removed. `@elysiumjs/heracles` is the only job system: extend its `Job`, list jobs in a module's `jobs`, declare queues with `HeraclesModule.with({ queues })`, and dispatch with `Heracles.dispatch()`.
|
|
45
|
+
- `@elysiumjs/styx` ships `StyxModule`, active in development only. The `migration:generate` and `migration:run` commands move to `DrizzleModule` and are available in production.
|
|
46
|
+
- `@elysiumjs/mnemosyne` ships `MnemosyneModule` for its caches (`redis: false` or `memory: false` opts out). `DrizzleModule` imports it.
|
|
47
|
+
- New modules: `HephaestusModule`, `ArgusModule` (`serviceName` is required), `SentryModule` (needs a `dsn` or `SENTRY_DSN`) and `CerberusModule` (`getSubject` is required).
|
|
48
|
+
- Module and service code throws typed errors (for example `InvalidModuleConfigError`) instead of exiting the process. `Application.run()` prints them and exits; command `run()` methods may still exit, and package plugin factories are unchanged.
|
|
49
|
+
- `Application.register` merges subclass props over the parent's (own props, then own metadata, then parent, then defaults), and concatenates `modules` parent first. Previously defaults and parent values won, so `openapi` could not be enabled.
|
|
50
|
+
- `Heracles.dispatch` starts a stopped queue on first use, so producers no longer start queues. `Queue.start()` is idempotent.
|
|
51
|
+
- `create-elysium` generates apps that use modules, and adds Sentry and Hephaestus to the `modules` list.
|
|
52
|
+
- `@Event.on`/`@Event.once` method listeners on classes in a loaded module's `services` or `controllers` are wired by the kernel and run in their module's context. Jobs, commands and middlewares are not wired, and an instance listener on a class that is not a service throws `EventListenerNotSupportedError`. Listeners on classes not listed in a loaded module no longer fire.
|
|
53
|
+
- New typed errors: `CircularDependencyError` (services that depend on each other, in sync and async resolution), `DuplicateModuleNameError` (two different module classes sharing a name; module scopes and config tokens are name based) and `EventListenerNotSupportedError`.
|
|
54
|
+
- Lazy boot contract: a CLI command initialises only its own module and that module's imports. Sync helpers such as `Database.getConnection()` work when the owning module's `onInit` is synchronous; otherwise they throw `ServiceNotReadyError` naming the module. Use `await Service.resolve()` or set `static boot = true` on the command.
|
|
55
|
+
|
|
56
|
+
### Patch Changes
|
|
57
|
+
|
|
58
|
+
- Updated dependencies [[`8ac91ab`](https://github.com/na2axl/elysiumjs/commit/8ac91ab676b1119b4eecf0ddb3fd0a3e84017cac), [`3625883`](https://github.com/na2axl/elysiumjs/commit/3625883dba92f1596e7444ee52f9399d8e9b049f), [`07236b3`](https://github.com/na2axl/elysiumjs/commit/07236b386c2506590d74e8753ce847c1e184b3ee)]:
|
|
59
|
+
- @elysiumjs/core@0.8.0
|
|
60
|
+
|
|
3
61
|
## 0.2.0
|
|
4
62
|
|
|
5
63
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
# @elysiumjs/hephaestus
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build tooling for Elysium.js applications: standalone binaries, Docker images and embedded assets.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
bun
|
|
8
|
+
bun add @elysiumjs/hephaestus
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Install it as a regular dependency, not a dev dependency: `HephaestusModule` is imported by your application at runtime.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Add `HephaestusModule` to the modules of your application. It provides the Hephaestus commands to `styx`.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Application } from '@elysiumjs/core';
|
|
19
|
+
import { HephaestusModule } from '@elysiumjs/hephaestus';
|
|
20
|
+
|
|
21
|
+
@Application.register({
|
|
22
|
+
modules: [HephaestusModule /* , your other modules */]
|
|
23
|
+
})
|
|
24
|
+
export class App extends Application {}
|
|
13
25
|
```
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
Then run `bun styx list` to see the available commands.
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
This project is licensed under the Apache License, Version 2.0. See the [LICENSE](../../LICENSE) file for more info.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { HephaestusConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Manifest mapping asset paths to their base64 content and MIME type.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export interface AssetManifest {
|
|
7
|
+
[path: string]: {
|
|
8
|
+
content: string;
|
|
9
|
+
mimeType: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Embeds assets into a generated loader module for use in compiled binaries.
|
|
14
|
+
*
|
|
15
|
+
* For static assets known at development time, prefer Bun's native file embedding:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import icon from './icon.png' with { type: 'file' };
|
|
18
|
+
* const bytes = await Bun.file(icon).arrayBuffer();
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* This class is for dynamic glob-based embedding from config.
|
|
22
|
+
*
|
|
23
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
24
|
+
*/
|
|
25
|
+
export declare class AssetEmbedder {
|
|
26
|
+
private config;
|
|
27
|
+
constructor(config: HephaestusConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Scans for assets matching the config patterns and generates a loader module.
|
|
30
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
31
|
+
* @returns A string containing the generated asset loader module.
|
|
32
|
+
*/
|
|
33
|
+
embed(): Promise<string>;
|
|
34
|
+
private buildManifest;
|
|
35
|
+
private isExcluded;
|
|
36
|
+
private generateLoader;
|
|
37
|
+
private getMimeType;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type AssetManifest, AssetEmbedder } from './embedder';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HephaestusConfig, PlatformTarget } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Result of a single binary compilation.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export interface BuildResult {
|
|
7
|
+
platform: PlatformTarget;
|
|
8
|
+
outputPath: string;
|
|
9
|
+
size: number;
|
|
10
|
+
duration: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compiles Elysium projects into single-binary executables using Bun.
|
|
14
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
15
|
+
*/
|
|
16
|
+
export declare class BinaryBuilder {
|
|
17
|
+
private config;
|
|
18
|
+
constructor(config: HephaestusConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Builds a single binary for a specific platform, or the current one if not specified.
|
|
21
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
22
|
+
* @param platform The target platform. Defaults to the current platform.
|
|
23
|
+
* @returns The build result with metrics.
|
|
24
|
+
*/
|
|
25
|
+
build(platform?: PlatformTarget): Promise<BuildResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Builds binaries for all configured platforms, or the current one if none are configured.
|
|
28
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
29
|
+
* @returns An array of build results.
|
|
30
|
+
*/
|
|
31
|
+
buildAll(): Promise<BuildResult[]>;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type BuildResult, BinaryBuilder } from './binary.builder';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@elysiumjs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Command used to build the project into a standalone binary.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export declare class HephaestusBuildCommand extends Command {
|
|
7
|
+
static readonly command: string;
|
|
8
|
+
static readonly description: string;
|
|
9
|
+
static readonly dev: boolean;
|
|
10
|
+
private platform?;
|
|
11
|
+
private allPlatforms;
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
private formatSize;
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from '@elysiumjs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Command used to generate a Dockerfile for the compiled binary.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export declare class HephaestusDockerCommand extends Command {
|
|
7
|
+
static readonly command: string;
|
|
8
|
+
static readonly description: string;
|
|
9
|
+
static readonly dev: boolean;
|
|
10
|
+
private output;
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HephaestusConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a multi-stage Dockerfile for compiled Elysium binaries.
|
|
4
|
+
*
|
|
5
|
+
* The runtime stage uses Alpine (not Bun) because the compiled binary
|
|
6
|
+
* is self-contained. Healthcheck uses `wget` (available in Alpine base).
|
|
7
|
+
*
|
|
8
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
9
|
+
*/
|
|
10
|
+
export declare class DockerGenerator {
|
|
11
|
+
private config;
|
|
12
|
+
constructor(config: HephaestusConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Generates the Dockerfile and writes it to the output directory.
|
|
15
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
16
|
+
* @param outputDir The directory to write the Dockerfile to.
|
|
17
|
+
*/
|
|
18
|
+
generate(outputDir: string): void;
|
|
19
|
+
private renderDockerfile;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from '@elysiumjs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Command used to generate asset loader module from configured patterns.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export declare class HephaestusEmbedCommand extends Command {
|
|
7
|
+
static readonly command: string;
|
|
8
|
+
static readonly description: string;
|
|
9
|
+
static readonly dev: boolean;
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { loadConfig } from './loader';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HephaestusConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Loads and validates the Hephaestus build configuration from the project root.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
* @param cwd The working directory to search for config files.
|
|
6
|
+
* @returns The validated configuration.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadConfig(cwd?: string): Promise<HephaestusConfig>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { HephaestusModule } from './hephaestus.module';
|
|
2
|
+
export type { HephaestusConfig, PlatformTarget } from './types';
|
|
3
|
+
export { HephaestusConfigSchema, PlatformTargetSchema } from './types';
|
|
4
|
+
export type { BuildResult } from './builder';
|
|
5
|
+
export { BinaryBuilder } from './builder';
|
|
6
|
+
export type { AssetManifest } from './assets';
|
|
7
|
+
export { AssetEmbedder } from './assets';
|
|
8
|
+
export { DockerGenerator } from './commands/docker.generator';
|
|
9
|
+
export { loadConfig } from './config';
|
|
10
|
+
export { bunTarget, detectCurrentPlatform, getOutputName } from './platform';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
const __assets__ = ${JSON.stringify(
|
|
2
|
+
var __legacyDecorateClassTS=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)if(d=decorators[i])r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r;return c>3&&r&&Object.defineProperty(target,key,r),r};var __legacyMetadataTS=(k,v)=>{if(typeof Reflect==="object"&&typeof Reflect.metadata==="function")return Reflect.metadata(k,v)};import{Module}from"@elysiumjs/core";import{Command,CommandArgumentType}from"@elysiumjs/core";import{join}from"path";var BUN_TARGET_MAP={"linux-x64":"bun-linux-x64","linux-x64-baseline":"bun-linux-x64-baseline","linux-arm64":"bun-linux-arm64","darwin-x64":"bun-darwin-x64","darwin-arm64":"bun-darwin-arm64","windows-x64":"bun-windows-x64"};function bunTarget(platform){return BUN_TARGET_MAP[platform]}function detectCurrentPlatform(){let platform=process.platform,arch=process.arch;if(platform==="linux"&&arch==="x64")return"linux-x64";if(platform==="linux"&&arch==="arm64")return"linux-arm64";if(platform==="darwin"&&arch==="x64")return"darwin-x64";if(platform==="darwin"&&arch==="arm64")return"darwin-arm64";if(platform==="win32"&&arch==="x64")return"windows-x64";return"linux-x64"}function getOutputName(baseName,platform){return platform.startsWith("windows")?`${baseName}.exe`:baseName}class BinaryBuilder{config;constructor(config){this.config=config}async build(platform){let startTime=Date.now(),targetPlatform=platform??detectCurrentPlatform(),outputName=getOutputName(this.config.output.name,targetPlatform),outputPath=join(this.config.output.dir,outputName),args=["bun","build",this.config.entry,"--compile","--outfile",outputPath];if(this.config.build.minify)args.push("--minify");if(this.config.build.sourcemap)args.push("--sourcemap");if(platform&&platform!==detectCurrentPlatform())args.push("--target",bunTarget(platform));let proc=Bun.spawn(args,{stdout:"pipe",stderr:"pipe"});if(await proc.exited!==0){let stderr=await new Response(proc.stderr).text();throw Error(`Build failed for ${targetPlatform}: ${stderr}`)}let size=Bun.file(outputPath).size;return{platform:targetPlatform,outputPath,size,duration:Date.now()-startTime}}async buildAll(){let platforms=this.config.platforms;if(platforms.length===0)return[await this.build()];let results=[];for(let platform of platforms)results.push(await this.build(platform));return results}}import{join as join2}from"path";import{z}from"zod";var PlatformTargetSchema=z.enum(["linux-x64","linux-x64-baseline","linux-arm64","darwin-x64","darwin-arm64","windows-x64"]),HephaestusConfigSchema=z.object({entry:z.string().default("./src/index.ts"),output:z.object({name:z.string(),dir:z.string().default("./dist")}),platforms:z.array(PlatformTargetSchema).default([]),build:z.object({minify:z.boolean().default(!0),sourcemap:z.boolean().default(!0),bytecode:z.boolean().default(!0),split:z.boolean().default(!1)}).prefault({}),assets:z.object({embed:z.array(z.string()).default([]),exclude:z.array(z.string()).default([])}).prefault({}),env:z.object({generateExample:z.boolean().default(!0)}).prefault({}),docker:z.object({enabled:z.boolean().default(!1),buildImage:z.string().default("oven/bun:1-alpine"),runtimeImage:z.string().default("alpine:3.19"),expose:z.array(z.number()).default([]),healthcheck:z.object({path:z.string().default("/health"),interval:z.string().default("30s")}).optional()}).optional(),release:z.object({include:z.array(z.string()).default([]),compress:z.enum(["zip","tar.gz"]).default("tar.gz")}).optional()});var CONFIG_FILENAMES=["hephaestus.config.ts","hephaestus.config.js","hephaestus.config.json"];async function loadConfig(cwd=process.cwd()){for(let filename of CONFIG_FILENAMES){let configPath=join2(cwd,filename),file=Bun.file(configPath);if(await file.exists()){if(filename.endsWith(".json")){let raw=await file.json();return HephaestusConfigSchema.parse(raw)}let mod=await import(configPath);return HephaestusConfigSchema.parse(mod.default??mod)}}throw Error(`No Hephaestus config found. Create one of: ${CONFIG_FILENAMES.join(", ")}`)}class HephaestusBuildCommand extends Command{constructor(){super(...arguments);this.allPlatforms=!1}static command="hephaestus:build";static description="Build the project into a standalone binary.";static dev=!0;async run(){try{let config=await loadConfig(),builder=new BinaryBuilder(config);if(this.allPlatforms){let spinner=this.spinner("Building for all platforms"),results=await builder.buildAll();spinner.complete("Build completed"),this.newLine(),this.title("Build Results:");for(let result of results)this.info(`${result.platform}: ${result.outputPath} (${this.formatSize(result.size)}, ${result.duration}ms)`)}else{let targetPlatform=this.platform,platformText=targetPlatform?` for ${targetPlatform}`:"",spinner=this.spinner(`Building${platformText}`),result=await builder.build(targetPlatform);spinner.complete("Build completed"),this.newLine(),this.success(`Built ${result.platform}: ${result.outputPath} (${this.formatSize(result.size)}, ${result.duration}ms)`)}}catch(error){this.trace(error,"Build failed"),process.exit(1)}}formatSize(bytes){if(bytes<1024)return`${bytes}B`;if(bytes<1048576)return`${(bytes/1024).toFixed(1)}KB`;return`${(bytes/1048576).toFixed(1)}MB`}}__legacyDecorateClassTS([Command.arg({name:"platform",required:!1,description:"Target platform for the build",type:CommandArgumentType.ENUM,enum:["linux-x64","linux-x64-baseline","linux-arm64","darwin-x64","darwin-arm64","windows-x64"]}),__legacyMetadataTS("design:type",typeof PlatformTarget==="undefined"?Object:PlatformTarget)],HephaestusBuildCommand.prototype,"platform",void 0),__legacyDecorateClassTS([Command.arg({name:"all-platforms",required:!1,description:"Build for all configured platforms",type:CommandArgumentType.BOOLEAN,default:!1}),__legacyMetadataTS("design:type",Boolean)],HephaestusBuildCommand.prototype,"allPlatforms",void 0),HephaestusBuildCommand=__legacyDecorateClassTS([Command.register()],HephaestusBuildCommand);import{join as join3}from"path";import{Command as Command2}from"@elysiumjs/core";import{relative}from"path";class AssetEmbedder{config;constructor(config){this.config=config}async embed(){let manifest=await this.buildManifest();return this.generateLoader(manifest)}async buildManifest(){let manifest={},patterns=this.config.assets.embed;for(let pattern of patterns){let glob=new Bun.Glob(pattern);for await(let file of glob.scan({cwd:process.cwd(),absolute:!0})){if(this.isExcluded(file))continue;let content=await Bun.file(file).arrayBuffer(),relativePath=relative(process.cwd(),file);manifest[relativePath]={content:Buffer.from(content).toString("base64"),mimeType:this.getMimeType(file)}}}return manifest}isExcluded(filePath){return this.config.assets.exclude.some((pattern)=>new Bun.Glob(pattern).match(filePath))}generateLoader(manifest){return`// Auto-generated by Hephaestus
|
|
3
|
+
const __assets__ = ${JSON.stringify(manifest,null,2)};
|
|
4
4
|
|
|
5
5
|
export function getAsset(path: string): Buffer | null {
|
|
6
6
|
const asset = __assets__[path];
|
|
@@ -16,18 +16,18 @@ export function getAssetString(path: string): string | null {
|
|
|
16
16
|
export function listAssets(): string[] {
|
|
17
17
|
return Object.keys(__assets__);
|
|
18
18
|
}
|
|
19
|
-
`}getMimeType(
|
|
20
|
-
FROM ${
|
|
19
|
+
`}getMimeType(path){let ext=path.split(".").pop()?.toLowerCase();return{html:"text/html",css:"text/css",js:"application/javascript",json:"application/json",png:"image/png",jpg:"image/jpeg",svg:"image/svg+xml"}[ext??""]??"application/octet-stream"}}class HephaestusEmbedCommand extends Command2{static command="hephaestus:embed";static description="Generate asset loader module from configured patterns.";static dev=!0;async run(){try{let spinner=this.spinner("Scanning and embedding assets"),config=await loadConfig(),loader=await new AssetEmbedder(config).embed(),outputPath=join3(config.output.dir,"__assets__.ts");await Bun.write(outputPath,loader),spinner.complete("Assets embedded successfully"),this.newLine(),this.success(`Asset loader generated: ${outputPath}`)}catch(error){this.trace(error,"Asset embedding failed"),process.exit(1)}}}HephaestusEmbedCommand=__legacyDecorateClassTS([Command2.register()],HephaestusEmbedCommand);import{Command as Command3,CommandArgumentType as CommandArgumentType2}from"@elysiumjs/core";import{mkdirSync,writeFileSync}from"fs";import{join as join4}from"path";class DockerGenerator{config;constructor(config){this.config=config}generate(outputDir){mkdirSync(outputDir,{recursive:!0});let dockerfile=this.renderDockerfile();writeFileSync(join4(outputDir,"Dockerfile"),dockerfile)}renderDockerfile(){let buildImage=this.config.docker?.buildImage??"oven/bun:1-alpine",runtimeImage=this.config.docker?.runtimeImage??"alpine:3.19",binaryName=this.config.output.name,expose=this.config.docker?.expose??[],healthcheck=this.config.docker?.healthcheck;return`# Generated by Hephaestus
|
|
20
|
+
FROM ${buildImage} AS builder
|
|
21
21
|
WORKDIR /app
|
|
22
22
|
COPY . .
|
|
23
23
|
RUN bun install --frozen-lockfile --production
|
|
24
24
|
RUN bun run build
|
|
25
25
|
|
|
26
|
-
FROM ${
|
|
26
|
+
FROM ${runtimeImage}
|
|
27
27
|
WORKDIR /app
|
|
28
|
-
COPY --from=builder /app/dist/${
|
|
29
|
-
${
|
|
28
|
+
COPY --from=builder /app/dist/${binaryName} /app/${binaryName}
|
|
29
|
+
${expose.map((p)=>`EXPOSE ${p}`).join(`
|
|
30
30
|
`)}
|
|
31
|
-
${
|
|
32
|
-
ENTRYPOINT ["./${
|
|
33
|
-
`}}class
|
|
31
|
+
${healthcheck?`HEALTHCHECK --interval=${healthcheck.interval} CMD wget -qO- http://localhost:${expose[0]??3000}${healthcheck.path} || exit 1`:""}
|
|
32
|
+
ENTRYPOINT ["./${binaryName}"]
|
|
33
|
+
`}}class HephaestusDockerCommand extends Command3{constructor(){super(...arguments);this.output="."}static command="hephaestus:docker";static description="Generate a Dockerfile for the compiled binary.";static dev=!0;async run(){try{let config=await loadConfig();new DockerGenerator(config).generate(this.output),this.success(`Dockerfile generated in ${this.output}`)}catch(error){this.trace(error,"Dockerfile generation failed"),process.exit(1)}}}__legacyDecorateClassTS([Command3.arg({name:"output",required:!1,description:"Output directory for the Dockerfile",type:CommandArgumentType2.STRING,default:"."}),__legacyMetadataTS("design:type",String)],HephaestusDockerCommand.prototype,"output",void 0),HephaestusDockerCommand=__legacyDecorateClassTS([Command3.register()],HephaestusDockerCommand);class HephaestusModule extends Module{}HephaestusModule=__legacyDecorateClassTS([Module.register({commands:[HephaestusBuildCommand,HephaestusDockerCommand,HephaestusEmbedCommand]})],HephaestusModule);export{AssetEmbedder,BinaryBuilder,DockerGenerator,HephaestusConfigSchema,HephaestusModule,PlatformTargetSchema,bunTarget,detectCurrentPlatform,getOutputName,loadConfig};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bunTarget, detectCurrentPlatform, getOutputName } from './targets';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PlatformTarget } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a Hephaestus platform target to a Bun target string.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
* @param platform The Hephaestus platform target.
|
|
6
|
+
* @returns The Bun `--target` value.
|
|
7
|
+
*/
|
|
8
|
+
export declare function bunTarget(platform: PlatformTarget): string;
|
|
9
|
+
/**
|
|
10
|
+
* Detects the current platform and returns the corresponding target.
|
|
11
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
12
|
+
* @returns The detected platform target.
|
|
13
|
+
*/
|
|
14
|
+
export declare function detectCurrentPlatform(): PlatformTarget;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the output file name for a given platform.
|
|
17
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
18
|
+
* @param baseName The base binary name.
|
|
19
|
+
* @param platform The target platform.
|
|
20
|
+
* @returns The platform-specific output file name.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getOutputName(baseName: string, platform: PlatformTarget): string;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Supported compilation target platforms.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export declare const PlatformTargetSchema: z.ZodEnum<{
|
|
7
|
+
"darwin-arm64": "darwin-arm64";
|
|
8
|
+
"darwin-x64": "darwin-x64";
|
|
9
|
+
"linux-arm64": "linux-arm64";
|
|
10
|
+
"linux-x64": "linux-x64";
|
|
11
|
+
"linux-x64-baseline": "linux-x64-baseline";
|
|
12
|
+
"windows-x64": "windows-x64";
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* A supported compilation target platform.
|
|
16
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
17
|
+
*/
|
|
18
|
+
export type PlatformTarget = z.infer<typeof PlatformTargetSchema>;
|
|
19
|
+
/**
|
|
20
|
+
* Hephaestus build configuration schema.
|
|
21
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
22
|
+
*/
|
|
23
|
+
export declare const HephaestusConfigSchema: z.ZodObject<{
|
|
24
|
+
entry: z.ZodDefault<z.ZodString>;
|
|
25
|
+
output: z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
platforms: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
30
|
+
"darwin-arm64": "darwin-arm64";
|
|
31
|
+
"darwin-x64": "darwin-x64";
|
|
32
|
+
"linux-arm64": "linux-arm64";
|
|
33
|
+
"linux-x64": "linux-x64";
|
|
34
|
+
"linux-x64-baseline": "linux-x64-baseline";
|
|
35
|
+
"windows-x64": "windows-x64";
|
|
36
|
+
}>>>;
|
|
37
|
+
build: z.ZodPrefault<z.ZodObject<{
|
|
38
|
+
minify: z.ZodDefault<z.ZodBoolean>;
|
|
39
|
+
sourcemap: z.ZodDefault<z.ZodBoolean>;
|
|
40
|
+
bytecode: z.ZodDefault<z.ZodBoolean>;
|
|
41
|
+
split: z.ZodDefault<z.ZodBoolean>;
|
|
42
|
+
}, z.core.$strip>>;
|
|
43
|
+
assets: z.ZodPrefault<z.ZodObject<{
|
|
44
|
+
embed: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
45
|
+
exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
env: z.ZodPrefault<z.ZodObject<{
|
|
48
|
+
generateExample: z.ZodDefault<z.ZodBoolean>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
docker: z.ZodOptional<z.ZodObject<{
|
|
51
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
52
|
+
buildImage: z.ZodDefault<z.ZodString>;
|
|
53
|
+
runtimeImage: z.ZodDefault<z.ZodString>;
|
|
54
|
+
expose: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
|
|
55
|
+
healthcheck: z.ZodOptional<z.ZodObject<{
|
|
56
|
+
path: z.ZodDefault<z.ZodString>;
|
|
57
|
+
interval: z.ZodDefault<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
}, z.core.$strip>>;
|
|
60
|
+
release: z.ZodOptional<z.ZodObject<{
|
|
61
|
+
include: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
62
|
+
compress: z.ZodDefault<z.ZodEnum<{
|
|
63
|
+
"tar.gz": "tar.gz";
|
|
64
|
+
zip: "zip";
|
|
65
|
+
}>>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
/**
|
|
69
|
+
* Hephaestus build configuration.
|
|
70
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
71
|
+
*/
|
|
72
|
+
export type HephaestusConfig = z.infer<typeof HephaestusConfigSchema>;
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elysiumjs/hephaestus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Compilation and bundling utilities for Elysium.js apps.",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Workbud Technologies Inc.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/
|
|
10
|
+
"url": "git+https://github.com/na2axl/elysiumjs.git",
|
|
11
|
+
"directory": "@elysiumjs/hephaestus"
|
|
11
12
|
},
|
|
12
13
|
"keywords": [
|
|
13
14
|
"elysium",
|
|
@@ -19,15 +20,23 @@
|
|
|
19
20
|
"compilation",
|
|
20
21
|
"bun"
|
|
21
22
|
],
|
|
22
|
-
"homepage": "https://github.com/
|
|
23
|
-
"
|
|
23
|
+
"homepage": "https://github.com/na2axl/elysiumjs/tree/main/@elysiumjs/hephaestus#readme",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/na2axl/elysiumjs/issues"
|
|
26
|
+
},
|
|
27
|
+
"module": "dist/index.js",
|
|
24
28
|
"type": "module",
|
|
29
|
+
"sideEffects": false,
|
|
25
30
|
"main": "dist/index.js",
|
|
26
31
|
"types": "dist/index.d.ts",
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"CHANGELOG.md"
|
|
35
|
+
],
|
|
27
36
|
"scripts": {
|
|
28
37
|
"format": "prettier --write \"./src/**/*.ts\"",
|
|
29
38
|
"clean": "rimraf dist",
|
|
30
|
-
"build:js": "bun build ./src/index.ts --outdir ./dist --target bun -e zod -e @elysiumjs/core --root ./src --minify",
|
|
39
|
+
"build:js": "bun build ./src/index.ts --outdir ./dist --target bun -e zod -e @elysiumjs/core --root ./src --minify-syntax --minify-whitespace",
|
|
31
40
|
"build:ts": "tsc",
|
|
32
41
|
"build": "bun run clean && bun run build:js && bun run build:ts",
|
|
33
42
|
"test": "bun test",
|
|
@@ -36,12 +45,12 @@
|
|
|
36
45
|
"prepublishOnly": "bun run build"
|
|
37
46
|
},
|
|
38
47
|
"dependencies": {
|
|
39
|
-
"zod": "^
|
|
48
|
+
"zod": "^4.6.7"
|
|
40
49
|
},
|
|
41
50
|
"devDependencies": {
|
|
42
|
-
"@elysiumjs/core": "0.
|
|
51
|
+
"@elysiumjs/core": "0.10.0"
|
|
43
52
|
},
|
|
44
53
|
"peerDependencies": {
|
|
45
|
-
"@elysiumjs/core": "^0.
|
|
54
|
+
"@elysiumjs/core": "^0.10.0"
|
|
46
55
|
}
|
|
47
56
|
}
|