@xova/matrix 0.1.0 → 0.1.2
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/README.md +76 -6
- package/README.zh-CN.md +76 -6
- package/dist/archive.js +1 -1
- package/dist/artifact.js +1 -0
- package/dist/cli-args.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/config.js +1 -1
- package/dist/defaults.d.ts +7 -2
- package/dist/defaults.js +1 -1
- package/dist/env.d.ts +3 -0
- package/dist/env.js +1 -0
- package/dist/esbuild.d.ts +5 -0
- package/dist/esbuild.js +1 -0
- package/dist/exec.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/plan.js +1 -1
- package/dist/rollup.d.ts +5 -0
- package/dist/rollup.js +1 -0
- package/dist/runtime.d.ts +17 -0
- package/dist/runtime.js +1 -0
- package/dist/schema.d.ts +16 -9
- package/dist/schema.js +1 -1
- package/dist/typegen.js +2 -0
- package/dist/types.d.ts +34 -18
- package/dist/unplugin.d.ts +15 -0
- package/dist/unplugin.js +2 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.js +1 -0
- package/dist/webpack.d.ts +5 -0
- package/dist/webpack.js +1 -0
- package/package.json +24 -2
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Define projects once, then run development, builds, previews, and custom command
|
|
|
15
15
|
- Custom environment names such as `qa` and `uat`
|
|
16
16
|
- Layered environment variables with dotenv and shell overrides
|
|
17
17
|
- Interactive product and environment selection
|
|
18
|
-
-
|
|
18
|
+
- Ordered target commands and configurable artifact materialization under `artifacts`
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
@@ -38,7 +38,7 @@ export default defineMatrixConfig({
|
|
|
38
38
|
root: './apps/web',
|
|
39
39
|
targets: {
|
|
40
40
|
dev: 'vite',
|
|
41
|
-
build: { command: 'vite build', archive:
|
|
41
|
+
build: { command: 'vite build', artifacts: { mode: 'archive', format: 'zip' } },
|
|
42
42
|
preview: 'vite preview',
|
|
43
43
|
},
|
|
44
44
|
},
|
|
@@ -121,12 +121,37 @@ export default defineMatrixConfig({
|
|
|
121
121
|
|
|
122
122
|
`defineMatrixEnv()` is syntax sugar for the c12-compatible `$env.<environment>.env` shape. The raw shape remains supported.
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Ordinary application variables are merged from low to high precedence:
|
|
125
125
|
|
|
126
126
|
```text
|
|
127
|
-
global env/$env < product env/$env < .env layers < process.env
|
|
127
|
+
global env/$env < product env/$env < .env layers < process.env
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
Product identity overrides are resolved from the merged environment before suffixes are applied:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
product identity < variant identity < merged identity override < environment suffix
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`MATRIX_PRODUCT_NAME`, `MATRIX_PRODUCT_SLUG`, and `MATRIX_PRODUCT_APP_ID` may provide identity overrides through the environment. The final values, including suffixes, are written back to both task metadata and the corresponding `MATRIX_PRODUCT_*` variables. `MATRIX_PRODUCT_ID`, `MATRIX_PRODUCT_KEY`, execution-context variables, and `NODE_ENV` are generated by Matrix and cannot be overridden by the environment.
|
|
137
|
+
|
|
138
|
+
Matrix injects the following execution-context variables into every child process:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
MATRIX_ENV_NAME
|
|
142
|
+
MATRIX_TARGET
|
|
143
|
+
MATRIX_PRODUCT_KEY
|
|
144
|
+
MATRIX_PRODUCT_ID
|
|
145
|
+
MATRIX_PRODUCT_NAME
|
|
146
|
+
MATRIX_PRODUCT_SLUG
|
|
147
|
+
MATRIX_PRODUCT_APP_ID
|
|
148
|
+
MATRIX_VARIANT
|
|
149
|
+
MATRIX_PROJECT
|
|
150
|
+
NODE_ENV
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`MATRIX_ENV_NAME` is the selected Matrix configuration environment and may be a custom name such as `staging` or `qa`. `NODE_ENV` describes the target process mode: `dev` uses `development`, while `build` and `preview` use `production`. Therefore a staging build normally receives `MATRIX_ENV_NAME=staging` and `NODE_ENV=production`. `MATRIX_PRODUCT_APP_ID` is emitted only when the resolved product identity has an `appId`; environment suffixes are applied before it is exported.
|
|
154
|
+
|
|
130
155
|
Product-level environment values are resolved independently for each product. This lets two products reuse the same Desktop project while connecting it to different Web variants or services.
|
|
131
156
|
|
|
132
157
|
Custom environment names are supported. Define them with the same helper and pass the name explicitly to the CLI:
|
|
@@ -152,6 +177,50 @@ Custom environments are available through `--env`. When running interactively, M
|
|
|
152
177
|
|
|
153
178
|
Dotenv files are loaded as `.env`, `.env.local`, `.env.<environment>`, and `.env.<environment>.local`. Matrix passes variables such as `VITE_*` and `NUXT_*` to child processes; application frameworks keep ownership of their own runtime configuration.
|
|
154
179
|
|
|
180
|
+
### Build tool integration
|
|
181
|
+
|
|
182
|
+
Matrix provides one Unplugin factory and host-specific entrypoints.
|
|
183
|
+
|
|
184
|
+
import matrix from '@xova/matrix/vite'
|
|
185
|
+
|
|
186
|
+
export default defineConfig({
|
|
187
|
+
plugins: [matrix()],
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
The Vite adapter preserves the resolved envPrefix and adds the reserved MATRIX_ prefix. It reads the final Vite config.env and exposes the structured build context through virtual:matrix/runtime:
|
|
191
|
+
|
|
192
|
+
import { matrix } from 'virtual:matrix/runtime'
|
|
193
|
+
|
|
194
|
+
matrix.environment
|
|
195
|
+
matrix.product.name
|
|
196
|
+
matrix.product.appId
|
|
197
|
+
matrix.config.apiBase
|
|
198
|
+
|
|
199
|
+
The same factory is available from @xova/matrix/rollup, @xova/matrix/webpack, and @xova/matrix/esbuild. The virtual module is a build-time snapshot, not a deployment-time runtime configuration system. Only variables already exposed by the host prefixes are mapped into matrix.config.
|
|
200
|
+
|
|
201
|
+
For multiple Electron configs, assign a scope to each build so main, preload, and renderer do not overwrite one another:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
export default defineConfig({
|
|
205
|
+
main: {
|
|
206
|
+
plugins: [matrix({ scope: 'main' })],
|
|
207
|
+
},
|
|
208
|
+
preload: {
|
|
209
|
+
plugins: [matrix({ scope: 'preload' })],
|
|
210
|
+
},
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Import `virtual:matrix/runtime/main` and `virtual:matrix/runtime/preload` respectively. Their declarations are generated as `.matrix/types/matrix-runtime-main.d.ts` and `.matrix/types/matrix-runtime-preload.d.ts`.
|
|
215
|
+
|
|
216
|
+
Run `matrix prepare` to generate `.matrix/types/matrix-runtime.d.ts` in the project. It derives `ImportMetaEnv` and `matrix.config` key types from `VITE_*` (and other configured public prefixes) without writing environment values. Build plugins also generate the matching declaration after resolving the final `envPrefix` by default; set `types: false` to disable it. Add `.matrix/types` to the `include` list in `tsconfig.json` to enable the declarations:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"include": ["src", ".matrix/types"]
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
155
224
|
## Targets and defaults
|
|
156
225
|
|
|
157
226
|
The built-in targets use these defaults:
|
|
@@ -162,7 +231,7 @@ The built-in targets use these defaults:
|
|
|
162
231
|
| `build` | `production` | No |
|
|
163
232
|
| `preview` | `production` | Yes |
|
|
164
233
|
|
|
165
|
-
Custom targets are non-continuous by default and use `development` unless `--env` is provided. Project roots default to `.`, target output directories default to `dist`, and
|
|
234
|
+
Custom targets are non-continuous by default and use `development` unless `--env` is provided. The built-in target runtime modes are `development` for `dev` and `production` for `build` and `preview`. Custom targets may set `nodeEnv` to `development`, `production`, or `test`. Project roots default to `.`, target output directories default to `dist`, and artifact output defaults to `artifacts`. Targets may use a string array for ordered commands, such as `release: ['pnpm build', 'pnpm package']`. Artifact delivery is configured per target with `artifacts.mode`: `move`, `archive`, or `both`; the source output is removed after successful delivery by default. Artifact names use `<variant>-<version>-<YYYYMMDD-HHmmss>`, with five ArtifactSets retained by default per product, environment, and variant.
|
|
166
235
|
|
|
167
236
|
Interactive Variant selection comes before Target selection. Target options are derived from the common targets available to the selected Variants; use `--variant` to provide the scope in non-interactive runs.
|
|
168
237
|
|
|
@@ -174,10 +243,11 @@ Any configured target can be invoked from the CLI. `test`, `lint`, and `e2e` are
|
|
|
174
243
|
matrix [target] [product] [--variant name] [--env <environment>]
|
|
175
244
|
matrix --product <product> [--target <target>] [--variant name] [--env <environment>]
|
|
176
245
|
matrix dev [product]
|
|
177
|
-
matrix build [product] [--env <environment>]
|
|
246
|
+
matrix build [product] [--env <environment>]
|
|
178
247
|
matrix preview [product] [--env <environment>]
|
|
179
248
|
matrix plan [product] [--target <target>] [--env <environment>]
|
|
180
249
|
matrix doctor
|
|
250
|
+
matrix prepare [product] [--env <environment>]
|
|
181
251
|
matrix <custom-target> [product] [--env <environment>]
|
|
182
252
|
```
|
|
183
253
|
|
package/README.zh-CN.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
- 支持 `qa`、`uat` 等自定义环境名称
|
|
16
16
|
- 支持 dotenv 和 Shell 覆盖的分层环境变量
|
|
17
17
|
- 支持交互式选择产品和环境
|
|
18
|
-
-
|
|
18
|
+
- 支持顺序执行多个 Target 命令,并按配置移动或压缩产物
|
|
19
19
|
|
|
20
20
|
## 安装
|
|
21
21
|
|
|
@@ -38,7 +38,7 @@ export default defineMatrixConfig({
|
|
|
38
38
|
root: './apps/web',
|
|
39
39
|
targets: {
|
|
40
40
|
dev: 'vite',
|
|
41
|
-
build: { command: 'vite build', archive:
|
|
41
|
+
build: { command: 'vite build', artifacts: { mode: 'archive', format: 'zip' } },
|
|
42
42
|
preview: 'vite preview',
|
|
43
43
|
},
|
|
44
44
|
},
|
|
@@ -121,12 +121,37 @@ export default defineMatrixConfig({
|
|
|
121
121
|
|
|
122
122
|
`defineMatrixEnv()` 是 c12 兼容的 `$env.<environment>.env` 写法的语法糖,底层结构仍然保持不变,也继续支持直接使用原始写法。
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
普通应用变量的覆盖优先级从低到高为:
|
|
125
125
|
|
|
126
126
|
```text
|
|
127
|
-
global env/$env < product env/$env < .env layers < process.env
|
|
127
|
+
global env/$env < product env/$env < .env layers < process.env
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
产品 identity override 会先从合并后的环境变量中解析,然后再应用 suffix:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
product identity < variant identity < 合并后的 identity override < environment suffix
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`MATRIX_PRODUCT_NAME`、`MATRIX_PRODUCT_SLUG` 和 `MATRIX_PRODUCT_APP_ID` 可以通过环境变量提供 identity override。包含 suffix 的最终值会同时写入任务元数据和对应的 `MATRIX_PRODUCT_*` 变量。`MATRIX_PRODUCT_ID`、`MATRIX_PRODUCT_KEY`、执行上下文变量和 `NODE_ENV` 由 Matrix 生成,不能被环境变量覆盖。
|
|
137
|
+
|
|
138
|
+
Matrix 会向每个子进程注入以下执行上下文变量:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
MATRIX_ENV_NAME
|
|
142
|
+
MATRIX_TARGET
|
|
143
|
+
MATRIX_PRODUCT_KEY
|
|
144
|
+
MATRIX_PRODUCT_ID
|
|
145
|
+
MATRIX_PRODUCT_NAME
|
|
146
|
+
MATRIX_PRODUCT_SLUG
|
|
147
|
+
MATRIX_PRODUCT_APP_ID
|
|
148
|
+
MATRIX_VARIANT
|
|
149
|
+
MATRIX_PROJECT
|
|
150
|
+
NODE_ENV
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`MATRIX_ENV_NAME` 是当前选择的 Matrix 配置环境,可以是 `staging`、`qa` 等自定义名称。`NODE_ENV` 表示目标进程的运行模式:`dev` 使用 `development`,`build` 和 `preview` 使用 `production`。因此 staging 构建通常会同时得到 `MATRIX_ENV_NAME=staging` 和 `NODE_ENV=production`。只有最终解析出的产品 identity 配置了 `appId` 时,才会注入 `MATRIX_PRODUCT_APP_ID`;环境 suffix 会在导出前生效。
|
|
154
|
+
|
|
130
155
|
产品级环境变量会为每个产品独立解析。这样多个产品可以复用同一个 Desktop 项目,同时连接不同的 Web 变体或服务。
|
|
131
156
|
|
|
132
157
|
支持自定义环境名称。使用相同的 helper 定义,并在 CLI 中显式传入环境名:
|
|
@@ -152,6 +177,50 @@ matrix plan app --target preview --env qa
|
|
|
152
177
|
|
|
153
178
|
dotenv 文件按 `.env`、`.env.local`、`.env.<environment>` 和 `.env.<environment>.local` 加载。Matrix 会将 `VITE_*`、`NUXT_*` 等变量传递给子进程,应用框架继续负责自己的运行时配置。
|
|
154
179
|
|
|
180
|
+
### 构建工具接入
|
|
181
|
+
|
|
182
|
+
Matrix 提供统一的 Unplugin 工厂,以及各构建工具的入口。
|
|
183
|
+
|
|
184
|
+
import matrix from '@xova/matrix/vite'
|
|
185
|
+
|
|
186
|
+
export default defineConfig({
|
|
187
|
+
plugins: [matrix()],
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
Vite 适配器会保留最终解析出的 envPrefix,并自动加入 Matrix 保留的 MATRIX_ 前缀。它读取 Vite 最终的 config.env,通过 virtual:matrix/runtime 提供结构化构建上下文:
|
|
191
|
+
|
|
192
|
+
import { matrix } from 'virtual:matrix/runtime'
|
|
193
|
+
|
|
194
|
+
matrix.environment
|
|
195
|
+
matrix.product.name
|
|
196
|
+
matrix.product.appId
|
|
197
|
+
matrix.config.apiBase
|
|
198
|
+
|
|
199
|
+
同一套工厂也可以通过 @xova/matrix/rollup、@xova/matrix/webpack 和 @xova/matrix/esbuild 使用。虚拟模块是构建时快照,不是部署后可变的 runtime config;只有宿主构建工具已通过前缀暴露的变量,才会进入 matrix.config。
|
|
200
|
+
|
|
201
|
+
Electron 多配置时为每个构建指定 scope,避免 main、preload、renderer 互相覆盖:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
export default defineConfig({
|
|
205
|
+
main: {
|
|
206
|
+
plugins: [matrix({ scope: 'main' })],
|
|
207
|
+
},
|
|
208
|
+
preload: {
|
|
209
|
+
plugins: [matrix({ scope: 'preload' })],
|
|
210
|
+
},
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
分别使用 `virtual:matrix/runtime/main` 和 `virtual:matrix/runtime/preload`。对应类型文件会生成到 `.matrix/types/matrix-runtime-main.d.ts` 和 `.matrix/types/matrix-runtime-preload.d.ts`。
|
|
215
|
+
|
|
216
|
+
运行一次 `matrix prepare` 可生成项目级声明文件 `.matrix/types/matrix-runtime.d.ts`。它会根据 `VITE_*`(以及配置的其他公开前缀)生成 `ImportMetaEnv` 和 `matrix.config` 的键类型,不会写入环境变量的实际值。构建插件默认也会在解析最终 `envPrefix` 后生成对应类型;可通过 `types: false` 关闭。将 `.matrix/types` 加入 `tsconfig.json` 的 `include` 即可获得类型提示:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"include": ["src", ".matrix/types"]
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
155
224
|
## 目标和默认值
|
|
156
225
|
|
|
157
226
|
内置目标的默认值如下:
|
|
@@ -162,7 +231,7 @@ dotenv 文件按 `.env`、`.env.local`、`.env.<environment>` 和 `.env.<environ
|
|
|
162
231
|
| `build` | `production` | 否 |
|
|
163
232
|
| `preview` | `production` | 是 |
|
|
164
233
|
|
|
165
|
-
自定义目标默认不会持续运行,未指定 `--env` 时使用 `development`。项目默认使用当前目录,目标输出目录默认为 `dist
|
|
234
|
+
自定义目标默认不会持续运行,未指定 `--env` 时使用 `development`。内置目标的运行模式为:`dev` 使用 `development`,`build` 和 `preview` 使用 `production`。自定义目标也可以将 `nodeEnv` 配置为 `development`、`production` 或 `test`。项目默认使用当前目录,目标输出目录默认为 `dist`,产物根目录默认为 `artifacts`。Target 可以使用字符串数组顺序执行多个命令,例如 `release: ['pnpm build', 'pnpm package']`。产物支持 `move`、`archive` 和 `both` 三种模式,成功处理后默认删除原始输出目录。产物命名为 `<variant>-<version>-<YYYYMMDD-HHmmss>`,默认按 Product、Environment、Variant 保留最近 5 个 ArtifactSet。
|
|
166
235
|
|
|
167
236
|
交互式运行会先选择 Variant,再选择 Target。Target 选项来自已选 Variant 共同支持的目标;非交互式运行可以使用 `--variant` 提前指定执行范围。
|
|
168
237
|
|
|
@@ -174,10 +243,11 @@ dotenv 文件按 `.env`、`.env.local`、`.env.<environment>` 和 `.env.<environ
|
|
|
174
243
|
matrix [target] [product] [--variant name] [--env <environment>]
|
|
175
244
|
matrix --product <product> [--target <target>] [--variant name] [--env <environment>]
|
|
176
245
|
matrix dev [product]
|
|
177
|
-
matrix build [product] [--env <environment>]
|
|
246
|
+
matrix build [product] [--env <environment>]
|
|
178
247
|
matrix preview [product] [--env <environment>]
|
|
179
248
|
matrix plan [product] [--target <target>] [--env <environment>]
|
|
180
249
|
matrix doctor
|
|
250
|
+
matrix prepare [product] [--env <environment>]
|
|
181
251
|
matrix <custom-target> [product] [--env <environment>]
|
|
182
252
|
```
|
|
183
253
|
|
package/dist/archive.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:path";import{randomUUID as t}from"node:crypto";import{
|
|
1
|
+
import e from"node:path";import{randomUUID as t}from"node:crypto";import{mkdir as n,rename as r,stat as i,unlink as a}from"node:fs/promises";import{createWriteStream as o}from"node:fs";import{pipeline as s}from"node:stream/promises";import c from"archiver";async function l(l,u,d){let f;try{f=await i(l)}catch(e){let t=e.code;throw t===`ENOENT`||t===`ENOTDIR`?Error(`Archive source directory does not exist: ${l}`,{cause:e}):e}if(!f.isDirectory())throw Error(`Archive source must be a directory: ${l}`);let p=e.relative(e.resolve(l),e.resolve(u));if(!p||!p.startsWith(`..`)&&!e.isAbsolute(p))throw Error(`Archive destination must be outside source directory: ${u}`);let m=e.dirname(u),h=e.join(m,`.${e.basename(u)}.${t()}.tmp`);await n(m,{recursive:!0});let g;try{let e=o(h),t=c(d===`zip`?`zip`:`tar`,d===`tar.gz`?{gzip:!0,gzipOptions:{level:9}}:void 0);g=s(t,e),t.directory(l,!1),await t.finalize(),await g,await r(h,u)}finally{await g?.catch(()=>void 0),await a(h).catch(e=>{if(e.code!==`ENOENT`)throw e})}}export{l as archiveDirectory};
|
package/dist/artifact.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{archiveDirectory as e}from"./archive.js";import t from"node:path";import{randomUUID as n}from"node:crypto";import{cp as r,mkdir as i,readFile as a,readdir as o,rename as s,rm as c,stat as l}from"node:fs/promises";function u(e){return e===`zip`?`zip`:`tar.gz`}function d(e){let t=e=>String(e).padStart(2,`0`);return`${String(e.getFullYear())+t(e.getMonth()+1)+t(e.getDate())}-${t(e.getHours())}${t(e.getMinutes())}${t(e.getSeconds())}`}async function f(e){let n=t.join(e,`package.json`),r;try{r=JSON.parse(await a(n,`utf8`))}catch(e){throw Error(`Unable to read package version from ${n}`,{cause:e})}if(!r||typeof r!=`object`||typeof r.version!=`string`||!r.version.trim())throw Error(`Package version is required for artifact output: ${n}`);return r.version.trim()}async function p(e,t){let i=`${t}.${n()}.tmp`;try{await r(e,i,{recursive:!0,errorOnExist:!0}),await s(i,t)}finally{await c(i,{recursive:!0,force:!0})}}async function m(e){if(!(await l(e).catch(t=>{throw Error(`Artifact source directory does not exist: ${e}`,{cause:t})})).isDirectory())throw Error(`Artifact source must be a directory: ${e}`)}async function h(e){try{throw await l(e),Error(`Artifact destination already exists: ${e}`)}catch(e){if(e.code!==`ENOENT`)throw e}}function g(e){return e.match(/(\d{8}-\d{6})(?:\.(?:zip|tar\.gz))?$/)?.[1]}function _(e){return/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9a-z-]+(?:\.[0-9a-z-]+)*)?(?:\+[0-9a-z-]+(?:\.[0-9a-z-]+)*)?$/i.test(e)}function v(e,t){let n=e.replace(/\.(?:zip|tar\.gz)$/,``),r=g(e);if(!r)return!1;let i=n.slice(0,-(r.length+1));return i.startsWith(`${t}-`)?_(i.slice(t.length+1)):!1}async function y(e,n,r){let i=(await o(e,{withFileTypes:!0})).filter(e=>v(e.name,n)&&(e.isDirectory()||e.name.endsWith(`.zip`)||e.name.endsWith(`.tar.gz`))).map(async n=>({name:n.name,timestamp:g(n.name)??``,modifiedAt:(await l(t.join(e,n.name))).mtimeMs})),a=(await Promise.all(i)).sort((e,t)=>t.timestamp.localeCompare(e.timestamp)||t.modifiedAt-e.modifiedAt);for(let n of a.slice(Math.max(r,0)))await c(t.join(e,n.name),{recursive:!0,force:!0})}async function b(r){await m(r.sourceDir);let a=await f(r.projectRoot),o=r.now??/* @__PURE__ */ new Date,l=`${r.variant}-${a}-${d(o)}`,g=t.join(r.artifactsRoot,r.product,r.environment),_=t.join(g,`${l}.${u(r.format)}`),v=t.join(g,l);if(await i(g,{recursive:!0}),r.mode===`archive`)await h(_),await e(r.sourceDir,_,r.format),r.removeSource&&await c(r.sourceDir,{recursive:!0,force:!1});else if(r.mode===`move`)await h(v),r.removeSource?await s(r.sourceDir,v):await p(r.sourceDir,v);else{await h(v);let i=t.join(g,`.${l}.${n()}.${u(r.format)}`);try{await e(r.sourceDir,i,r.format),r.removeSource?await s(r.sourceDir,v):await p(r.sourceDir,v),await s(i,t.join(v,`${l}.${u(r.format)}`))}finally{await c(i,{force:!0})}}return await y(g,r.variant,r.retention),r.mode===`archive`?_:v}export{b as materializeArtifact};
|
package/dist/cli-args.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=`matrix [target] [product] [--product name] [--variant name] [--env name] [--target name] [
|
|
1
|
+
const e=`matrix [target|prepare] [product] [--product name] [--variant name] [--env name] [--target name] [-h|--help]`;function t(e,t,n){let r=e[t+1];if(!r||r.startsWith(`-`))throw Error(`Option ${n} requires a value`);return r}function n(e,t){let n=e.split(`,`).map(e=>e.trim());if(n.some(e=>!e))throw Error(`Option ${t} contains an empty variant name`);return n}function r(e){let r={variants:[]},i=[];for(let a=0;a<e.length;a++){let o=e[a];if(!o)throw Error(`Unexpected empty argument`);if(o===`--help`||o===`-h`){r.help=!0;continue}if(o===`--variant`||o===`-v`){let i=t(e,a,o);r.variants.push(...n(i,o)),a++;continue}if(o===`--product`||o===`--env`||o===`--mode`||o===`--target`){let n=t(e,a,o);if(o===`--product`){if(r.product!==void 0)throw Error(`Duplicate option: --product`);r.product=n}else if(o===`--target`){if(r.target!==void 0)throw Error(`Duplicate option: --target`);r.target=n}else{if(r.env!==void 0)throw Error(`Duplicate option: --env`);r.env=n}a++;continue}if(o.startsWith(`-`))throw Error(`Unknown option: ${o}`);if(i.push(o),i.length>2)throw Error(`Unexpected argument: ${o}`)}if(i[0]&&(r.command=i[0]),i[1]){if(r.product!==void 0)throw Error(`Product was provided more than once`);r.product=i[1]}return r}function i(e){let t=e.product!==void 0||e.target!==void 0||e.env!==void 0||e.variants.length>0;if(e.help||e.command===`help`){if(t||e.command!==void 0&&e.command!==`help`)throw Error(`Help does not accept execution options`);return}if(e.command===`doctor`){if(e.product!==void 0||e.target!==void 0||e.variants.length>0)throw Error(`doctor only accepts --env`);return}if(e.command===`prepare`&&e.target!==void 0)throw Error(`${e.command} does not accept --target`);if(e.command&&e.command!==`plan`&&e.target!==void 0)throw Error(`Target is already selected by command ${e.command}; use --target only with plan or --product`)}export{e as CLI_HELP,r as parseArgs,i as validateCliArgs};
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{MATRIX_DEFAULTS as e,defaultEnvironmentForTarget as t}from"./defaults.js";import{listMatrixEnvironments as n,loadMatrixConfig as r}from"./config.js";import{createExecutionPlan as i,validateExecutionGraph as a}from"./plan.js";import{CLI_HELP as o,parseArgs as s,validateCliArgs as c}from"./cli-args.js";import{runExecutionPlan as l}from"./exec.js";import u from"node:process";import{isCancel as
|
|
2
|
+
import{MATRIX_DEFAULTS as e,defaultEnvironmentForTarget as t}from"./defaults.js";import{listMatrixEnvironments as n,loadMatrixConfig as r}from"./config.js";import{createExecutionPlan as i,validateExecutionGraph as a}from"./plan.js";import{CLI_HELP as o,parseArgs as s,validateCliArgs as c}from"./cli-args.js";import{runExecutionPlan as l}from"./exec.js";import{generateMatrixTypes as u,matrixTypeEnvKeys as d}from"./typegen.js";import f from"node:process";import{isCancel as p,multiselect as m,outro as h,select as g}from"@clack/prompts";import _ from"consola";const v=/token|secret|password|passwd|authorization|cookie|api[_-]?key|private[_-]?key/i;function y(e,t){return{...e,tasks:e.tasks.map(e=>({...e,env:Object.fromEntries(Object.entries(e.env).filter(([e])=>t.has(e)||e.startsWith(`MATRIX_`)).map(([e,t])=>[e,v.test(e)?`***`:t]))}))}}function b(e,t=[]){let n=(t.length?t.map(t=>e.variants[t]).filter(e=>e!==void 0):Object.values(e.variants)).map(e=>new Set(Object.keys(e.targets)));return[...n[0]??/* @__PURE__ */ new Set].filter(e=>n.every(t=>t.has(e))).sort()}function x(e,t){for(let n of t)if(!e.variants[n])throw Error(`Unknown variant for product ${e.key}: ${n}`)}function S(e,t,n=[]){let r=b(t,n),i=r.length?r.join(`, `):`none`;if(!r.includes(e))throw Error(`Unknown command or target for product ${t.key}: ${e}. Available targets: ${i}`)}async function C(e,t){if(!e.product){if(!f.stdin.isTTY||!f.stdout.isTTY)throw Error(`Product is required in non-interactive mode. Try: matrix <target> <product> or matrix --product <product>`);let n=await g({message:`Select product`,options:Object.keys(t).map(e=>({value:e,label:e}))});if(p(n))return null;e.product=n}if(e.product.includes(`,`))throw Error(`Only one product can be selected per run`);if(!t[e.product])throw Error(`Unknown product: ${e.product}`);return e}async function w(t,n){let r=t.target??(t.command&&t.command!==`plan`?t.command:void 0);if(r)return t.target=r,t;let i=b(n,t.variants);if(!i.length)throw Error(`Product ${n.key} has no common targets`);if(!f.stdin.isTTY||!f.stdout.isTTY)return t.target=i.includes(e.target)?e.target:i[0],t;let a=await g({message:`Select target`,initialValue:i.includes(e.target)?e.target:i[0],options:i.map(t=>({value:t,label:t,...t===e.target?{hint:`default`}:{}}))});return p(a)?null:(t.target=a,t)}async function T(e,t){let n=!e.command&&f.stdin.isTTY&&f.stdout.isTTY;if(!e.variants.length&&n&&Object.keys(t.variants).length>1){let n=Object.entries(t.variants),r=await m({message:`Select variants (leave empty to select all)`,options:n.map(([e])=>({value:e,label:e}))});if(p(r))return null;e.variants=r}return e}async function E(e,n,r){if(e.env)return e;let i=t(n);if(f.stdin.isTTY&&f.stdout.isTTY){let t=await g({message:`Select environment`,initialValue:i,options:r.map(e=>({value:e,label:e,...e===i?{hint:`default`}:{}}))});if(p(t))return null;e.env=t}else e.env=i;return e}async function D(p=f.argv.slice(2)){let m=s(p);if(c(m),m.command===`help`||m.help){console.log(o);return}if(m.command===`doctor`){let e=await r({...m.env?{envName:m.env}:{}});a({config:e.config,projects:e.projects,products:e.products,externalEnv:e.externalEnv,cwd:e.cwd,envName:e.envName}),_.success(`Configuration is valid: ${e.configFile??`matrix.config.ts`}`);return}if(m.command===`prepare`){let e=await r({...m.env?{envName:m.env}:{}}),t=m.product?e.products[m.product]:void 0;if(m.product&&!t)throw Error(`Unknown product: ${m.product}`);let n=[e.config.env,e.externalEnv];for(let r of t?[t]:Object.values(e.products))n.push(r.env);let i=await u({cwd:e.cwd,env:d(...n)});_.success(`Types generated: ${i}`);return}let g=m.target??(m.command&&m.command!==`plan`?m.command:e.target),v=m.env??t(g),b=await r({envName:v}),D=await C(m,b.products);if(!D)return h(`Cancelled`);let O=b.products[D.product];if(!O)throw Error(`Unknown product: ${D.product}`);x(O,D.variants);let k=await T(D,O);if(!k)return h(`Cancelled`);x(O,k.variants);let A=await w(k,O);if(!A)return h(`Cancelled`);let j=A.target;S(j,O,A.variants);let M=await E(A,j,!A.env&&f.stdin.isTTY&&f.stdout.isTTY?await n({productName:A.product}):[]);if(!M)return h(`Cancelled`);let N=M.env===v?b:await r({envName:M.env}),P=N.products[M.product];if(!P)throw Error(`Unknown product: ${M.product}`);x(P,M.variants),S(j,P,M.variants);let F=M.command??j,I=[M.product],L={config:N.config,projects:N.projects,products:N.products,externalEnv:N.externalEnv,cwd:N.cwd,productNames:I,target:j,envName:N.envName},R=M.variants.length?i({...L,variantNames:M.variants}):i(L);if(F===`plan`){let e=new Set(Object.keys(N.config.env??{}));for(let t of I)for(let n of Object.keys(N.config.products[t]?.env??{}))e.add(n);console.log(JSON.stringify(y(R,e),null,2));return}_.info(`Plan: ${I[0]} / ${M.variants.length?M.variants.join(`, `):`all variants`} / ${j} / ${N.envName}`);let z=M.variants.length?M.variants:Object.keys(P.variants),B=new Set(z.map(e=>`${I[0]}:${e}:${j}`)),V=R.tasks.filter(e=>!B.has(e.id));V.length&&_.info(`Including dependencies: ${V.map(e=>e.id).join(`, `)}`),await l(R)}export{D as runCli};
|
package/dist/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MATRIX_DEFAULTS as e,defaultEnvironmentForTarget as t}from"./defaults.js";import{assertMatrixConfig as n}from"./schema.js";import{MATRIX_ENVIRONMENTS as r}from"./types.js";import i from"node:path";import a from"node:process";import{loadConfig as o}from"c12";function s(e){return e}function c(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{env:t}]))}async function l(e={}){let t=i.resolve(e.cwd??a.cwd()),n=(await o({name:`matrix`,cwd:t,...e.configFile?{configFile:e.configFile}:{},envName:!1,dotenv:!1,omit$Keys:!1,rcFile:!1,packageJson:!1})).config,s=new Set(r);for(let e of Object.keys(n.$env??{}))s.add(e);let c=e.productName?n.products?.[e.productName]:void 0,l=e.productName?c?[c]:[]:Object.values(n.products??{});for(let e of l)for(let t of Object.keys(e.$env??{}))s.add(t);return[...s]}function u(t,n){let r=typeof n==`string
|
|
1
|
+
import{MATRIX_DEFAULTS as e,defaultEnvironmentForTarget as t}from"./defaults.js";import{assertMatrixConfig as n}from"./schema.js";import{MATRIX_ENVIRONMENTS as r}from"./types.js";import i from"node:path";import a from"node:process";import{loadConfig as o}from"c12";function s(e){return e}function c(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{env:t}]))}async function l(e={}){let t=i.resolve(e.cwd??a.cwd()),n=(await o({name:`matrix`,cwd:t,...e.configFile?{configFile:e.configFile}:{},envName:!1,dotenv:!1,omit$Keys:!1,rcFile:!1,packageJson:!1})).config,s=new Set(r);for(let e of Object.keys(n.$env??{}))s.add(e);let c=e.productName?n.products?.[e.productName]:void 0,l=e.productName?c?[c]:[]:Object.values(n.products??{});for(let e of l)for(let t of Object.keys(e.$env??{}))s.add(t);return[...s]}function u(t,n){let r=typeof n==`string`||Array.isArray(n)?{command:n}:{...n};if(!r.command)throw Error(`Target ${t} must define a command`);if(Array.isArray(r.command)&&(!r.command.length||r.command.some(e=>!e.trim())))throw Error(`Target commands must contain non-empty commands`);let i={mode:r.artifacts?.mode??e.artifacts.mode,format:r.artifacts?.format??e.artifacts.format,removeSource:r.artifacts?.removeSource??e.artifacts.removeSource},a=e.targets[t],o=r.continuous??a?.continuous??!1;if(o&&Array.isArray(r.command))throw Error(`Continuous targets cannot use multiple commands`);return{...r,name:t,continuous:o,nodeEnv:r.nodeEnv??a?.nodeEnv??`development`,outputDir:r.outputDir??e.outputDir,artifacts:i,dependsOn:(r.dependsOn??[]).map(e=>typeof e==`string`?{variant:e}:e)}}function d(e,t){if(typeof t==`string`||Array.isArray(t))return u(e.name,t);let n=t.readyWhen===void 0?e.readyWhen:{...e.readyWhen,...t.readyWhen},r=t.artifacts===void 0?e.artifacts:{...e.artifacts,...t.artifacts};return u(e.name,{...e,...t,artifacts:r,dependsOn:(t.dependsOn??e.dependsOn).map(e=>typeof e==`string`?{variant:e}:e),...n?{readyWhen:n}:{}})}function f(...e){return Object.assign({},...e.filter(Boolean))}function p(e,t){let n=Object.fromEntries(Object.entries(e.products).map(([e,n])=>{let{$env:r,...i}=n,a=f(n.env,r?.[t]?.env);return[e,{...i,...Object.keys(a).length?{env:a}:{}}]}));return{...e,products:n}}function m(e){let t=Object.fromEntries(Object.entries(e.projects).map(([e,t])=>[e,{...t,id:e,targets:Object.fromEntries(Object.entries(t.targets).map(([e,t])=>[e,u(e,t)]))}]));return{config:e,projects:t,products:Object.fromEntries(Object.entries(e.products).map(([e,n])=>{let r=Object.fromEntries(Object.entries(n.variants).map(([n,r])=>{let i=typeof r==`string`?{project:r}:r,a=t[i.project];if(!a)throw Error(`Product ${e} variant ${n} references unknown project ${i.project}`);let o=Object.fromEntries(Object.entries(a.targets).map(([e,t])=>{let n=i.targets?.[e];return[e,n===void 0?t:d(t,n)]}));for(let[t,r]of Object.entries(i.targets??{}))if(!(t in o)){if(typeof r==`string`||Array.isArray(r))o[t]=u(t,r);else if(r.command)o[t]=u(t,r);else throw Error(`Variant ${e}/${n} target ${t} must define a command`)}return[n,{...i,id:n,targets:o}]}));return[e,{...n,id:n.id??e,name:n.name??e,slug:n.slug??e,key:e,variants:r}]}))}}async function h(t={}){let r=i.resolve(t.cwd??a.cwd()),s=t.envName??e.environment,c={name:`matrix`,cwd:r,...t.configFile?{configFile:t.configFile}:{},envName:s,dotenv:{fileName:[`.env`,`.env.local`,`.env.${s}`,`.env.${s}.local`]},omit$Keys:!0,rcFile:!1,packageJson:!1},l=await o(c),u=p(n(l.config),s),d=Object.fromEntries(Object.entries(a.env).filter(e=>e[1]!==void 0));return{...m(u),configFile:l.configFile,layers:l.layers,cwd:r,envName:s,externalEnv:d}}export{e as MATRIX_DEFAULTS,t as defaultEnvironmentForTarget,s as defineMatrixConfig,c as defineMatrixEnv,l as listMatrixEnvironments,h as loadMatrixConfig,m as normalizeMatrixConfig};
|
package/dist/defaults.d.ts
CHANGED
|
@@ -6,21 +6,26 @@ export declare const MATRIX_DEFAULTS: {
|
|
|
6
6
|
readonly projectRoot: ".";
|
|
7
7
|
readonly outputDir: "dist";
|
|
8
8
|
readonly artifactsRoot: "artifacts";
|
|
9
|
-
readonly
|
|
10
|
-
readonly
|
|
9
|
+
readonly artifacts: {
|
|
10
|
+
readonly mode: "none";
|
|
11
11
|
readonly format: "zip";
|
|
12
|
+
readonly removeSource: true;
|
|
13
|
+
readonly retention: 5;
|
|
12
14
|
};
|
|
13
15
|
readonly targets: {
|
|
14
16
|
readonly dev: {
|
|
15
17
|
readonly environment: "development";
|
|
18
|
+
readonly nodeEnv: "development";
|
|
16
19
|
readonly continuous: true;
|
|
17
20
|
};
|
|
18
21
|
readonly build: {
|
|
19
22
|
readonly environment: "production";
|
|
23
|
+
readonly nodeEnv: "production";
|
|
20
24
|
readonly continuous: false;
|
|
21
25
|
};
|
|
22
26
|
readonly preview: {
|
|
23
27
|
readonly environment: "production";
|
|
28
|
+
readonly nodeEnv: "production";
|
|
24
29
|
readonly continuous: true;
|
|
25
30
|
};
|
|
26
31
|
};
|
package/dist/defaults.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={target:`dev`,environment:`development`,projectRoot:`.`,outputDir:`dist`,artifactsRoot:`artifacts`,
|
|
1
|
+
const e={target:`dev`,environment:`development`,projectRoot:`.`,outputDir:`dist`,artifactsRoot:`artifacts`,artifacts:{mode:`none`,format:`zip`,removeSource:!0,retention:5},targets:{dev:{environment:`development`,nodeEnv:`development`,continuous:!0},build:{environment:`production`,nodeEnv:`production`,continuous:!1},preview:{environment:`production`,nodeEnv:`production`,continuous:!0}}};function t(t){return e.targets[t]?.environment??e.environment}export{e as MATRIX_DEFAULTS,t as defaultEnvironmentForTarget};
|
package/dist/env.d.ts
ADDED
package/dist/env.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{camelCase as e}from"scule";const t=/* @__PURE__ */ new Set([`MATRIX_ENV_NAME`,`MATRIX_TARGET`,`MATRIX_PRODUCT_KEY`,`MATRIX_PRODUCT_ID`,`MATRIX_PRODUCT_NAME`,`MATRIX_PRODUCT_SLUG`,`MATRIX_PRODUCT_APP_ID`,`MATRIX_VARIANT`,`MATRIX_PROJECT`,`NODE_ENV`]);function n(e){return e===void 0?[`VITE_`]:Array.isArray(e)?e:[e]}function r(e){return[.../* @__PURE__ */ new Set([...n(e),`MATRIX_`])]}function i(e,r=[`VITE_`,`MATRIX_`]){let i=n(r);return Object.keys(e).filter(e=>e.startsWith(`MATRIX_`)||t.has(e)?!1:i.some(t=>e.startsWith(t))).sort()}function a(t,n){let r=n.find(e=>t.startsWith(e));return r?e(t.slice(r.length).toLowerCase()):``}function o(e,t=[`VITE_`,`MATRIX_`]){let r=n(t),o={};for(let t of i(e,r)){let n=a(t,r);n&&(o[n]=e[t])}return o}export{o as createPublicConfig,r as ensureMatrixEnvPrefix,n as normalizeEnvPrefix,a as publicEnvConfigName,i as publicEnvKeys};
|
package/dist/esbuild.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{MatrixUnplugin as e}from"./unplugin.js";var t=e.esbuild;export{t as default};
|
package/dist/exec.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{materializeArtifact as e}from"./artifact.js";import t from"node:process";import n from"consola";import r from"node:net";import{execaCommand as i}from"execa";const a=new Promise(()=>void 0);function o(e){return new Promise(t=>setTimeout(t,e))}function s(e,t){return t.size?Promise.race([e,...t]):e}function c(e,t,n){return new Promise(i=>{let a=r.createConnection({host:e,port:t}),o=!1,s=e=>{o||(o=!0,a.destroy(),i(e))};a.once(`connect`,()=>s(!0)),a.once(`error`,()=>s(!1)),a.setTimeout(n,()=>s(!1))})}async function l(e,t,n){let r=t.readyWhen;if(!r)return;let i=r.timeout??3e4,a=Date.now()+i;for(;;){let i=a-Date.now();if(i<=0)break;if(await s(c(r.host??`127.0.0.1`,r.port,Math.min(1e3,i)),n))return;if(await s(Promise.race([e.then(e=>e),new Promise(e=>setTimeout(e,Math.min(200,Math.max(1,a-Date.now()))))]),n)!==void 0)throw Error(`${t.id} exited before becoming ready`)}throw Error(`Timed out waiting for ${t.id} on port ${r.port}`)}async function u(e,t,n){for(let[n,r]of e)t.has(n)||(t.add(n),r.kill(`SIGTERM`));await Promise.race([Promise.allSettled([...e.values()]),o(5e3)]);for(let[r,i]of e)n.has(r)||(t.add(r),i.kill(`SIGKILL`));await Promise.allSettled([...e.values()])}async function d(r){let o=/* @__PURE__ */ new Map,c=/* @__PURE__ */ new Set,d=/* @__PURE__ */ new Set,f=/* @__PURE__ */ new Set,p=()=>{for(let[e,t]of o)c.has(e)||(c.add(e),t.kill(`SIGTERM`))};t.on(`SIGINT`,p),t.on(`SIGTERM`,p);try{for(let t of r.tasks){for(let e of t.dependsOn){let t=o.get(e.id);if(!t)throw Error(`Dependency ${e.id} was not started`);if(e.condition===`completed`){let n=await s(t,f);if(n.exitCode!==0)throw Error(`${e.id} exited with code ${n.exitCode}`)}else{let n=r.tasks.find(t=>t.id===e.id);if(!n)throw Error(`Dependency task ${e.id} is missing`);await l(t,n,f)}}let u=Array.isArray(t.command)?t.command:[t.command];for(let[e,r]of u.entries()){n.info(`${t.id} [${e+1}/${u.length}] → ${r}`);let l=i(r,{cwd:t.cwd,env:Object.fromEntries(Object.entries(t.env).map(([e,t])=>[e,String(t)])),extendEnv:!0,stdio:`inherit`,reject:!1,killDescendants:!0});if(o.set(t.id,l),l.then(()=>d.add(t.id),()=>d.add(t.id)),t.continuous){let e=l.then(e=>{if(c.size||e.exitCode===0)return a;throw Error(`${t.id} exited with code ${e.exitCode}`)});f.add(e),e.catch(()=>void 0);break}let p=await s(l,f);if(p.exitCode!==0)throw Error(`${t.id} exited with code ${p.exitCode}`)}if(!t.continuous&&t.artifacts.mode!==`none`){let i=await e({sourceDir:t.outputDir,artifactsRoot:r.artifactsRoot,product:t.product,environment:r.envName,variant:t.variant,projectRoot:t.projectRoot,mode:t.artifacts.mode,format:t.artifacts.format,removeSource:t.artifacts.removeSource,retention:r.artifactRetention});n.success(`Artifact: ${i}`)}}let t=r.tasks.filter(e=>e.continuous).map(e=>o.get(e.id));return t.length&&await s(Promise.race(t.map(async e=>{let t=await e;if(!c.size&&t.exitCode!==0)throw Error(`Service exited with code ${t.exitCode}`)})),f),{children:o}}finally{r.tasks.some(e=>e.continuous)?await u(o,c,d):await Promise.allSettled([...o.values()]),t.removeListener(`SIGINT`,p),t.removeListener(`SIGTERM`,p)}}export{d as runExecutionPlan};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CommandTarget, CreateExecutionPlanInput, EnvMap, EnvironmentConfig, ExecutionPlan, ExecutionTask, MATRIX_ENVIRONMENTS, MatrixConfig, MatrixEnvironment, NormalizedProduct, NormalizedProject, NormalizedTarget, NormalizedVariant, ProductConfig, ProjectConfig, Scalar, SuffixConfig, TargetConfig, TargetDependency, TargetOverride, VariantConfig } from "./types.js";
|
|
1
|
+
import { ArtifactConfig, CommandTarget, CreateExecutionPlanInput, EnvMap, EnvironmentConfig, ExecutionPlan, ExecutionTask, MATRIX_ENVIRONMENTS, MatrixConfig, MatrixEnvironment, NodeEnvironment, NormalizedProduct, NormalizedProject, NormalizedTarget, NormalizedVariant, ProductConfig, ProjectConfig, Scalar, SuffixConfig, TargetConfig, TargetDependency, TargetOverride, VariantConfig } from "./types.js";
|
|
2
2
|
import { MATRIX_DEFAULTS, defaultEnvironmentForTarget } from "./defaults.js";
|
|
3
3
|
import { defineMatrixConfig, defineMatrixEnv, listMatrixEnvironments, loadMatrixConfig, normalizeMatrixConfig } from "./config.js";
|
|
4
4
|
import { createExecutionPlan } from "./plan.js";
|
|
5
5
|
import { assertMatrixConfig, matrixConfigSchema } from "./schema.js";
|
|
6
|
-
export { type CommandTarget, type CreateExecutionPlanInput, type EnvMap, type EnvironmentConfig, type ExecutionPlan, type ExecutionTask, MATRIX_DEFAULTS, MATRIX_ENVIRONMENTS, type MatrixConfig, type MatrixEnvironment, type NormalizedProduct, type NormalizedProject, type NormalizedTarget, type NormalizedVariant, type ProductConfig, type ProjectConfig, type Scalar, type SuffixConfig, type TargetConfig, type TargetDependency, type TargetOverride, type VariantConfig, assertMatrixConfig, createExecutionPlan, defaultEnvironmentForTarget, defineMatrixConfig, defineMatrixEnv, listMatrixEnvironments, loadMatrixConfig, matrixConfigSchema, normalizeMatrixConfig };
|
|
6
|
+
export { type ArtifactConfig, type CommandTarget, type CreateExecutionPlanInput, type EnvMap, type EnvironmentConfig, type ExecutionPlan, type ExecutionTask, MATRIX_DEFAULTS, MATRIX_ENVIRONMENTS, type MatrixConfig, type MatrixEnvironment, type NodeEnvironment, type NormalizedProduct, type NormalizedProject, type NormalizedTarget, type NormalizedVariant, type ProductConfig, type ProjectConfig, type Scalar, type SuffixConfig, type TargetConfig, type TargetDependency, type TargetOverride, type VariantConfig, assertMatrixConfig, createExecutionPlan, defaultEnvironmentForTarget, defineMatrixConfig, defineMatrixEnv, listMatrixEnvironments, loadMatrixConfig, matrixConfigSchema, normalizeMatrixConfig };
|
package/dist/plan.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MATRIX_DEFAULTS as e}from"./defaults.js";import t from"node:path";import n from"node:process";function r(...e){return Object.assign({},...e.filter(Boolean))}function i(){return Object.fromEntries(Object.entries(n.env).filter(e=>e[1]!==void 0))}function a(e,t){return e===void 0||t===void 0?e:`${e}${t}`}function o(...e){let t={};for(let n of e)for(let[e,r]of Object.entries(n??{}))t[e]={...t[e],...r};return t}function
|
|
1
|
+
import{MATRIX_DEFAULTS as e}from"./defaults.js";import t from"node:path";import n from"node:process";function r(...e){return Object.assign({},...e.filter(Boolean))}function i(){return Object.fromEntries(Object.entries(n.env).filter(e=>e[1]!==void 0))}function a(e,t){return e===void 0||t===void 0?e:`${e}${t}`}function o(e,t){let n=e[t];return n===void 0?void 0:String(n)}function s(...e){let t={};for(let n of e)for(let[e,r]of Object.entries(n??{}))t[e]={...t[e],...r};return t}function c(e,t,n,r){let i={...e.suffixes?.[n]??{},...t.suffixes?.[n]??{}},s=o(r,`MATRIX_PRODUCT_NAME`)??t.name??e.name,c=o(r,`MATRIX_PRODUCT_SLUG`)??t.slug??e.slug,l=o(r,`MATRIX_PRODUCT_APP_ID`)??t.appId??e.appId;return{id:e.id,name:a(s,i.name),slug:a(c,i.slug),appId:a(l,i.appId)}}function l(e,t){return e.condition??(t.continuous?`ready`:`completed`)}function u(n){let a=/* @__PURE__ */ new Map,o=/* @__PURE__ */ new Set,u=[],d=(f,p,m)=>{let h=`${f}:${p}:${m}`,g=a.get(h);if(g)return g;if(o.has(h))throw Error(`Dependency cycle detected at ${h}`);let _=n.products[f];if(!_)throw Error(`Unknown product: ${f}`);let v=_.variants[p];if(!v)throw Error(`Unknown variant ${p} for product ${f}`);let y=n.projects[v.project];if(!y)throw Error(`Variant ${f}/${p} references unknown project ${v.project}`);let b=v.targets[m];if(!b)throw Error(`Variant ${f}/${p} has no target ${m}`);o.add(h);let x=b.dependsOn.map(e=>{let t=e.target??m,n=_.variants[e.variant];if(!n)throw Error(`Unknown dependency variant ${f}/${e.variant}`);let r=n.targets[t];if(!r)throw Error(`Variant ${f}/${e.variant} has no target ${t}`);return{id:d(f,e.variant,t).id,condition:l(e,r)}});o.delete(h);let S=r(n.config.env,_.env,n.externalEnv??i()),C=c({..._,suffixes:s(n.config.suffixes,_.suffixes)},v,n.envName,S),w=t.resolve(n.cwd,y.root??e.projectRoot),T={id:h,product:f,variant:p,project:v.project,projectRoot:w,target:m,name:C.name,slug:C.slug,...C.appId?{appId:C.appId}:{},command:b.command,cwd:w,env:r(S,{MATRIX_ENV_NAME:n.envName,MATRIX_TARGET:m,MATRIX_PRODUCT_KEY:f,MATRIX_PRODUCT_ID:C.id,MATRIX_PRODUCT_NAME:C.name,MATRIX_PRODUCT_SLUG:C.slug,MATRIX_VARIANT:p,MATRIX_PROJECT:v.project,NODE_ENV:b.nodeEnv,...C.appId?{MATRIX_PRODUCT_APP_ID:C.appId}:{}}),continuous:b.continuous,artifacts:b.artifacts,...b.readyWhen?{readyWhen:b.readyWhen}:{},outputDir:t.resolve(w,b.outputDir),dependsOn:x};return a.set(h,T),u.push(T),T};for(let e of n.productNames){let t=n.products[e];if(!t)throw Error(`Unknown product: ${e}`);let r=n.variantNames?.length?n.variantNames:Object.keys(t.variants);for(let t of r)d(e,t,n.target)}return{envName:n.envName,tasks:u,artifactsRoot:t.resolve(n.cwd,n.config.artifacts?.root??e.artifactsRoot),artifactRetention:n.config.artifacts?.retention?.keep??e.artifacts.retention}}function d(e){for(let[t,n]of Object.entries(e.products))for(let[r,i]of Object.entries(n.variants))for(let n of Object.keys(i.targets))u({...e,productNames:[t],variantNames:[r],target:n})}export{u as createExecutionPlan,d as validateExecutionGraph};
|
package/dist/rollup.d.ts
ADDED
package/dist/rollup.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{MatrixUnplugin as e}from"./unplugin.js";var t=e.rollup;export{t as default};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/runtime.d.ts
|
|
2
|
+
export interface MatrixRuntime<Config extends Record<string, string> = Record<string, string>> {
|
|
3
|
+
environment: string;
|
|
4
|
+
target: string;
|
|
5
|
+
nodeEnv: 'development' | 'production' | 'test' | string;
|
|
6
|
+
variant: string;
|
|
7
|
+
project: string;
|
|
8
|
+
product: {
|
|
9
|
+
key: string;
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
appId?: string;
|
|
14
|
+
};
|
|
15
|
+
config: Config;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
package/dist/schema.d.ts
CHANGED
|
@@ -14,8 +14,9 @@ export declare const matrixConfigSchema: v.ObjectSchema<{
|
|
|
14
14
|
readonly projects: v.RecordSchema<v.StringSchema<undefined>, v.ObjectSchema<{
|
|
15
15
|
readonly root: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
16
16
|
readonly targets: v.RecordSchema<v.StringSchema<undefined>, v.UnionSchema<[v.StringSchema<undefined>, v.ObjectSchema<{
|
|
17
|
-
readonly command: v.StringSchema<undefined>;
|
|
17
|
+
readonly command: v.UnionSchema<[v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, undefined>]>], undefined>;
|
|
18
18
|
readonly continuous: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
19
|
+
readonly nodeEnv: v.OptionalSchema<v.PicklistSchema<["development", "production", "test"], undefined>, undefined>;
|
|
19
20
|
readonly readyWhen: v.OptionalSchema<v.ObjectSchema<{
|
|
20
21
|
readonly type: v.LiteralSchema<"port", undefined>;
|
|
21
22
|
readonly host: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -23,10 +24,11 @@ export declare const matrixConfigSchema: v.ObjectSchema<{
|
|
|
23
24
|
readonly timeout: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
24
25
|
}, undefined>, undefined>;
|
|
25
26
|
readonly outputDir: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
26
|
-
readonly
|
|
27
|
-
readonly
|
|
27
|
+
readonly artifacts: v.OptionalSchema<v.ObjectSchema<{
|
|
28
|
+
readonly mode: v.OptionalSchema<v.PicklistSchema<["move", "archive", "both"], undefined>, undefined>;
|
|
28
29
|
readonly format: v.OptionalSchema<v.PicklistSchema<["zip", "tar.gz"], undefined>, undefined>;
|
|
29
|
-
|
|
30
|
+
readonly removeSource: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
31
|
+
}, undefined>, undefined>;
|
|
30
32
|
readonly dependsOn: v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.StringSchema<undefined>, v.ObjectSchema<{
|
|
31
33
|
readonly variant: v.StringSchema<undefined>;
|
|
32
34
|
readonly target: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -58,9 +60,10 @@ export declare const matrixConfigSchema: v.ObjectSchema<{
|
|
|
58
60
|
readonly slug: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
59
61
|
readonly appId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
60
62
|
}, undefined>, undefined>, undefined>;
|
|
61
|
-
readonly targets: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnionSchema<[v.StringSchema<undefined>, v.ObjectSchema<{
|
|
62
|
-
readonly command: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
63
|
+
readonly targets: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnionSchema<[v.StringSchema<undefined>, v.UnionSchema<[v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, undefined>]>], undefined>, v.ObjectSchema<{
|
|
64
|
+
readonly command: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, undefined>]>], undefined>, undefined>;
|
|
63
65
|
readonly continuous: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
66
|
+
readonly nodeEnv: v.OptionalSchema<v.PicklistSchema<["development", "production", "test"], undefined>, undefined>;
|
|
64
67
|
readonly readyWhen: v.OptionalSchema<v.ObjectSchema<{
|
|
65
68
|
readonly type: v.LiteralSchema<"port", undefined>;
|
|
66
69
|
readonly host: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -68,10 +71,11 @@ export declare const matrixConfigSchema: v.ObjectSchema<{
|
|
|
68
71
|
readonly timeout: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
69
72
|
}, undefined>, undefined>;
|
|
70
73
|
readonly outputDir: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
71
|
-
readonly
|
|
72
|
-
readonly
|
|
74
|
+
readonly artifacts: v.OptionalSchema<v.ObjectSchema<{
|
|
75
|
+
readonly mode: v.OptionalSchema<v.PicklistSchema<["move", "archive", "both"], undefined>, undefined>;
|
|
73
76
|
readonly format: v.OptionalSchema<v.PicklistSchema<["zip", "tar.gz"], undefined>, undefined>;
|
|
74
|
-
|
|
77
|
+
readonly removeSource: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
78
|
+
}, undefined>, undefined>;
|
|
75
79
|
readonly dependsOn: v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.StringSchema<undefined>, v.ObjectSchema<{
|
|
76
80
|
readonly variant: v.StringSchema<undefined>;
|
|
77
81
|
readonly target: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -82,6 +86,9 @@ export declare const matrixConfigSchema: v.ObjectSchema<{
|
|
|
82
86
|
}, undefined>, undefined>;
|
|
83
87
|
readonly artifacts: v.OptionalSchema<v.ObjectSchema<{
|
|
84
88
|
readonly root: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
89
|
+
readonly retention: v.OptionalSchema<v.ObjectSchema<{
|
|
90
|
+
readonly keep: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
91
|
+
}, undefined>, undefined>;
|
|
85
92
|
}, undefined>, undefined>;
|
|
86
93
|
}, undefined>;
|
|
87
94
|
/** Validates a configuration and throws a Valibot error when it is malformed. */
|
package/dist/schema.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"valibot";const t=e.union([e.string(),e.number(),e.boolean()]),n=e.optional(e.record(e.string(),t)),r=e.object({name:e.optional(e.string()),slug:e.optional(e.string()),appId:e.optional(e.string())}),i=e.object({variant:e.string(),target:e.optional(e.string()),condition:e.optional(e.picklist([`completed`,`ready`]))}),a=e.union([e.string(),i]),o=e.pipe(e.number(),e.integer(),e.minValue(1),e.maxValue(65535)),s=e.pipe(e.number(),e.integer(),e.minValue(1)),c=e.union([e.string(),e.
|
|
1
|
+
import*as e from"valibot";const t=e.union([e.string(),e.number(),e.boolean()]),n=e.optional(e.record(e.string(),t)),r=e.object({name:e.optional(e.string()),slug:e.optional(e.string()),appId:e.optional(e.string())}),i=e.object({variant:e.string(),target:e.optional(e.string()),condition:e.optional(e.picklist([`completed`,`ready`]))}),a=e.union([e.string(),i]),o=e.pipe(e.number(),e.integer(),e.minValue(1),e.maxValue(65535)),s=e.pipe(e.number(),e.integer(),e.minValue(1)),c=e.union([e.string(),e.pipe(e.array(e.string()),e.minLength(1))]),l=e.object({mode:e.optional(e.picklist([`move`,`archive`,`both`])),format:e.optional(e.picklist([`zip`,`tar.gz`])),removeSource:e.optional(e.boolean())}),u=e.union([e.string(),e.object({command:c,continuous:e.optional(e.boolean()),nodeEnv:e.optional(e.picklist([`development`,`production`,`test`])),readyWhen:e.optional(e.object({type:e.literal(`port`),host:e.optional(e.string()),port:o,timeout:e.optional(s)})),outputDir:e.optional(e.string()),artifacts:e.optional(l),dependsOn:e.optional(e.array(a))})]),d=e.union([e.string(),c,e.object({command:e.optional(c),continuous:e.optional(e.boolean()),nodeEnv:e.optional(e.picklist([`development`,`production`,`test`])),readyWhen:e.optional(e.object({type:e.literal(`port`),host:e.optional(e.string()),port:o,timeout:e.optional(s)})),outputDir:e.optional(e.string()),artifacts:e.optional(l),dependsOn:e.optional(e.array(a))})]),f=e.object({root:e.optional(e.string()),targets:e.record(e.string(),u)}),p=e.object({env:n}),m=e.union([e.string(),e.object({project:e.string(),name:e.optional(e.string()),slug:e.optional(e.string()),appId:e.optional(e.string()),suffixes:e.optional(e.record(e.string(),r)),targets:e.optional(e.record(e.string(),d))})]),h=e.object({id:e.optional(e.string()),name:e.optional(e.string()),slug:e.optional(e.string()),appId:e.optional(e.string()),env:n,$env:e.optional(e.record(e.string(),p)),suffixes:e.optional(e.record(e.string(),r)),variants:e.record(e.string(),m)}),g=e.object({suffixes:e.optional(e.record(e.string(),r)),env:n,$env:e.optional(e.record(e.string(),p)),projects:e.record(e.string(),f),products:e.record(e.string(),h),artifacts:e.optional(e.object({root:e.optional(e.string()),retention:e.optional(e.object({keep:e.optional(e.pipe(e.number(),e.integer(),e.minValue(1)))}))}))});function _(t){return e.parse(g,t)}export{_ as assertMatrixConfig,g as matrixConfigSchema};
|
package/dist/typegen.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ensureMatrixEnvPrefix as e,publicEnvConfigName as t,publicEnvKeys as n}from"./env.js";import r from"node:path";import{randomUUID as i}from"node:crypto";import{mkdir as a,readFile as o,rename as s,writeFile as c}from"node:fs/promises";function l(e){if(!e)return`virtual:matrix/runtime`;if(!/^[\w-]+$/.test(e))throw Error(`Invalid Matrix scope: ${e}`);return`virtual:matrix/runtime/${e}`}async function u(u){let d=e(u.envPrefix),f=n(u.env,d),p=f.map(e=>t(e,d)).filter(Boolean),m=[...new Set(p)].sort(),h=l(u.scope),g=u.scope?`.matrix/types/matrix-runtime-${u.scope}.d.ts`:`.matrix/types/matrix-runtime.d.ts`,_=r.resolve(u.cwd,u.output??g),v=["// Generated by `matrix prepare`. Do not edit manually.",`import type { MatrixRuntime } from '@xova/matrix/runtime'`,``,`interface MatrixConfig {`,...m.map(e=>` readonly ${e}: string`),`}`,``,`declare global {`,` interface ImportMetaEnv {`,...f.map(e=>` readonly ${e}: string`),` }`,`}`,``,`declare module '${h}' {`,` const matrix: MatrixRuntime<MatrixConfig>`,` export { matrix }`,`}`,``].join(`
|
|
2
|
+
`);if(await a(r.dirname(_),{recursive:!0}),await o(_,`utf8`).catch(()=>void 0)!==v){let e=`${_}.${i()}.tmp`;await c(e,v),await s(e,_)}return _}function d(...e){return Object.fromEntries([...new Set(e.flatMap(e=>e?Object.keys(e):[]))].map(e=>[e,``]))}export{u as generateMatrixTypes,l as matrixRuntimeModuleId,d as matrixTypeEnvKeys};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
2
|
/** Values that can be passed to a process as environment variables. */
|
|
3
3
|
export type Scalar = string | number | boolean;
|
|
4
|
+
/** Node.js runtime mode exported as `NODE_ENV` for child processes. */
|
|
5
|
+
export type NodeEnvironment = 'development' | 'production' | 'test';
|
|
4
6
|
/** A flat environment variable map. */
|
|
5
7
|
export type EnvMap = Record<string, Scalar>;
|
|
6
8
|
/** Configuration for a project command such as `dev`, `build`, or `preview`. */
|
|
7
9
|
export interface CommandTarget {
|
|
8
10
|
/** Command to execute from the project's root directory. */
|
|
9
|
-
command: string;
|
|
11
|
+
command: string | string[];
|
|
10
12
|
/** Whether the command keeps running after it starts. Defaults from the target name. */
|
|
11
13
|
continuous?: boolean;
|
|
14
|
+
/** Node.js runtime mode passed to the target process. */
|
|
15
|
+
nodeEnv?: NodeEnvironment;
|
|
12
16
|
/** Readiness probe used by dependent continuous targets. */
|
|
13
17
|
readyWhen?: {
|
|
14
18
|
/** Probe type. Port probing is currently supported. */
|
|
@@ -20,20 +24,22 @@ export interface CommandTarget {
|
|
|
20
24
|
/** Maximum time to wait for readiness, in milliseconds. */
|
|
21
25
|
timeout?: number;
|
|
22
26
|
};
|
|
23
|
-
/** Directory
|
|
27
|
+
/** Directory containing completed output, relative to the project root. Defaults to `dist`. */
|
|
24
28
|
outputDir?: string;
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
enabled: boolean;
|
|
28
|
-
format?: 'zip' | 'tar.gz';
|
|
29
|
-
};
|
|
29
|
+
/** How completed output should be materialized as an artifact. */
|
|
30
|
+
artifacts?: ArtifactConfig;
|
|
30
31
|
/** Other variants that must run before this target. */
|
|
31
32
|
dependsOn?: Array<string | TargetDependency>;
|
|
32
33
|
}
|
|
33
34
|
/** Short target syntax containing only the command. */
|
|
34
|
-
export type TargetConfig = string | CommandTarget;
|
|
35
|
+
export type TargetConfig = string | string[] | CommandTarget;
|
|
35
36
|
/** Partial target configuration used to override a project's target on a variant. */
|
|
36
|
-
export type TargetOverride = string | Partial<CommandTarget>;
|
|
37
|
+
export type TargetOverride = string | string[] | Partial<CommandTarget>;
|
|
38
|
+
export interface ArtifactConfig {
|
|
39
|
+
mode?: 'move' | 'archive' | 'both';
|
|
40
|
+
format?: 'zip' | 'tar.gz';
|
|
41
|
+
removeSource?: boolean;
|
|
42
|
+
}
|
|
37
43
|
/** Dependency on another variant of the same product. */
|
|
38
44
|
export interface TargetDependency {
|
|
39
45
|
/** Variant that must be executed first. */
|
|
@@ -113,6 +119,9 @@ export interface MatrixConfig {
|
|
|
113
119
|
/** Output artifact configuration. */
|
|
114
120
|
artifacts?: {
|
|
115
121
|
root?: string;
|
|
122
|
+
retention?: {
|
|
123
|
+
keep?: number;
|
|
124
|
+
};
|
|
116
125
|
};
|
|
117
126
|
}
|
|
118
127
|
/** Built-in environment names offered by Matrix. Custom names can be added with `$env`. */
|
|
@@ -120,13 +129,15 @@ export declare const MATRIX_ENVIRONMENTS: readonly ["development", "staging", "p
|
|
|
120
129
|
/** A built-in Matrix environment name. */
|
|
121
130
|
export type MatrixEnvironment = typeof MATRIX_ENVIRONMENTS[number];
|
|
122
131
|
/** Target after defaults and variant overrides have been resolved. */
|
|
123
|
-
export type NormalizedTarget = Omit<CommandTarget, 'outputDir' | 'dependsOn'> & {
|
|
132
|
+
export type NormalizedTarget = Omit<CommandTarget, 'outputDir' | 'dependsOn' | 'artifacts'> & {
|
|
124
133
|
name: string;
|
|
125
134
|
continuous: boolean;
|
|
135
|
+
nodeEnv: NodeEnvironment;
|
|
126
136
|
outputDir: string;
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
artifacts: {
|
|
138
|
+
mode: 'move' | 'archive' | 'both' | 'none';
|
|
129
139
|
format: 'zip' | 'tar.gz';
|
|
140
|
+
removeSource: boolean;
|
|
130
141
|
};
|
|
131
142
|
dependsOn: TargetDependency[];
|
|
132
143
|
};
|
|
@@ -169,18 +180,19 @@ export interface ExecutionTask {
|
|
|
169
180
|
slug: string;
|
|
170
181
|
/** Resolved application identifier, when configured. */
|
|
171
182
|
appId?: string;
|
|
172
|
-
/** Command to execute. */
|
|
173
|
-
command: string;
|
|
183
|
+
/** Command or ordered commands to execute. */
|
|
184
|
+
command: string | string[];
|
|
174
185
|
/** Working directory for the command. */
|
|
175
186
|
cwd: string;
|
|
176
187
|
/** Environment passed to the command. */
|
|
177
188
|
env: EnvMap;
|
|
178
189
|
/** Whether the command is expected to remain running. */
|
|
179
190
|
continuous: boolean;
|
|
180
|
-
/** Resolved
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
/** Resolved artifact settings. */
|
|
192
|
+
artifacts: {
|
|
193
|
+
mode: 'move' | 'archive' | 'both' | 'none';
|
|
183
194
|
format: 'zip' | 'tar.gz';
|
|
195
|
+
removeSource: boolean;
|
|
184
196
|
};
|
|
185
197
|
/** Readiness probe, when configured. */
|
|
186
198
|
readyWhen?: {
|
|
@@ -203,8 +215,9 @@ export interface ExecutionPlan {
|
|
|
203
215
|
envName: string;
|
|
204
216
|
/** Tasks in dependency-safe execution order. */
|
|
205
217
|
tasks: ExecutionTask[];
|
|
206
|
-
/** Absolute root directory for generated
|
|
218
|
+
/** Absolute root directory for generated artifacts. */
|
|
207
219
|
artifactsRoot: string;
|
|
220
|
+
artifactRetention: number;
|
|
208
221
|
}
|
|
209
222
|
/** Input accepted by {@link createExecutionPlan}. */
|
|
210
223
|
export interface CreateExecutionPlanInput {
|
|
@@ -212,6 +225,9 @@ export interface CreateExecutionPlanInput {
|
|
|
212
225
|
config: {
|
|
213
226
|
artifacts?: {
|
|
214
227
|
root?: string;
|
|
228
|
+
retention?: {
|
|
229
|
+
keep?: number;
|
|
230
|
+
};
|
|
215
231
|
};
|
|
216
232
|
env?: EnvMap;
|
|
217
233
|
suffixes?: Record<string, SuffixConfig>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EnvPrefix } from "./env.js";
|
|
2
|
+
import { MatrixRuntime } from "./runtime.js";
|
|
3
|
+
import "unplugin";
|
|
4
|
+
//#region src/unplugin.d.ts
|
|
5
|
+
export interface MatrixUnpluginOptions {
|
|
6
|
+
/** Public prefixes for non-Vite adapters; Vite uses the resolved config. */
|
|
7
|
+
envPrefix?: EnvPrefix;
|
|
8
|
+
/** Build scope used to isolate Electron main/preload/renderer runtime modules and types. */
|
|
9
|
+
scope?: string;
|
|
10
|
+
/** Generate project-local declarations during the build. Defaults to true. */
|
|
11
|
+
types?: boolean | {
|
|
12
|
+
output?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
package/dist/unplugin.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createPublicConfig as e,ensureMatrixEnvPrefix as t,normalizeEnvPrefix as n}from"./env.js";import{generateMatrixTypes as r,matrixRuntimeModuleId as i}from"./typegen.js";import a from"node:process";import{createUnplugin as o}from"unplugin";function s(t,r=[`VITE_`,`MATRIX_`]){let i=n(r);return{environment:t.MATRIX_ENV_NAME??``,target:t.MATRIX_TARGET??``,nodeEnv:t.NODE_ENV??``,variant:t.MATRIX_VARIANT??``,project:t.MATRIX_PROJECT??``,product:{key:t.MATRIX_PRODUCT_KEY??``,id:t.MATRIX_PRODUCT_ID??``,name:t.MATRIX_PRODUCT_NAME??``,slug:t.MATRIX_PRODUCT_SLUG??``,...t.MATRIX_PRODUCT_APP_ID?{appId:t.MATRIX_PRODUCT_APP_ID}:{}},config:e(t,i)}}function c(e){return[`export const matrix = `,JSON.stringify(e),`
|
|
2
|
+
`].join(``)}function l(){return Object.fromEntries(Object.entries(a.env).filter(e=>e[1]!==void 0))}const u=(e={})=>{let n=t(e.envPrefix),o=l(),u=!1,d=i(e.scope),f=`\0${d}`;async function p(t){e.types===!1||u||(await r({cwd:t,env:o,envPrefix:n,...e.scope?{scope:e.scope}:{},...typeof e.types==`object`&&e.types.output?{output:e.types.output}:{}}),u=!0)}return{name:`xova-matrix`,vite:{config(n){let r=e.envPrefix??n.envPrefix;return{envPrefix:t(r)}},async configResolved(e){n=t(e.envPrefix),o=e.env,await p(e.root)}},async buildStart(){await p(a.cwd())},resolveId(e){return e===d?f:void 0},load(e){if(e===f)return c(s(o,n))}}},d=o(u);export{d as MatrixUnplugin,s as createMatrixRuntime,u as matrixUnpluginFactory};
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MatrixUnpluginOptions } from "./unplugin.js";
|
|
2
|
+
//#region src/vite.d.ts
|
|
3
|
+
declare const _default: (options?: MatrixUnpluginOptions | undefined) => import("unplugin").VitePlugin<any> | import("unplugin").VitePlugin<any>[];
|
|
4
|
+
//#endregion
|
|
5
|
+
export { _default as default };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{MatrixUnplugin as e}from"./unplugin.js";var t=e.vite;export{t as default};
|
package/dist/webpack.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{MatrixUnplugin as e}from"./unplugin.js";var t=e.webpack;export{t as default};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xova/matrix",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2",
|
|
5
5
|
"description": "A configuration-driven multi-app workspace orchestration engine and CLI.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/xova-dev/matrix#readme",
|
|
@@ -31,6 +31,26 @@
|
|
|
31
31
|
"./plan": {
|
|
32
32
|
"types": "./dist/plan.d.ts",
|
|
33
33
|
"import": "./dist/plan.js"
|
|
34
|
+
},
|
|
35
|
+
"./vite": {
|
|
36
|
+
"types": "./dist/vite.d.ts",
|
|
37
|
+
"import": "./dist/vite.js"
|
|
38
|
+
},
|
|
39
|
+
"./rollup": {
|
|
40
|
+
"types": "./dist/rollup.d.ts",
|
|
41
|
+
"import": "./dist/rollup.js"
|
|
42
|
+
},
|
|
43
|
+
"./webpack": {
|
|
44
|
+
"types": "./dist/webpack.d.ts",
|
|
45
|
+
"import": "./dist/webpack.js"
|
|
46
|
+
},
|
|
47
|
+
"./esbuild": {
|
|
48
|
+
"types": "./dist/esbuild.d.ts",
|
|
49
|
+
"import": "./dist/esbuild.js"
|
|
50
|
+
},
|
|
51
|
+
"./runtime": {
|
|
52
|
+
"types": "./dist/runtime.d.ts",
|
|
53
|
+
"import": "./dist/runtime.js"
|
|
34
54
|
}
|
|
35
55
|
},
|
|
36
56
|
"bin": {
|
|
@@ -49,6 +69,8 @@
|
|
|
49
69
|
"c12": "^3.3.0",
|
|
50
70
|
"consola": "^3.4.2",
|
|
51
71
|
"execa": "^9.6.0",
|
|
72
|
+
"scule": "^1.3.0",
|
|
73
|
+
"unplugin": "^3.4.0",
|
|
52
74
|
"valibot": "^1.1.0"
|
|
53
75
|
},
|
|
54
76
|
"devDependencies": {
|
|
@@ -66,7 +88,7 @@
|
|
|
66
88
|
},
|
|
67
89
|
"scripts": {
|
|
68
90
|
"build": "tsdown",
|
|
69
|
-
"release:prepare": "changelogen --release --push",
|
|
91
|
+
"release:prepare": "changelogen --clean --release --push",
|
|
70
92
|
"release:github": "changelogen gh release",
|
|
71
93
|
"test:pack": "node scripts/pack-smoke.mjs",
|
|
72
94
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|