@hashsome/runtime 0.1.0

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.
Files changed (69) hide show
  1. package/LICENSE +674 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/app/entry.client.d.ts +1 -0
  4. package/dist/app/entry.client.js +7 -0
  5. package/dist/app/entry.client.js.map +1 -0
  6. package/dist/app/entry.server.d.ts +2 -0
  7. package/dist/app/entry.server.js +20 -0
  8. package/dist/app/entry.server.js.map +1 -0
  9. package/dist/app/index.d.ts +1 -0
  10. package/dist/app/index.js +1 -0
  11. package/dist/app/index.js.map +1 -0
  12. package/dist/app/root.d.ts +18 -0
  13. package/dist/app/root.js +36 -0
  14. package/dist/app/root.js.map +1 -0
  15. package/dist/bin/hashsome.d.ts +2 -0
  16. package/dist/bin/hashsome.js +17 -0
  17. package/dist/bin/hashsome.js.map +1 -0
  18. package/dist/src/cli/build.d.ts +4 -0
  19. package/dist/src/cli/build.js +18 -0
  20. package/dist/src/cli/build.js.map +1 -0
  21. package/dist/src/cli/dev.d.ts +1 -0
  22. package/dist/src/cli/dev.js +19 -0
  23. package/dist/src/cli/dev.js.map +1 -0
  24. package/dist/src/cli/package.d.ts +13 -0
  25. package/dist/src/cli/package.js +115 -0
  26. package/dist/src/cli/package.js.map +1 -0
  27. package/dist/src/cli/start.d.ts +1 -0
  28. package/dist/src/cli/start.js +12 -0
  29. package/dist/src/cli/start.js.map +1 -0
  30. package/dist/src/config.d.ts +36 -0
  31. package/dist/src/config.js +54 -0
  32. package/dist/src/config.js.map +1 -0
  33. package/dist/src/index.d.ts +1 -0
  34. package/dist/src/index.js +8 -0
  35. package/dist/src/index.js.map +1 -0
  36. package/dist/src/release/bundle.d.ts +10 -0
  37. package/dist/src/release/bundle.js +50 -0
  38. package/dist/src/release/bundle.js.map +1 -0
  39. package/dist/src/release/package.d.ts +26 -0
  40. package/dist/src/release/package.js +102 -0
  41. package/dist/src/release/package.js.map +1 -0
  42. package/dist/src/release/render.d.ts +32 -0
  43. package/dist/src/release/render.js +335 -0
  44. package/dist/src/release/render.js.map +1 -0
  45. package/dist/src/serve.d.ts +8 -0
  46. package/dist/src/serve.js +14 -0
  47. package/dist/src/serve.js.map +1 -0
  48. package/dist/src/server/assets.d.ts +10 -0
  49. package/dist/src/server/assets.js +46 -0
  50. package/dist/src/server/assets.js.map +1 -0
  51. package/dist/src/server/integrations.d.ts +12 -0
  52. package/dist/src/server/integrations.js +39 -0
  53. package/dist/src/server/integrations.js.map +1 -0
  54. package/dist/src/server/production.d.ts +7 -0
  55. package/dist/src/server/production.js +45 -0
  56. package/dist/src/server/production.js.map +1 -0
  57. package/dist/src/server/proxy.d.ts +34 -0
  58. package/dist/src/server/proxy.js +165 -0
  59. package/dist/src/server/proxy.js.map +1 -0
  60. package/dist/src/server/websocket.d.ts +5 -0
  61. package/dist/src/server/websocket.js +17 -0
  62. package/dist/src/server/websocket.js.map +1 -0
  63. package/dist/src/vite-config.d.ts +12 -0
  64. package/dist/src/vite-config.js +35 -0
  65. package/dist/src/vite-config.js.map +1 -0
  66. package/dist/src/vite.d.ts +5 -0
  67. package/dist/src/vite.js +42 -0
  68. package/dist/src/vite.js.map +1 -0
  69. package/package.json +73 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.js","sourceRoot":"","sources":["../../app/root.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAIvE,MAAM,KAAK,GAAG;IACZ,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE;IACtC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE;CACxC,CAAC;AAEF;;;;;6FAK6F;AAC7F,MAAM,UAAU,YAAY,CAAC,KAAK,GAAc,MAAM,EAAE,IAAI,GAAW,YAAY;IACjF,MAAM,WAAW,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,MAAM,OAAO,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAC7D,MAAM,cAAc,GAClB,KAAK,KAAK,QAAQ;QAChB,CAAC,CAAC,mEAAmE,KAAK,CAAC,KAAK,CAAC,EAAE,YAAY,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO;QACpH,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,QAAQ,GAAG;wDACqC,OAAO,CAAC,EAAE,YAAY,OAAO,CAAC,EAAE,kBAAkB,SAAS,CAAC,IAAI,CAAC;;;MAGnH,cAAc;GACjB,CAAC;IAEF,OAAO,SAAS,MAAM,CAAC,EAAE,QAAQ,EAAiC;QAChE,OAAO,CACL,gBAAM,IAAI,EAAC,IAAI,aACb,2BACE,eAAM,OAAO,EAAC,OAAO,GAAG,EACxB,eACE,IAAI,EAAC,UAAU,EACf,OAAO,EAAC,4FAA4F,GACpG,EACF,eAAM,IAAI,EAAC,cAAc,EAAC,OAAO,EAAE,WAAW,GAAI,EAClD,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAC,8BAA8B,GAAG,EAC7D,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAC,2BAA2B,EAAC,WAAW,EAAC,EAAE,GAAG,EACzE,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,wBAAqB,EAAE,GAAG,EAC3E,gBAAO,uBAAuB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAI,EACxD,KAAC,IAAI,KAAG,EACR,KAAC,KAAK,KAAG,IACJ,EACP,2BACG,QAAQ,EACT,KAAC,iBAAiB,KAAG,EACrB,KAAC,OAAO,KAAG,IACN,IACF,CACR,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;8BAE8B;AAC9B,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAE3C,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ // Makes this file a module, which top-level `await` below requires.
