@orkestrel/scaffold 0.0.67 → 0.0.69

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 (74) hide show
  1. package/dist/bin/main.js +67 -44
  2. package/dist/bin/main.js.map +1 -1
  3. package/dist/host/agents/templates/brief.md +9 -0
  4. package/dist/host/claude/agents/orkestrel.md +4 -4
  5. package/dist/host/claude/rules/names.md +15 -0
  6. package/dist/host/claude/rules/tests.md +33 -4
  7. package/dist/host/claude/rules/workspace.md +14 -2
  8. package/dist/host/dotfiles/prettierignore +3 -0
  9. package/dist/host/guides/README.md +65 -0
  10. package/dist/host/guides/abort.md +169 -0
  11. package/dist/host/guides/agent.md +1567 -0
  12. package/dist/host/guides/brief.md +1266 -0
  13. package/dist/host/guides/browser.md +2200 -0
  14. package/dist/host/guides/budget.md +196 -0
  15. package/dist/host/guides/codec.md +519 -0
  16. package/dist/host/guides/console.md +785 -0
  17. package/dist/host/guides/contract.md +1193 -0
  18. package/dist/host/guides/csv.md +541 -0
  19. package/dist/host/guides/database.md +2518 -0
  20. package/dist/host/guides/emitter.md +233 -0
  21. package/dist/host/guides/form.md +1791 -0
  22. package/dist/host/guides/html.md +717 -0
  23. package/dist/host/guides/indexeddb.md +505 -0
  24. package/dist/host/guides/interpret.md +1029 -0
  25. package/dist/host/guides/lsp.md +515 -0
  26. package/dist/host/guides/markdown.md +964 -0
  27. package/dist/host/guides/mcp.md +5554 -0
  28. package/dist/host/guides/middleware.md +927 -0
  29. package/dist/host/guides/msg.md +440 -0
  30. package/dist/host/guides/ndjson.md +120 -0
  31. package/dist/host/guides/ollama.md +380 -0
  32. package/dist/host/guides/pool.md +280 -0
  33. package/dist/host/guides/probe.md +1210 -0
  34. package/dist/host/guides/process.md +1620 -0
  35. package/dist/host/guides/program.md +1110 -0
  36. package/dist/host/guides/qualifier.md +854 -0
  37. package/dist/host/guides/queue.md +370 -0
  38. package/dist/host/guides/rater.md +330 -0
  39. package/dist/host/guides/reason.md +1122 -0
  40. package/dist/host/guides/relation.md +373 -0
  41. package/dist/host/guides/router.md +753 -0
  42. package/dist/host/guides/scaffold.md +192 -31
  43. package/dist/host/guides/sea.md +383 -0
  44. package/dist/host/guides/server.md +752 -0
  45. package/dist/host/guides/sqlite.md +330 -0
  46. package/dist/host/guides/sse.md +187 -0
  47. package/dist/host/guides/supervisor.md +4890 -0
  48. package/dist/host/guides/table.md +1556 -0
  49. package/dist/host/guides/template.md +280 -0
  50. package/dist/host/guides/terminal.md +1145 -0
  51. package/dist/host/guides/test.md +2969 -0
  52. package/dist/host/guides/timeout.md +252 -0
  53. package/dist/host/guides/tool.md +507 -0
  54. package/dist/host/guides/toolbox.md +1038 -0
  55. package/dist/host/guides/websocket.md +282 -0
  56. package/dist/host/guides/worker.md +615 -0
  57. package/dist/host/guides/workflow.md +1507 -0
  58. package/dist/host/guides/workspace.md +595 -0
  59. package/dist/host/manifest.json +1218 -10
  60. package/dist/host/tests/policy.test.ts +279 -2
  61. package/dist/host/tests/setupPolicy.ts +445 -6
  62. package/dist/src/core/index.cjs +38 -16
  63. package/dist/src/core/index.cjs.map +1 -1
  64. package/dist/src/core/index.d.cts +33 -9
  65. package/dist/src/core/index.d.ts +33 -9
  66. package/dist/src/core/index.js +37 -17
  67. package/dist/src/core/index.js.map +1 -1
  68. package/dist/src/server/index.cjs +1750 -1567
  69. package/dist/src/server/index.cjs.map +1 -1
  70. package/dist/src/server/index.d.cts +106 -24
  71. package/dist/src/server/index.d.ts +106 -24
  72. package/dist/src/server/index.js +1751 -1570
  73. package/dist/src/server/index.js.map +1 -1
  74. package/package.json +3 -3