3
+ // oxlint-disable-next-line unicorn/require-module-specifiers
4
+ export {};
5
+ const commands = {
6
+ dev: async () => (await import('../src/cli/dev.js')).dev(),
7
+ build: async () => (await import('../src/cli/build.js')).build(),
8
+ start: async () => (await import('../src/cli/start.js')).start(),
9
+ package: async () => (await import('../src/cli/package.js')).packageCommand(process.argv.slice(3)),
10
+ };
11
+ const command = process.argv[2];
12
+ const run = command && commands[command];
13
+ if (!run) {
14
+ console.error(`Usage: hashsome <${Object.keys(commands).join('|')}>`);
15
+ process.exit(1);
16
+ }
17
+ await run();
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashsome.js","sourceRoot":"","sources":["../../bin/hashsome.ts"],"names":[],"mappings":";AAEA,oEAAoE;AACpE,6DAA6D;AAC7D,OAAO,EAAE,CAAC;AAEV,MAAM,QAAQ,GAAG;IACf,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,EAAE;IAC1D,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,KAAK,EAAE;IAChE,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,KAAK,EAAE;IAChE,OAAO,EAAE,KAAK,IAAI,EAAE,CAClB,CAAC,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACvE,CAAC;AAEX,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAsC,CAAC;AACrE,MAAM,GAAG,GAAG,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzC,IAAI,CAAC,GAAG,EAAE,CAAC;IACT,OAAO,CAAC,KAAK,CAAC,oBAAoB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,GAAG,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Builds the client into `build/client`. Exits when done, unless `exit` is false (a caller that has more to do). */
2
+ export declare function build({ exit }?: {
3
+ exit?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,18 @@
1
+ import { resolve } from 'node:path';
2
+ import { createBuilder } from 'vite';
3
+ import { loadConfig } from '../config.js';
4
+ import { createViteConfig } from '../vite.js';
5
+ /** Builds the client into `build/client`. Exits when done, unless `exit` is false (a caller that has more to do). */
6
+ export async function build({ exit = true } = {}) {
7
+ const config = await loadConfig(resolve(process.cwd()));
8
+ const inline = createViteConfig(config);
9
+ // React Router's SPA prerender step starts a Vite preview server that resolves the
10
+ // project from the working directory.
11
+ process.chdir(inline.root ?? config.root);
12
+ const builder = await createBuilder(inline);
13
+ await builder.buildApp();
14
+ // Vite/React Router leave handles open after the SPA prerender; nothing else to wait for.
15
+ if (exit) {
16
+ process.exit(0);
17
+ }
18
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/cli/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,qHAAqH;AACrH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,GAAuB,EAAE;IAClE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,mFAAmF;IACnF,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IACzB,0FAA0F;IAC1F,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function dev(): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { resolve } from 'node:path';
2
+ import { createServer } from 'vite';
3
+ import { loadConfig } from '../config.js';
4
+ import { Proxy } from '../server/proxy.js';
5
+ import { startIntegrations } from '../server/integrations.js';
6
+ import { createViteConfig } from '../vite.js';
7
+ export async function dev() {
8
+ const config = await loadConfig(resolve(process.cwd()));
9
+ const stop = startIntegrations(config.integrations, { log: console.log });
10
+ const server = await createServer(createViteConfig(config, new Proxy(config.integrations, { log: console.log })));
11
+ await server.listen();
12
+ server.printUrls();
13
+ const shutdown = () => {
14
+ stop();
15
+ void server.close().then(() => process.exit(0));
16
+ };
17
+ process.on('SIGINT', shutdown);
18
+ process.on('SIGTERM', shutdown);
19
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../src/cli/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,MAAM,YAAY,CAC/B,gBAAgB,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAC/E,CAAC;IAEF,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,SAAS,EAAE,CAAC;IACnB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,EAAE,CAAC;QACP,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type Target } from '../release/render.ts';
2
+ /** Reads the targets and the \`--flag value\` / \`--flag=value\` / \`--no-image\` options. */
3
+ export declare function parseArgs(args: string[]): {
4
+ help: boolean;
5
+ image: boolean;
6
+ platform: string | undefined;
7
+ name: string | undefined;
8
+ tag: string | undefined;
9
+ out: string;
10
+ targets: Target[];
11
+ port: number | undefined;
12
+ };
13
+ export declare function packageCommand(args: string[]): Promise<void>;
@@ -0,0 +1,115 @@
1
+ import { resolve } from 'node:path';
2
+ import { loadConfig } from '../config.js';
3
+ import { packageRelease } from '../release/package.js';
4
+ import { TARGETS } from '../release/render.js';
5
+ import { build } from './build.js';
6
+ const USAGE = `Usage: hashsome package [target...] [options]
7
+
8
+ Builds the project and writes what you need to deploy it, into ./release.
9
+
10
+ Targets (one or more; with none, \`package.targets\` in hashsome.config.ts):
11
+ plain The server (one file) and the client. Runs with just Node 24+. No Docker needed.
12
+ compose A Docker Compose file and the container image (image.tar).
13
+ helm A Helm chart for k3s/Kubernetes and the container image (image.tar).
14
+ image Only the container image (image.tar), for manifests you write yourself.
15
+
16
+ Options:
17
+ --platform <p> What the image runs on, e.g. linux/amd64 (default: package.platform, else this machine's)
18
+ --name <name> Image, service and chart name (default: package.name, else the package name)
19
+ --tag <tag> Image tag (default: the time, so each release has its own)
20
+ --out <dir> Where to write it (default: release)
21
+ --port <n> The port the server listens on in the image (default: package.port, else 3000)
22
+ --no-image Skip building the image (no Docker needed; compose and helm need one later)
23
+
24
+ Examples:
25
+ hashsome package helm --platform linux/amd64
26
+ hashsome package plain
27
+ `;
28
+ const VALUE_FLAGS = ['platform', 'name', 'tag', 'out', 'port'];
29
+ /** Reads the targets and the \`--flag value\` / \`--flag=value\` / \`--no-image\` options. */
30
+ export function parseArgs(args) {
31
+ const values = new Map();
32
+ const targets = [];
33
+ const flags = new Set();
34
+ for (let i = 0; i < args.length; i++) {
35
+ const arg = args[i];
36
+ if (!arg.startsWith('--')) {
37
+ if (!TARGETS.includes(arg)) {
38
+ throw new Error(`Unknown target "${arg}" (use ${TARGETS.join(', ')})`);
39
+ }
40
+ targets.push(arg);
41
+ continue;
42
+ }
43
+ const [key, inline] = arg.slice(2).split('=', 2);
44
+ if (key === 'no-image' || key === 'help') {
45
+ flags.add(key);
46
+ }
47
+ else if (VALUE_FLAGS.includes(key)) {
48
+ const value = inline ?? args[++i];
49
+ if (value === undefined) {
50
+ throw new Error(`--${key} needs a value`);
51
+ }
52
+ values.set(key, value);
53
+ }
54
+ else {
55
+ throw new Error(`Unknown option --${key}`);
56
+ }
57
+ }
58
+ const port = values.has('port') ? Number(values.get('port')) : undefined;
59
+ if (port !== undefined && (!Number.isInteger(port) || port < 1 || port > 65535)) {
60
+ throw new Error('--port must be a port number');
61
+ }
62
+ return {
63
+ help: flags.has('help'),
64
+ image: !flags.has('no-image'),
65
+ platform: values.get('platform'),
66
+ name: values.get('name'),
67
+ tag: values.get('tag'),
68
+ out: values.get('out') ?? 'release',
69
+ targets,
70
+ port,
71
+ };
72
+ }
73
+ export async function packageCommand(args) {
74
+ let options;
75
+ try {
76
+ options = parseArgs(args);
77
+ }
78
+ catch (error) {
79
+ console.error(`${error instanceof Error ? error.message : String(error)}\n\n${USAGE}`);
80
+ process.exit(1);
81
+ }
82
+ if (options.help) {
83
+ console.log(USAGE);
84
+ return;
85
+ }
86
+ const root = resolve(process.cwd());
87
+ const defaults = (await loadConfig(root)).package;
88
+ const targets = options.targets.length > 0 ? options.targets : (defaults.targets ?? []);
89
+ if (targets.length === 0) {
90
+ console.error(`Say what to package for: ${TARGETS.join(', ')}.\n\n${USAGE}`);
91
+ process.exit(1);
92
+ }
93
+ await build({ exit: false });
94
+ try {
95
+ const { out, image: ref } = await packageRelease({
96
+ root,
97
+ out: options.out,
98
+ name: options.name ?? defaults.name,
99
+ tag: options.tag,
100
+ platform: options.platform ?? defaults.platform,
101
+ port: options.port ?? defaults.port ?? 3000,
102
+ image: options.image,
103
+ targets: [...new Set(targets)],
104
+ });
105
+ console.log(`\nRelease (${[...new Set(targets)].join(', ')}) written to ${out}`);
106
+ if (ref) {
107
+ console.log(`\nImage: ${ref}\nOn the server: k3s ctr -n k8s.io images import image.tar`);
108
+ }
109
+ }
110
+ catch (error) {
111
+ console.error(error instanceof Error ? error.message : String(error));
112
+ process.exit(1);
113
+ }
114
+ process.exit(0);
115
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","sourceRoot":"","sources":["../../../src/cli/package.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAe,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBb,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAE/D,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAa,CAAC,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,UAAU,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzE,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,GAAa,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAiC,CAAC;QACjF,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YACzC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;aAAM,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAClC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,gBAAgB,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;QACvB,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;QAChC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QACxB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;QACtB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS;QACnC,OAAO;QACP,IAAI;KACL,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAc;IACjD,IAAI,OAAqC,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACxF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,MAAM,cAAc,CAAC;YAC/C,IAAI;YACJ,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;YACnC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;YAC/C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI;YAC3C,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;SAC/B,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;QACjF,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,4DAA4D,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function start(): Promise<void>;
@@ -0,0 +1,12 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { loadConfig } from '../config.js';
4
+ import { startServer } from '../server/production.js';
5
+ export async function start() {
6
+ const config = await loadConfig(resolve(process.cwd()));
7
+ if (!existsSync(join(config.root, 'build', 'client', 'index.html'))) {
8
+ console.error('No build found. Run `hashsome build` first.');
9
+ process.exit(1);
10
+ }
11
+ startServer(config);
12
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QACpE,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { Integration } from '@hashsome/core';
2
+ /** How a project is packaged for deployment: what `hashsome package` does without being told. */
3
+ export interface PackageConfig {
4
+ /** What to write: `plain` (the server bundle and client, runs with Node), `compose` (Docker Compose), `helm` (a Helm chart for k3s), `image` (just the container image, for your own manifests). Command-line targets win over this. */
5
+ targets?: ('plain' | 'compose' | 'helm' | 'image')[];
6
+ /** What the image runs on, e.g. `linux/amd64`. Default: the machine that builds it. */
7
+ platform?: string;
8
+ /** The image, service and chart name. Default: the package name. */
9
+ name?: string;
10
+ /** Where the server listens in the image. Default 3000. */
11
+ port?: number;
12
+ }
13
+ export interface HashsomeConfig {
14
+ /** Backends the runtime proxies to the browser. `@hashsome/runtime` ships no integrations of its
15
+ * own — install whichever you need (e.g. `@hashsome/integration.home-assistant`) and construct them
16
+ * here, typically reading connection details from your own environment variables. */
17
+ integrations?: Integration[];
18
+ port?: number;
19
+ host?: string;
20
+ /** Defaults for `hashsome package`, so deploying is `pnpm package` with no flags. */
21
+ package?: PackageConfig;
22
+ }
23
+ export interface ResolvedConfig {
24
+ root: string;
25
+ integrations: Integration[];
26
+ port: number;
27
+ host: string;
28
+ package: PackageConfig;
29
+ }
30
+ export declare function defineConfig(config: HashsomeConfig): HashsomeConfig;
31
+ export declare const CONFIG_FILE = "hashsome.config.ts";
32
+ /** Applies defaults to a config (and checks it). `PORT` and `HOST` in the environment win over the
33
+ * file, so a container can be told where to listen without rebuilding. */
34
+ export declare function resolveConfig(root: string, user: HashsomeConfig): ResolvedConfig;
35
+ /** Loads `<root>/hashsome.config.ts` (if present) and applies defaults. */
36
+ export declare function loadConfig(root: string): Promise<ResolvedConfig>;
@@ -0,0 +1,54 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ export function defineConfig(config) {
13
+ return config;
14
+ }
15
+ export const CONFIG_FILE = 'hashsome.config.ts';
16
+ /** Throws if two integrations were configured with the same `id` — each id is a claimed entity-ref
17
+ * prefix, and a silent collision (whichever integration was constructed last would simply win in
18
+ * every `Map`-keyed lookup) is exactly the kind of bug that's worth catching at startup. */
19
+ function assertUniqueIds(integrations) {
20
+ const seen = new Map();
21
+ for (const [index, integration] of integrations.entries()) {
22
+ const firstIndex = seen.get(integration.id);
23
+ if (firstIndex !== undefined) {
24
+ throw new Error(`Duplicate integration id "${integration.id}" (integrations[${firstIndex}] and ` +
25
+ `integrations[${index}]). Each integration's id becomes its entity-ref prefix ` +
26
+ `(e.g. "${integration.id}:some.entity") and must be unique — pass a distinct \`id\` ` +
27
+ 'to one of them.');
28
+ }
29
+ seen.set(integration.id, index);
30
+ }
31
+ }
32
+ /** Applies defaults to a config (and checks it). `PORT` and `HOST` in the environment win over the
33
+ * file, so a container can be told where to listen without rebuilding. */
34
+ export function resolveConfig(root, user) {
35
+ const integrations = user.integrations ?? [];
36
+ assertUniqueIds(integrations);
37
+ return {
38
+ root,
39
+ integrations,
40
+ port: Number(process.env.PORT ?? user.port ?? 3000),
41
+ host: process.env.HOST ?? user.host ?? '0.0.0.0',
42
+ package: user.package ?? {},
43
+ };
44
+ }
45
+ /** Loads `<root>/hashsome.config.ts` (if present) and applies defaults. */
46
+ export async function loadConfig(root) {
47
+ const file = join(root, CONFIG_FILE);
48
+ let user = {};
49
+ if (existsSync(file)) {
50
+ const mod = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ pathToFileURL(file).href)));
51
+ user = mod.default ?? {};
52
+ }
53
+ return resolveConfig(root, user);
54
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;;;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAqCzC,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD;;4FAE4F;AAC5F,SAAS,eAAe,CAAC,YAA2B;IAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,6BAA6B,WAAW,CAAC,EAAE,mBAAmB,UAAU,QAAQ;gBAC9E,gBAAgB,KAAK,0DAA0D;gBAC/E,UAAU,WAAW,CAAC,EAAE,6DAA6D;gBACrF,iBAAiB,CACpB,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED;0EAC0E;AAC1E,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAoB;IAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;IAC7C,eAAe,CAAC,YAAY,CAAC,CAAC;IAC9B,OAAO;QACL,IAAI;QACJ,YAAY;QACZ,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QACnD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,SAAS;QAChD,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE;KAC5B,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACrC,IAAI,IAAI,GAAmB,EAAE,CAAC;IAC9B,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,kCAAC,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC,CAErE,CAAC;QAEF,IAAI,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1 @@
1
+ export { defineConfig, type HashsomeConfig, type PackageConfig } from './config.ts';
@@ -0,0 +1,8 @@
1
+ // Node-only and JSX-free on purpose: `hashsome.config.ts` imports `defineConfig` from here and is
2
+ // loaded via a plain Node `import()` in the CLI (see `config.ts`'s `loadConfig()`), which both
3
+ // can't transform JSX and runs `config.ts`'s own `node:fs` import for real. Anything browser code
4
+ // imports — the React-facing pieces (`createLayout`, ...) —
5
+ // lives under the `@hashsome/runtime/app` subpath instead: importing *anything* from this file pulls
6
+ // in the whole module, and `config.ts`'s `node:fs` import throws immediately if that ever reaches
7
+ // a browser bundle (Vite externalizes Node builtins client-side as throwing stubs).
8
+ export { defineConfig } from './config.js';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,+FAA+F;AAC/F,kGAAkG;AAClG,4DAA4D;AAC5D,qGAAqG;AACrG,kGAAkG;AAClG,oFAAoF;AACpF,OAAO,EAAE,YAAY,EAA2C,MAAM,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Bundles a project's server into one file: the runtime, the project's `hashsome.config.ts` and every
3
+ * integration it imports, with their dependencies, so the file runs with just `node` and no
4
+ * `node_modules`. Secrets are not in it: the config reads them from the environment when it runs.
5
+ * Uses Vite's own server build, so there is no bundler of its own to install.
6
+ */
7
+ export declare function bundleServer({ root, outFile }: {
8
+ root: string;
9
+ outFile: string;
10
+ }): Promise<void>;
@@ -0,0 +1,50 @@
1
+ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { basename, dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { build } from 'vite';
5
+ /** The runtime's own entry for a packaged server, by path: it does not depend on how the project resolves `@hashsome/runtime`. Next to this file, as source in the repo and as built JavaScript when installed. */
6
+ const SERVE = fileURLToPath(new URL(`../serve${import.meta.url.endsWith('.ts') ? '.ts' : '.js'}`, import.meta.url));
7
+ /**
8
+ * Bundles a project's server into one file: the runtime, the project's `hashsome.config.ts` and every
9
+ * integration it imports, with their dependencies, so the file runs with just `node` and no
10
+ * `node_modules`. Secrets are not in it: the config reads them from the environment when it runs.
11
+ * Uses Vite's own server build, so there is no bundler of its own to install.
12
+ */
13
+ export async function bundleServer({ root, outFile }) {
14
+ const outDir = dirname(outFile);
15
+ // In the project, next to its config.
16
+ const entry = join(root, '.hashsome-server-entry.ts');
17
+ mkdirSync(outDir, { recursive: true });
18
+ writeFileSync(entry, [
19
+ `import config from ${JSON.stringify(join(root, 'hashsome.config.ts'))};`,
20
+ `import { serve } from ${JSON.stringify(SERVE)};`,
21
+ `serve(config, import.meta.url);`,
22
+ ].join('\n'));
23
+ try {
24
+ await build({
25
+ root,
26
+ configFile: false,
27
+ logLevel: 'warn',
28
+ // The runtime and the integrations are bundled in, not left to be installed.
29
+ ssr: { noExternal: true, target: 'node' },
30
+ build: {
31
+ ssr: entry,
32
+ outDir,
33
+ emptyOutDir: false,
34
+ minify: false,
35
+ target: 'node24',
36
+ rollupOptions: {
37
+ output: {
38
+ format: 'es',
39
+ entryFileNames: basename(outFile),
40
+ // Dependencies that are still CommonJS (express, ws) call `require`, which an ES module lacks.
41
+ banner: "import { createRequire as __hashsomeCreateRequire } from 'node:module';\nconst require = __hashsomeCreateRequire(import.meta.url);",
42
+ },
43
+ },
44
+ },
45
+ });
46
+ }
47
+ finally {
48
+ rmSync(entry, { force: true });
49
+ }
50
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../../src/release/bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAE7B,mNAAmN;AACnN,MAAM,KAAK,GAAG,aAAa,CACzB,IAAI,GAAG,CAAC,WAAW,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CACvF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAqC;IACrF,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,sCAAsC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC;IACtD,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,aAAa,CACX,KAAK,EACL;QACE,sBAAsB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,GAAG;QACzE,yBAAyB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG;QACjD,iCAAiC;KAClC,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,KAAK,CAAC;YACV,IAAI;YACJ,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,MAAM;YAChB,6EAA6E;YAC7E,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;YACzC,KAAK,EAAE;gBACL,GAAG,EAAE,KAAK;gBACV,MAAM;gBACN,WAAW,EAAE,KAAK;gBAClB,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,QAAQ;gBAChB,aAAa,EAAE;oBACb,MAAM,EAAE;wBACN,MAAM,EAAE,IAAI;wBACZ,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC;wBACjC,+FAA+F;wBAC/F,MAAM,EACJ,oIAAoI;qBACvI;iBACF;aACF;SACF,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type Target } from './render.ts';
2
+ export interface ReleaseOptions {
3
+ /** The project's folder. */
4
+ root: string;
5
+ /** Where the release goes, relative to `root`. Emptied first. Default `release`. */
6
+ out: string;
7
+ /** Default: the project's package name. */
8
+ name?: string | undefined;
9
+ /** Default: the time, so every release has a tag of its own and a node picks up the update. */
10
+ tag?: string | undefined;
11
+ /** What the image is built for, e.g. `linux/amd64`. Default: this machine's. */
12
+ platform?: string | undefined;
13
+ targets: readonly Target[];
14
+ /** Build the image and write `image.tar` for the targets that run one (`compose`, `helm`, `image`). Needs Docker. */
15
+ image: boolean;
16
+ port: number;
17
+ }
18
+ /**
19
+ * Writes the release for the chosen `targets` only: `plain` is the server bundled into one file next
20
+ * to the built client; `compose` and `helm` are run from an image, so they also get `image.tar`.
21
+ * `build` must have run (the client is read from `build/client`).
22
+ */
23
+ export declare function packageRelease(options: ReleaseOptions): Promise<{
24
+ out: string;
25
+ image?: string;
26
+ }>;
@@ -0,0 +1,102 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { chmodSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import { bundleServer } from './bundle.js';
6
+ import { chartDeployment, chartHelpers, chartIngress, chartNotes, chartService, chartValues, chartYaml, composeFile, composeReadme, dockerfile, envExample, helmReadme, imageRef, importScript, plainReadme, releaseReadme, safeName, } from './render.js';
7
+ const timestamp = () => new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
8
+ function hostPlatform() {
9
+ return process.arch === 'arm64' ? 'linux/arm64' : 'linux/amd64';
10
+ }
11
+ /** Runs a command, passing its output through; throws when it fails. */
12
+ function run(command, args, cwd) {
13
+ const result = spawnSync(command, args, { cwd, stdio: 'inherit' });
14
+ if (result.error || result.status !== 0) {
15
+ throw new Error(result.error?.message.includes('ENOENT')
16
+ ? `${command} is not installed (use --no-image to skip building the image)`
17
+ : `${command} ${args.join(' ')} failed`);
18
+ }
19
+ }
20
+ const write = (dir, files) => {
21
+ for (const [name, content] of Object.entries(files)) {
22
+ const file = join(dir, name);
23
+ mkdirSync(dirname(file), { recursive: true });
24
+ writeFileSync(file, content);
25
+ }
26
+ };
27
+ /**
28
+ * Writes the release for the chosen `targets` only: `plain` is the server bundled into one file next
29
+ * to the built client; `compose` and `helm` are run from an image, so they also get `image.tar`.
30
+ * `build` must have run (the client is read from `build/client`).
31
+ */
32
+ export async function packageRelease(options) {
33
+ const { root, targets } = options;
34
+ const needsImage = targets.includes('compose') || targets.includes('helm') || targets.includes('image');
35
+ const client = join(root, 'build', 'client');
36
+ if (!existsSync(join(client, 'index.html'))) {
37
+ throw new Error('No build found. Run `hashsome build` first.');
38
+ }
39
+ const pkg = existsSync(join(root, 'package.json'))
40
+ ? JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
41
+ : {};
42
+ const envFile = join(root, '.env.example');
43
+ const info = {
44
+ name: safeName(options.name ?? pkg.name ?? 'hashsome'),
45
+ tag: options.tag ?? timestamp(),
46
+ platform: options.platform ?? hostPlatform(),
47
+ port: options.port,
48
+ image: options.image && needsImage,
49
+ envExample: existsSync(envFile) ? readFileSync(envFile, 'utf8') : undefined,
50
+ };
51
+ const out = join(root, options.out);
52
+ rmSync(out, { recursive: true, force: true });
53
+ // The bundle is what every target is made from. It stays in the release only when asked for;
54
+ // otherwise it is just the folder the image is built from.
55
+ const keepPlain = targets.includes('plain');
56
+ mkdirSync(out, { recursive: true });
57
+ const plain = keepPlain ? join(out, 'plain') : mkdtempSync(join(tmpdir(), 'hashsome-release-'));
58
+ mkdirSync(plain, { recursive: true });
59
+ cpSync(client, join(plain, 'client'), { recursive: true });
60
+ await bundleServer({ root, outFile: join(plain, 'server.mjs') });
61
+ write(plain, { Dockerfile: dockerfile(info) });
62
+ if (keepPlain) {
63
+ write(plain, { 'README.md': plainReadme(info) });
64
+ }
65
+ try {
66
+ if (info.image) {
67
+ run('docker', ['buildx', 'build', '--platform', info.platform, '--load', '-t', imageRef(info), plain], root);
68
+ run('docker', ['save', imageRef(info), '-o', join(out, 'image.tar')], root);
69
+ }
70
+ }
71
+ finally {
72
+ if (!keepPlain) {
73
+ rmSync(plain, { recursive: true, force: true });
74
+ }
75
+ }
76
+ if (targets.includes('compose')) {
77
+ write(join(out, 'compose'), {
78
+ 'compose.yaml': composeFile(info),
79
+ '.env.example': envExample(info),
80
+ 'README.md': composeReadme(info),
81
+ });
82
+ }
83
+ if (targets.includes('helm')) {
84
+ const helm = join(out, 'helm');
85
+ write(helm, {
86
+ 'Chart.yaml': chartYaml(info),
87
+ 'values.yaml': chartValues(info),
88
+ 'templates/_helpers.tpl': chartHelpers(),
89
+ 'templates/deployment.yaml': chartDeployment(),
90
+ 'templates/service.yaml': chartService(),
91
+ 'templates/ingress.yaml': chartIngress(),
92
+ 'templates/NOTES.txt': chartNotes(),
93
+ 'import-image.sh': importScript(info),
94
+ 'README.md': helmReadme(info),
95
+ });
96
+ chmodSync(join(helm, 'import-image.sh'), 0o755);
97
+ }
98
+ write(out, {
99
+ 'README.md': releaseReadme(info, targets),
100
+ });
101
+ return { out, ...(info.image ? { image: imageRef(info) } : {}) };
102
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","sourceRoot":"","sources":["../../../src/release/package.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,MAAM,EACN,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,EACX,aAAa,EACb,UAAU,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,QAAQ,GAGT,MAAM,aAAa,CAAC;AAwBrB,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAEpF,SAAS,YAAY;IACnB,OAAO,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;AAClE,CAAC;AAED,wEAAwE;AACxE,SAAS,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,GAAW;IACvD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACnE,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACtC,CAAC,CAAC,GAAG,OAAO,+DAA+D;YAC3E,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAC1C,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,KAA6B,EAAE,EAAE;IAC3D,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAuB;IAEvB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAClC,MAAM,UAAU,GACd,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEvF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAChD,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAuB;QACrF,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAgB;QACxB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,UAAU,CAAC;QACtD,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,SAAS,EAAE;QAC/B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,YAAY,EAAE;QAC5C,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,UAAU;QAClC,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;KAC5E,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,6FAA6F;IAC7F,2DAA2D;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5C,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAChG,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,GAAG,CACD,QAAQ,EACR,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EACvF,IAAI,CACL,CAAC;YAEF,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE;YAC1B,cAAc,EAAE,WAAW,CAAC,IAAI,CAAC;YACjC,cAAc,EAAE,UAAU,CAAC,IAAI,CAAC;YAChC,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC;SACjC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC/B,KAAK,CAAC,IAAI,EAAE;YACV,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC;YAC7B,aAAa,EAAE,WAAW,CAAC,IAAI,CAAC;YAChC,wBAAwB,EAAE,YAAY,EAAE;YACxC,2BAA2B,EAAE,eAAe,EAAE;YAC9C,wBAAwB,EAAE,YAAY,EAAE;YACxC,wBAAwB,EAAE,YAAY,EAAE;YACxC,qBAAqB,EAAE,UAAU,EAAE;YACnC,iBAAiB,EAAE,YAAY,CAAC,IAAI,CAAC;YACrC,WAAW,EAAE,UAAU,CAAC,IAAI,CAAC;SAC9B,CAAC,CAAC;QAEH,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,EAAE;QACT,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC;KAC1C,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACnE,CAAC"}
@@ -0,0 +1,32 @@
1
+ /** The files of a release, as text. Pure: `package.ts` writes them out. */
2
+ export type Target = 'plain' | 'compose' | 'helm' | 'image';
3
+ export declare const TARGETS: readonly Target[];
4
+ export interface ReleaseInfo {
5
+ /** The project's name: the image, the compose service and the chart. A valid DNS label. */
6
+ name: string;
7
+ tag: string;
8
+ platform: string;
9
+ port: number;
10
+ /** The project's `.env.example`, shown to the person deploying. */
11
+ envExample?: string | undefined;
12
+ /** Whether `image.tar` is in the release. */
13
+ image: boolean;
14
+ }
15
+ export declare const imageRef: ({ name, tag }: Pick<ReleaseInfo, 'name' | 'tag'>) => string;
16
+ /** A project name made safe for an image, a service and a chart. */
17
+ export declare function safeName(raw: string): string;
18
+ export declare function dockerfile({ port }: Pick<ReleaseInfo, 'port'>): string;
19
+ export declare function plainReadme(info: ReleaseInfo): string;
20
+ export declare function composeFile(info: ReleaseInfo): string;
21
+ export declare function composeReadme(info: ReleaseInfo): string;
22
+ export declare function envExample(info: ReleaseInfo): string;
23
+ export declare function chartYaml(info: ReleaseInfo): string;
24
+ export declare function chartValues(info: ReleaseInfo): string;
25
+ export declare function chartHelpers(): string;
26
+ export declare function chartDeployment(): string;
27
+ export declare function chartService(): string;
28
+ export declare function chartIngress(): string;
29
+ export declare function chartNotes(): string;
30
+ export declare function importScript(info: ReleaseInfo): string;
31
+ export declare function helmReadme(info: ReleaseInfo): string;
32
+ export declare function releaseReadme(info: ReleaseInfo, targets: readonly Target[]): string;