@@ -0,0 +1,383 @@
1
+ # SEA
2
+
3
+ > The Node.js single executable application (SEA) builder: a pure-TypeScript pipeline
4
+ > that compresses assets, assembles the SEA blob, injects it into a copy of the host
5
+ > Node binary, and signs the result, with no WASM and no external tools.
6
+
7
+ Every export named here reaches a consumer through the `@orkestrel/sea` barrel, and its
8
+ source sits under [`src/server`](../src/server).
9
+
10
+ ## Overview
11
+
12
+ ### Build a single executable
13
+
14
+ Describe the build to `createSEA` — its entry script, output directory, assets, and compression — then `await sea.execute()` for the finished executable and its size:
15
+
16
+ ```ts
17
+ import { createSEA, formatSize } from '@orkestrel/sea'
18
+
19
+ const sea = createSEA({
20
+ name: 'myapp',
21
+ entry: { path: 'dist/server/serve.cjs' },
22
+ output: 'dist/sea',
23
+ assets: { 'model.gguf': 'models/model.gguf' },
24
+ compression: { paths: ['dist/app/browser'], mode: 'text' },
25
+ windows: { terminal: false },
26
+ timeout: 30_000,
27
+ })
28
+
29
+ const result = await sea.execute()
30
+ process.stdout.write(
31
+ `${result.executable} ${formatSize(result.size)} ${String(result.duration)}ms\n`,
32
+ )
33
+ ```
34
+
35
+ `sea.execute()` runs the pipeline — compress assets, generate the blob, assemble and sign the executable — and transitions `sea.status` from `'idle'` to `'active'` to `'done'` (or `'error'`). `sea.emitter` reports progress on `compress`, `progress` (once per compressed file, with `current`/`total` counts), `blob`, `assemble`, and `complete`.
36
+
37
+ When an `assets` path is compressed by `compression`, blob generation embeds the Brotli output under that asset's original key. Uncompressed entries keep their original paths, the compression manifest still reports each output path, and SEA does not mutate the caller's `assets` record.
38
+
39
+ On Windows, `SEAOptions.windows.terminal` (default `true`) selects whether the executable keeps its console window: `false` builds a GUI-subsystem binary that launches without a terminal, at the cost of detached stdio when no console is attached (console output is discarded).
40
+
41
+ On Windows, `SEAOptions.windows.sign` is optional Authenticode signing. When present, the assembled executable is signed with `signtool` (a certificate `file` with its `password`, or a store `thumbprint` — exactly one of those) and verified as the last content mutation before the atomic finalize; when absent, the output stays unsigned (`SEAResult.signed` is `false`). `buildSignCommand` builds the `signtool` argv and is available standalone.
42
+
43
+ `SEAOptions.entry` is a `SEAEntryOptions` object (`{ path, format? }`) rather than a bare path — `format` selects the entry module format (`'cjs'` default, or `'esm'` on Node >= 25.7). Every domain failure throws a `SEAError` carrying a machine-readable `SEAErrorCode`; narrow a caught value with `isSEAError`. `SEAResult` additionally reports `signed`, `stripped`, and the patched `terminal` flag (Windows only).
44
+
45
+ `ROOM` names the applicability limit the host binary itself imposes: a layout the injector cannot write into. The injector reads that layout from the target's headers and load commands and refuses under `ROOM` before any byte reaches the output, for a PE whose header slack is smaller than one section entry, a Mach-O whose first section sits inside the space another load command needs, a Mach-O carrying no `__LINKEDIT` segment, and a `__LINKEDIT` segment carrying sections. Where the injector takes a measurement, that measurement rides in `context`: `availableHeaderSpace` against `requiredHeaderSpace` for the PE case, and `firstSectionOffset` against `requiredOffset` for the load-command case. The `__LINKEDIT` cases carry the executable path alone, because the layout is the whole finding. `INJECT` keeps the failures another host does not clear: a refusal to replace a resource that already exists while `overwrite` is `false`, a malformed resource directory, and a defect the injector reports against its own construction or a write it already made. Retry a `ROOM` build on another host, and read an `INJECT` code against the options you passed, the resource tree in the host binary, or the injector itself.
46
+
47
+ `SEAOptions.timeout` bounds each spawned blob-generation, stripping, signing, and verification command in milliseconds. Omit it to leave those commands unbounded.
48
+
49
+ ## Surface
50
+
51
+ ### Classes
52
+
53
+ | API | Kind | Summary |
54
+ | -------------- | ----- | -------------------------------------------------------------------------- |
55
+ | `SEA` | class | Runs a Node.js single executable application build to completion. |
56
+ | `Injector` | class | Writes a named resource into a PE, ELF, or Mach-O executable in place. |
57
+ | `Asset` | class | Holds one named asset's key, bytes, and compression state. |
58
+ | `AssetManager` | class | Collects named assets from a SEA blob or from disk and serves them by key. |
59
+
60
+ ### Factories
61
+
62
+ | API | Kind | Summary |
63
+ | -------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
64
+ | `createSEA` | function | Creates a SEA build orchestrator over the given options and returns it as a `SEAInterface`, the published contract a caller holds instead of the `SEA` class. |
65
+ | `createInjector` | function | Creates a resource injector bound to one target executable and returns it as an `InjectorInterface`, with the executable's format already detected from its header. |
66
+ | `createAsset` | function | Creates one named asset from a key and a content buffer and returns it as an `AssetInterface`, with `compressed` inferred from the key where the input leaves it unset. |
67
+ | `createAssetManager` | function | Creates an asset collection and returns it as an `AssetManagerInterface`, already carrying whatever assets the running SEA blob embeds. |
68
+
69
+ ### Constants
70
+
71
+ A `Shape` cell holds the constant's declared type.
72
+
73
+ | API | Kind | Shape | Summary |
74
+ | --------------------------------- | ----- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
75
+ | `SEA_SENTINEL_FUSE` | const | `string` | Holds the SEA sentinel fuse value embedded in the Node.js binary, `NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2`. |
76
+ | `SEA_BLOB_RESOURCE` | const | `string` | Names the SEA blob resource in the executable, `NODE_SEA_BLOB`. |
77
+ | `DEFAULT_SEA_COMPRESSION_QUALITY` | const | `number` | Holds the default Brotli compression quality level, 11, the maximum Brotli accepts. |
78
+ | `WINDOWS_SUBSYSTEM_GUI` | const | `number` | Holds the Windows PE subsystem value for a GUI application, 2, which launches without a terminal window. |
79
+ | `WINDOWS_SUBSYSTEM_CONSOLE` | const | `number` | Holds the Windows PE subsystem value for a console application, 3. |
80
+ | `BROTLI_EXTENSION` | const | `string` | Names the file extension indicating Brotli compression, `.br`. |
81
+ | `SKIP_EXTENSIONS` | const | `ReadonlySet<string>` | Lists the file extensions Brotli compression skips, the already-compressed archive, image, font, and media formats. |
82
+ | `PE_MAGIC` | const | `number` | Holds the DOS MZ header magic, 0x5a4d, the first two bytes of a PE file. |
83
+ | `PE_SIGNATURE` | const | `number` | Holds the PE signature, 0x00004550, the bytes `PE\0\0` read as a 32-bit value. |
84
+ | `PE32_MAGIC` | const | `number` | Holds the PE32 optional header magic, 0x10b. |
85
+ | `PE32_PLUS_MAGIC` | const | `number` | Holds the PE32+ optional header magic, 0x20b, the 64-bit form. |
86
+ | `ELF_MAGIC` | const | `number` | Holds the ELF magic, 0x7f454c46, the bytes 0x7F `E` `L` `F` read as a 32-bit big-endian value. |
87
+ | `ELF_CLASS_64` | const | `number` | Holds the ELF 64-bit class identifier, 2. |
88
+ | `ELF_DATA_LSB` | const | `number` | Holds the ELF little-endian data encoding, 1. |
89
+ | `ELF_PT_NOTE` | const | `number` | Holds the ELF program header type for a note segment, 4. |
90
+ | `ELF_PT_LOAD` | const | `number` | Holds the ELF program header type for a loadable segment, 1. |
91
+ | `ELF_PT_PHDR` | const | `number` | Holds the ELF program header type for the program header table itself, 6. |
92
+ | `ELF_PF_R` | const | `number` | Holds the ELF segment permission flag marking a segment readable, 4. |
93
+ | `ELF_PAGE_SIZE` | const | `number` | Holds the page size an injected ELF segment is aligned to, 0x1000. |
94
+ | `MACHO_MAGIC_64` | const | `number` | Holds the Mach-O 64-bit magic, 0xfeedfacf, in little-endian byte order. |
95
+ | `MACHO_LC_SEGMENT_64` | const | `number` | Holds the Mach-O `LC_SEGMENT_64` load command, 0x19. |
96
+ | `PE_RT_RCDATA` | const | `number` | Holds the PE resource type `RT_RCDATA` for raw data, 10. |
97
+ | `PE_RESOURCE_DIR_SIZE` | const | `number` | Holds the size of `IMAGE_RESOURCE_DIRECTORY` in bytes, 16. |
98
+ | `PE_RESOURCE_ENTRY_SIZE` | const | `number` | Holds the size of `IMAGE_RESOURCE_DIRECTORY_ENTRY` in bytes, 8. |
99
+ | `PE_RESOURCE_DATA_ENTRY_SIZE` | const | `number` | Holds the size of `IMAGE_RESOURCE_DATA_ENTRY` in bytes, 16. |
100
+ | `PE_SECTION_HEADER_SIZE` | const | `number` | Holds the PE section header size in bytes, 40. |
101
+ | `PE_RESOURCE_SUBDIR_FLAG` | const | `number` | Holds the high bit mask marking a resource directory entry offset as a subdirectory, 0x80000000. |
102
+ | `PE_RESOURCE_NAME_FLAG` | const | `number` | Holds the high bit mask marking a resource entry as named rather than integer-identified, 0x80000000. |
103
+ | `PE_SCN_INITIALIZED_DATA` | const | `number` | Marks a section as containing initialized data, 0x00000040. |
104
+ | `PE_SCN_MEM_READ` | const | `number` | Marks a section as readable, 0x40000000. |
105
+ | `SEA_PLATFORMS` | const | `Readonly<Record<string, SEAPlatform>>` | Holds the platform-specific SEA build configurations, keyed by `process.platform` for `win32`, `darwin`, and `linux`. |
106
+ | `SEA_COMPRESSION_MODE_VALUES` | const | `Readonly<Record<SEACompressionMode, number>>` | Maps a `SEACompressionMode` to its numeric Brotli mode value: `generic` to 0, `text` to 1, and `font` to 2. |
107
+ | `DEFAULT_ENTRY_FORMAT` | const | `SEAEntryFormat` | Names the default SEA entry point module format when none is specified, `cjs`. |
108
+
109
+ ### Helpers and errors
110
+
111
+ | API | Kind | Summary |
112
+ | --------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
113
+ | `isExecutableFormat` | function | Checks whether a value is a valid `ExecutableFormat`. |
114
+ | `resolvePlatform` | function | Resolves the effective platform configuration. |
115
+ | `isPlatformSupported` | function | Checks whether the current or named platform is supported for SEA builds. |
116
+ | `ensureExists` | function | Asserts that a path exists, throwing a coded `SEAError` if not. |
117
+ | `isCompressible` | function | Checks whether a file's extension is outside `SKIP_EXTENSIONS`, so Brotli compression applies to it. |
118
+ | `walkDirectory` | function | Walks a directory recursively and returns every file path it finds, relative to the base and skipping symlinks. |
119
+ | `executeShell` | function | Executes a command synchronously and returns stdout. |
120
+ | `redactCommand` | function | Redacts password arguments from a shell command, so the command is safe to include in an error message. |
121
+ | `computeSize` | function | Computes a size comparison between original and compressed byte counts. |
122
+ | `compressFile` | function | Brotli-compresses a single file, writing the output alongside it. |
123
+ | `compressDirectory` | function | Compresses all compressible files in a directory tree. |
124
+ | `alignTo` | function | Rounds a value up to the next multiple of an alignment boundary. |
125
+ | `readPEOffset` | function | Reads the PE header offset from a Windows executable. |
126
+ | `readU16` | function | Reads a 16-bit unsigned integer from a file descriptor. |
127
+ | `readU32` | function | Reads a 32-bit unsigned little-endian integer from a file descriptor. |
128
+ | `readU64` | function | Reads a 64-bit unsigned little-endian integer from a file descriptor. |
129
+ | `writeU16` | function | Writes a 16-bit unsigned integer to a file descriptor. |
130
+ | `writeU32` | function | Writes a 32-bit unsigned little-endian integer to a file descriptor. |
131
+ | `writeU64` | function | Writes a 64-bit unsigned little-endian integer to a file descriptor. |
132
+ | `appendFile` | function | Appends a source file to a target file, streaming in fixed-size chunks. |
133
+ | `stripTrailingNulls` | function | Truncates a NUL-padded binary name field at its first NUL character. |
134
+ | `isPEExecutable` | function | Checks whether a file is a Windows PE executable. |
135
+ | `patchPESubsystem` | function | Patches the PE subsystem field in a Windows executable. |
136
+ | `stripPESignature` | function | Removes the Authenticode signature from a PE executable by zeroing the security directory entry in the optional header. |
137
+ | `buildSignCommand` | function | Builds the `signtool sign` argv for signing a Windows executable. |
138
+ | `formatSize` | function | Formats a byte count as a human-readable string. |
139
+ | `ensureSafeKey` | function | Asserts that an asset key is safe to use as a relative filesystem/archive key. |
140
+ | `ensureContained` | function | Asserts that `path` (resolved against `base`) real-path-resolves to a location inside `base`, defeating a symlink escape. |
141
+ | `ensureSafeName` | function | Asserts that `name` is a single safe path segment suitable as an output executable base name. |
142
+ | `finalizeExecutable` | function | Finalizes a built executable by durably flushing it to disk and atomically moving it into place. |
143
+ | `syncDirectory` | function | Fsyncs a directory to durably persist a prior file rename/create within it. |
144
+ | `buildBlobConfig` | function | Builds the Node.js `--experimental-sea-config` JSON object for a SEA blob. |
145
+ | `patchSentinelFuse` | function | Patches the sentinel fuse in a binary from `:0` to `:1`. |
146
+ | `buildELFNoteHeader` | function | Builds an ELF `PT_NOTE` entry's header bytes (namesz/descsz/type + padded name) for the SEA blob note, without the blob body itself. |
147
+ | `alignELFNoteSize` | function | Aligns an ELF note component size to its four-byte boundary. |
148
+ | `isPowerOfTwo` | function | Checks whether a number is a nonzero power of two. |
149
+ | `copyRange` | function | Copies a byte range from one open file descriptor to another, streaming in fixed-size chunks instead of buffering the whole range in memory. |
150
+ | `openBrowser` | function | Launches the system default browser at an http(s) URL. |
151
+ | `SEAError` | class | Represents the coded base error for every failure raised by the SEA build. |
152
+ | `isSEAError` | function | Checks whether a value is a `SEAError`. |
153
+ | `ShellError` | class | Represents an error thrown when a shell command executed through `executeShell` exits non-zero. |
154
+ | `isShellError` | function | Checks whether a value is a `ShellError`. |
155
+
156
+ ### Types
157
+
158
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an optional member and `plus` introducing its call-signature members, and a type alias's own type literal with a union's arms escaped as `\|`. An extended interface's name comes before `plus`, with the members it adds after.
159
+
160
+ | API | Kind | Shape | Summary |
161
+ | ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
162
+ | `SEACompressionSize` | interface | `{ original, compressed, ratio }` | Represents a size comparison between original and compressed data. |
163
+ | `SEACompressionMode` | type | `'generic' \| 'text' \| 'font'` | Names a Brotli compression mode. |
164
+ | `SEACompressionResult` | interface | `{ input, output, size }` | Represents the result of compressing a single file. |
165
+ | `SEACompressionManifest` | interface | `{ assets, total }` | Summarizes all compressed assets. |
166
+ | `SEAProgress` | interface | `{ path, current, total }` | Represents the progress reported while compressing a directory. |
167
+ | `SEACompressionHandler` | type | `(result: SEACompressionResult) => void` | Describes the callback `compressDirectory` invokes after each file it compresses. |
168
+ | `SEABrotliOptions` | interface | `{ mode?, quality? }` | Controls how Brotli encodes one file. |
169
+ | `SEACompressionOptions` | interface | `SEABrotliOptions plus { paths }` | Controls Brotli compression of one or more directories. |
170
+ | `SEAPlatform` | interface | `{ executable, remove?, sign?, verify? }` | Represents a platform-specific SEA build configuration. |
171
+ | `SEAShellOptions` | interface | `{ cwd?, env?, timeout?, signal? }` | Configures the execution of a shell command. |
172
+ | `ExecutableFormat` | type | `'pe' \| 'elf' \| 'macho'` | Names an executable binary format detected from file header magic bytes. |
173
+ | `ELFNoteHeader` | interface | `{ header, total }` | Holds an ELF `PT_NOTE` entry's header bytes and the on-disk size of the whole entry. |
174
+ | `ELFProgramHeader` | interface | `{ type, flags, offset, vaddr, paddr, filesz, memsz, align }` | Holds one ELF64 program header entry. |
175
+ | `PEResourceLeaf` | interface | `{ typeId, typeName, nameId, nameName, language, codePage, dataRVA, dataSize }` | Holds one leaf of a PE resource directory tree. |
176
+ | `PEResourceEntry` | interface | `{ language, codePage, leafIndex, dataSize }` | Holds one language entry of a PE resource name directory. |
177
+ | `PESection` | interface | `{ name, virtualSize, virtualAddress, rawSize, rawOffset, characteristics, headerOffset }` | Holds one PE section table entry. |
178
+ | `InjectorOptions` | interface | `{ executable, resource, blob, fuse?, macho?, overwrite? }` | Configures the injection of a resource into an executable. |
179
+ | `InjectorMachOOptions` | interface | `{ segment? }` | Configures Mach-O specific injector behavior. |
180
+ | `InjectorInterface` | interface | `{ format } plus inject` | Represents a cross-platform binary resource injector. |
181
+ | `AssetInput` | interface | `{ key, content, compressed? }` | Holds the minimal data needed to create an `AssetInterface`. |
182
+ | `AssetInterface` | interface | `{ key, content, compressed }` | Represents a single named asset wrapping its key, content buffer, and compression flag. |
183
+ | `AssetManagerEventMap` | type | `{ register, load, clear, error }` | Lists the events emitted by an `AssetManagerInterface`. |
184
+ | `AssetManagerOptions` | interface | `{ on?, error?, root?, assets? }` | Configures the creation of an `AssetManagerInterface`. |
185
+ | `AssetManagerInterface` | interface | `{ emitter, count } plus asset, assets, keys, register, load, clear, destroy` | Represents a named asset collection with SEA and disk loading. |
186
+ | `SEAStatus` | type | `'idle' \| 'active' \| 'done' \| 'error'` | Names the overall status of the SEA build. |
187
+ | `SEAErrorCode` | type | `'PLATFORM' \| 'ENTRY' \| 'ASSET' \| 'BLOB' \| 'FORMAT' \| 'INJECT' \| 'ROOM' \| 'FUSE' \| 'SIGN' \| 'SHELL' \| 'TIMEOUT' \| 'ABORT' \| 'OUTPUT' \| 'STATE' \| 'BROWSER'` | Names the machine-readable error code carried by every `SEAError`. |
188
+ | `SEAEntryFormat` | type | `'cjs' \| 'esm'` | Names the SEA entry point module format. |
189
+ | `SEAEntryOptions` | interface | `{ path, format? }` | Describes the SEA entry point. |
190
+ | `SEABlobOptions` | interface | `{ cache?, snapshot? }` | Controls generated SEA blob behavior. |
191
+ | `SEAEventMap` | type | `{ compress, progress, blob, assemble, complete, error }` | Lists the events emitted by a `SEAInterface`. |
192
+ | `SEAOptions` | interface | `{ on?, error?, name, entry, output, assets?, compression?, windows?, root?, signal?, timeout?, blob? }` | Configures the creation of a SEA build. |
193
+ | `SEAWindowsOptions` | interface | `{ terminal?, sign? }` | Configures Windows-specific SEA build behavior. |
194
+ | `SEAWindowsSignOptions` | interface | `{ file?, password?, thumbprint?, timestamp?, digest? }` | Describes the Windows Authenticode signing options passed through to `signtool`. |
195
+ | `SEAResult` | interface | `{ executable, platform, size, duration, compression?, signed, stripped, terminal? }` | Represents the result of a successful SEA build. |
196
+ | `SEAInterface` | interface | `{ emitter, status } plus execute, destroy` | Represents a SEA build orchestrator. |
197
+
198
+ ## Methods
199
+
200
+ The public methods of each behavioral interface — one table per type, keyed by its backticked name, every call-signature member listed. A `readonly` data member stays in the interface's `Shape` cell and off these tables: `format` on `InjectorInterface`, `emitter` and `status` on `SEAInterface`, `emitter` and `count` on `AssetManagerInterface`. Each concrete class implements its interface exactly, so this doubles as the class's instance-method surface.
201
+
202
+ #### `SEAInterface`
203
+
204
+ `execute` runs the build pipeline; `destroy` tears down the emitter.
205
+
206
+ | Method | Returns | Summary |
207
+ | --------- | -------------------- | -------------------------------------------------------------------------- |
208
+ | `execute` | `Promise<SEAResult>` | Runs the compress, blob, and assemble stages and returns the build result. |
209
+ | `destroy` | `void` | Tears down the emitter. |
210
+
211
+ #### `InjectorInterface`
212
+
213
+ `inject` performs the one-shot resource write.
214
+
215
+ | Method | Returns | Summary |
216
+ | -------- | ------- | ---------------------------------------------- |
217
+ | `inject` | `void` | Injects the resource data into the executable. |
218
+
219
+ #### `AssetManagerInterface`
220
+
221
+ `asset` / `assets` are the singular/plural accessors; `register` / `load` add assets; `clear` / `destroy` are the lifecycle pair.
222
+
223
+ | Method | Returns | Summary |
224
+ | ---------- | ----------------------------- | ----------------------------------------------------------------------------- |
225
+ | `asset` | `AssetInterface \| undefined` | Looks up one registered asset by key. |
226
+ | `assets` | `readonly AssetInterface[]` | Lists every registered asset, in registration order. |
227
+ | `keys` | `readonly string[]` | Lists every registered asset key, in registration order. |
228
+ | `register` | `void` | Registers one asset, or every asset of a list. |
229
+ | `load` | `void` | Loads the configured assets from disk, and registers nothing inside SEA mode. |
230
+ | `clear` | `void` | Removes every registered asset without destroying the manager. |
231
+ | `destroy` | `void` | Clears every registered asset and tears down the emitter. |
232
+
233
+ ## Usage
234
+
235
+ ### Injecting a resource directly
236
+
237
+ Construct an injector over an already-assembled executable, read the format it detected, and call `inject` to write the blob into it:
238
+
239
+ ```ts
240
+ import { createInjector } from '@orkestrel/sea'
241
+
242
+ const injector = createInjector({
243
+ executable: 'dist/sea/myapp.exe',
244
+ resource: 'NODE_SEA_BLOB',
245
+ blob: 'dist/sea/sea-prep.blob',
246
+ fuse: 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2',
247
+ macho: { segment: 'NODE_SEA' },
248
+ })
249
+
250
+ injector.format // 'pe' | 'elf' | 'macho'
251
+ injector.inject()
252
+ ```
253
+
254
+ ### Assets
255
+
256
+ Create an asset from a buffer, register it with a manager configured to load more from disk, then read the collection back and tear it down:
257
+
258
+ ```ts
259
+ import { createAsset, createAssetManager } from '@orkestrel/sea'
260
+
261
+ const asset = createAsset({ key: 'client.html.br', content: compressedBuffer })
262
+ asset.key // 'client.html.br'
263
+ asset.compressed // true (inferred from .br extension)
264
+
265
+ const manager = createAssetManager({
266
+ root: process.cwd(),
267
+ assets: { 'client.html.br': 'dist/client/client.html.br' },
268
+ })
269
+ manager.register(asset)
270
+ manager.load() // reads the configured assets outside SEA mode; no-op inside SEA mode
271
+ manager.asset('client.html.br')
272
+ manager.assets()
273
+ manager.keys()
274
+ manager.clear()
275
+ manager.destroy()
276
+ ```
277
+
278
+ ### Boundary and formatting helpers
279
+
280
+ Every helper the build pipeline runs on is exported too, from the shell boundary and the path assertions to the fixed-width binary readers, the PE patches, and the size formatter:
281
+
282
+ ```ts
283
+ import {
284
+ executeShell,
285
+ redactCommand,
286
+ isShellError,
287
+ resolvePlatform,
288
+ isPlatformSupported,
289
+ ensureExists,
290
+ isCompressible,
291
+ walkDirectory,
292
+ computeSize,
293
+ compressFile,
294
+ compressDirectory,
295
+ formatSize,
296
+ isExecutableFormat,
297
+ readPEOffset,
298
+ readU16,
299
+ readU32,
300
+ readU64,
301
+ writeU16,
302
+ writeU32,
303
+ writeU64,
304
+ appendFile,
305
+ stripTrailingNulls,
306
+ alignTo,
307
+ isPEExecutable,
308
+ patchPESubsystem,
309
+ stripPESignature,
310
+ patchSentinelFuse,
311
+ ensureContained,
312
+ ensureSafeName,
313
+ openBrowser,
314
+ buildSignCommand,
315
+ syncDirectory,
316
+ alignELFNoteSize,
317
+ isPowerOfTwo,
318
+ } from '@orkestrel/sea'
319
+
320
+ try {
321
+ executeShell(['node', '--version'])
322
+ } catch (error) {
323
+ if (isShellError(error)) {
324
+ error.stdout // captured stdout Buffer
325
+ error.stderr // captured stderr Buffer
326
+ }
327
+ }
328
+
329
+ resolvePlatform() // SEAPlatform for process.platform, or undefined
330
+ isPlatformSupported() // true on win32 / darwin / linux
331
+
332
+ ensureExists('dist/server/serve.cjs', 'entry file is missing')
333
+ walkDirectory('dist/app/browser') // every relative file path under the directory
334
+ isCompressible('dist/app/browser/index.html') // true — not in SKIP_EXTENSIONS
335
+
336
+ const size = computeSize(1000, 400) // { original: 1000, compressed: 400, ratio: 0.4 }
337
+ compressFile('dist/index.html', 'dist/index.html.br')
338
+ compressDirectory('dist/app/browser', { mode: 'text' })
339
+
340
+ formatSize(size.compressed) // '400 B'
341
+
342
+ isExecutableFormat('elf') // true
343
+
344
+ const fd = 0 // an open file descriptor from openSync in real usage
345
+ // readPEOffset(fd) / readU16(fd, offset) / writeU16(fd, offset, value)
346
+ // readU32(fd, offset) / readU64(fd, offset) — 32- and 64-bit little-endian reads
347
+ // writeU32(fd, offset, value) / writeU64(fd, offset, value) — the matching writes
348
+ // isPEExecutable(path) / patchPESubsystem(path, subsystem) / stripPESignature(path)
349
+ // patchSentinelFuse(executable, fuse)
350
+ // appendFile('dist/sea/app', 'dist/sea/sea-prep.blob') — streams the blob onto the binary
351
+
352
+ stripTrailingNulls('.rsrc\0\0\0') // '.rsrc' — a NUL-padded PE section name field
353
+
354
+ ensureContained('/dist/app', 'browser') // real, symlink-resolved path inside the base root
355
+
356
+ openBrowser('http://localhost:3000') // best-effort launch of the system default browser
357
+ ensureSafeName('myapp') // ok; throws SEAError('ASSET', ...) for '../evil' or 'a/b'
358
+
359
+ buildSignCommand({ thumbprint: 'AABBCCDDEEFF00112233445566778899AABBCCDD' }, 'dist/sea/app.exe')
360
+ // ['signtool', 'sign', '/fd', 'sha256', '/sha1', 'AABBCCDDEEFF00112233445566778899AABBCCDD', 'dist/sea/app.exe']
361
+
362
+ syncDirectory('/dist/sea') // fsync a directory to durably persist a prior rename/create; no-op on win32
363
+
364
+ redactCommand(['signtool', 'sign', '/p', 'hunter2']) // ['signtool', 'sign', '/p', '***']
365
+ alignELFNoteSize(10) // 12 — the next four-byte ELF note boundary
366
+ alignTo(4097, 4096) // 8192 — the general form behind every format's alignment
367
+ isPowerOfTwo(4096) // true
368
+ ```
369
+
370
+ ## Tests
371
+
372
+ - [`tests/guides.test.ts`](../tests/guides.test.ts) — the `## Surface` ↔ `src/server` bijection (value and type exports), the `SEAInterface` ↔ `SEA`, `InjectorInterface` ↔ `Injector`, and `AssetManagerInterface` ↔ `AssetManager` method bijections, and the equality gate: every `Summary` cell against its declaration's description paragraph, the titled `Build a single executable` fence against the `@example` block of that title (pinned so the titled pair cannot be retired silently), and the README pitch against this guide's tagline. It also runs the flagship fences and asserts the values their comments claim.
373
+ - [`tests/src/server/seas/SEA.test.ts`](../tests/src/server/seas/SEA.test.ts) — the build pipeline end to end: the status transitions, the emitted `compress` / `progress` / `blob` / `assemble` / `complete` events, the compressed-asset key rewrite that leaves the caller's `assets` record alone, abort through `SEAOptions.signal`, the per-command timeout, and the `windows.sign` option validation.
374
+ - [`tests/src/server/injectors/Injector.test.ts`](../tests/src/server/injectors/Injector.test.ts) — format detection from the header magic, and injection into synthetic PE, ELF, and Mach-O fixtures, including the `ROOM` refusals a host layout forces and the `INJECT` failures it does not.
375
+ - [`tests/src/server/assets/Asset.test.ts`](../tests/src/server/assets/Asset.test.ts) — the key, the content buffer, and the `compressed` flag inferred from a `.br` suffix or taken from the input.
376
+ - [`tests/src/server/assets/AssetManager.test.ts`](../tests/src/server/assets/AssetManager.test.ts) — registration, the singular and plural accessors in registration order, `load` from disk with an `error` event per missing path, `clear`, and `destroy`.
377
+ - [`tests/src/server/helpers.test.ts`](../tests/src/server/helpers.test.ts) — every exported helper against real files and real processes: the shell boundary and its `ShellError`, the path and key assertions including symlink escape, Brotli compression and its size arithmetic, the fixed-width binary readers and writers, the PE subsystem and signature patches, the sentinel fuse patch, the ELF note header, the streaming copy and append, the signing argv, and the browser launch.
378
+ - [`tests/src/server/factories.test.ts`](../tests/src/server/factories.test.ts) — each factory returns the published contract and honors the options it is given.
379
+ - [`tests/src/server/validators.test.ts`](../tests/src/server/validators.test.ts) — `isExecutableFormat` accepts `pe`, `elf`, and `macho` and stays total for every other value.
380
+
381
+ ## See also
382
+
383
+ - [`README.md`](README.md) — the guides index.