@mirta/package 0.0.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
package/README.md CHANGED
@@ -1,45 +1,181 @@
1
- # @mirta/package
1
+ # `@mirta/package`
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ [![en](https://img.shields.io/badge/lang-en-olivedrab.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta-package/README.md)
4
+ [![ru](https://img.shields.io/badge/lang-ru-dimgray.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta-package/README.ru.md)
5
+ [![NPM Version](https://img.shields.io/npm/v/@mirta/package?style=flat-square)](https://npmjs.com/package/@mirta/package)
6
+ [![NPM Downloads](https://img.shields.io/npm/dm/@mirta/package?style=flat-square&logo=npm)](https://npmjs.com/package/@mirta/package)
4
7
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
8
+ > A simple and reliable way to read `package.json` in Mirta tools.
6
9
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
10
+ `@mirta/package` is a utility for safely reading `package.json` in the development environment. It supports:
11
+ - TypeScript typing
12
+ - Clear error handling
13
+ - Reading only required fields: `name`, `exports`, `workspaces`
14
+ - Synchronous and asynchronous APIs
8
15
 
9
- ## Purpose
16
+ Used internally by `@mirta/workspace`, `@mirta/rollup`, and other Mirta tools for project structure analysis.<br/>
10
17
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@mirta/package`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
18
+ **Not intended for execution in the Duktape environment on Wiren Board controllers.**
15
19
 
16
- ## What is OIDC Trusted Publishing?
20
+ ## 📦 Installation
17
21
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
22
+ ```bash
23
+ # Not required directly — used internally by Mirta
24
+ pnpm add -D @mirta/package
25
+ ```
26
+ ⚠️ This package is part of Mirta's internal infrastructure. It is typically not used directly.
19
27
 
20
- ## Setup Instructions
28
+ ## 🚀 Quick Start
21
29
 
22
- To properly configure OIDC trusted publishing for this package:
30
+ ```ts
31
+ import { readPackage, readPackageAsync, PackageError } from '@mirta/package'
23
32
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
33
+ // Synchronous reading
28
34
 
29
- ## DO NOT USE THIS PACKAGE
35
+ try {
36
+ const pkg = readPackage('packages/mirta-testing')
37
+ console.log(pkg.name)
38
+ } catch (err) {
39
+ if (err instanceof PackageError)
40
+ console.error('Error:', err.message)
41
+ }
30
42
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
43
+ // Asynchronous reading
36
44
 
37
- ## More Information
45
+ try {
46
+ const pkg = await readPackageAsync('packages/mirta-testing')
47
+ console.log(pkg.name)
48
+ } catch (err) {
49
+ if (err instanceof PackageError)
50
+ console.error('Error:', err.message)
51
+ }
52
+ ```
38
53
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
54
+ ## 🧰 API
55
+
56
+ `readPackage(path: string): Package`
57
+
58
+ Synchronously reads and parses `package.json` from the given path.
59
+
60
+ Supports:
61
+ - Path to file: `'package.json'`, `'packages/mirta-testing/package.json'`
62
+ - Path to package directory: `'.'`, `'packages/mirta-testing'`
63
+
64
+ Returns: an object of type `Package`.<br/>
65
+ Throws: `PackageError` with one of the error codes listed in the "[Possible error codes](#possible-error-codes)" section.
66
+
67
+ ---
68
+
69
+ `readPackageAsync(path: string): Promise<Package>`
70
+
71
+ Asynchronously reads and parses `package.json` from the specified path.
72
+
73
+ Fully equivalent to `readPackage`, but works asynchronously. Recommended for use in async contexts (e.g. bundler plugins).
74
+
75
+ Returns: a Promise resolving to a `Package` object.<br/>
76
+ Throws: `PackageError` with one of the error codes listed in the "[Possible error codes](#possible-error-codes)" section.
42
77
 
43
78
  ---
44
79
 
45
- **Maintained for OIDC setup purposes only**
80
+ `parsePackageJson(content: string): Package`
81
+
82
+ Parses a string containing `package.json` content into a `Package` object.
83
+
84
+ Use if the file content is already loaded (e.g. from cache or test).
85
+
86
+ ---
87
+
88
+ `PackageError`
89
+
90
+ Error class with clear messages and codes. Helps quickly identify what went wrong.
91
+
92
+ <a name="#possible-error-codes"></a>
93
+ Possible error codes:
94
+ - `notFound`: the package.json file was not found,
95
+ - `accessDenied`: permission denied to read the file,
96
+ - `invalidPath`: the path does not point to a package.json file or package directory,
97
+ - `invalidJson`: the file contains invalid or malformed JSON,
98
+ - `invalidJsonRoot`: the JSON root is not an object,
99
+ - `failedToRead`: failed to read the file.
100
+
101
+ Example usage:
102
+
103
+ ```ts
104
+ if (err.code === 'notFound') {
105
+ console.error('File not found:', err.message)
106
+ }
107
+ ```
108
+ ## 🧩 Supported Fields
109
+
110
+ The package reads only the `package.json` fields required by the framework:
111
+
112
+ `name`
113
+
114
+ Package name, e.g.: `"@mirta/testing"`
115
+
116
+ `exports`
117
+
118
+ Simplified format with import is supported:
119
+
120
+ ```json
121
+ {
122
+ "exports": {
123
+ ".": {
124
+ "import": "./dist/index.mjs"
125
+ },
126
+ "./setup-global": "./dist/setup/global.mjs"
127
+ }
128
+ }
129
+ ```
130
+ Or with types:
131
+
132
+ ```json
133
+ {
134
+ "exports": {
135
+ ".": {
136
+ "import": {
137
+ "types": "./dist/index.d.mts",
138
+ "default": "./dist/index.mjs"
139
+ }
140
+ }
141
+ }
142
+ }
143
+ ```
144
+ Ignored: `require`, `node`, `browser`, and other conditions.
145
+
146
+ `workspaces`
147
+
148
+ Only array of strings is allowed: `["packages/*"]`</br>
149
+ Object format (`{ packages: [...] }`) is not supported.
150
+
151
+ ## ✅ Testing
152
+
153
+ The package is fully tested:
154
+
155
+ - Successful `package.json` reading
156
+ - Handling all error types: file not found, no access, invalid JSON
157
+ - Support for various paths
158
+ - Correct error mapping to `PackageError`
159
+
160
+ Uses Vitest, dependency mocks, and isolated tests.
161
+
162
+ ⚠️ Limitations
163
+
164
+ - Works only in Node.js (not in Duktape).
165
+ - Supports only `import` in `exports`.
166
+ - The `workspaces` field must be an array of strings.
167
+ - Use `readPackageAsync` in asynchronous environments.
168
+ - Synchronous operations are not recommended in async contexts (use `readPackageAsync`).
169
+
170
+ ## 🔄 Usage in `@mirta/workspace`
171
+
172
+ This package is used in `@mirta/workspace` to:
173
+ - Read `package.json` of the root project and individual packages.
174
+ - Validate the `workspaces` field.
175
+ - Collect metadata from every package in the monorepo.
176
+
177
+ Example:
178
+ ```ts
179
+ const pkg = await readPackageAsync(`${rootDir}/packages/mirta-testing/package.json`)
180
+ ```
181
+ Ensures a consistent and reliable way to access package metadata.
package/README.ru.md ADDED
@@ -0,0 +1,180 @@
1
+ # `@mirta/package`
2
+
3
+ [![en](https://img.shields.io/badge/lang-en-dimgray.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta-package/README.md)
4
+ [![ru](https://img.shields.io/badge/lang-ru-olivedrab.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta-package/README.ru.md)
5
+ [![NPM Version](https://img.shields.io/npm/v/@mirta/package?style=flat-square)](https://npmjs.com/package/@mirta/package)
6
+ [![NPM Downloads](https://img.shields.io/npm/dm/@mirta/package?style=flat-square&logo=npm)](https://npmjs.com/package/@mirta/package)
7
+
8
+ > Простой и надёжный способ чтения `package.json` в инструментах Mirta.
9
+
10
+ `@mirta/package` — это утилита для безопасного чтения `package.json` в среде разработки. Она поддерживает:
11
+ - TypeScript-типизацию
12
+ - Чёткую обработку ошибок
13
+ - Работу только с нужными полями: `name`, `exports`, `workspaces`
14
+ - Синхронный и асинхронный API
15
+
16
+ Используется внутри `@mirta/workspace`, `@mirta/rollup` и других инструментов Mirta для анализа структуры проекта.<br/>
17
+
18
+ **Не предназначен для выполнения в среде Duktape на контроллерах Wiren Board.**
19
+
20
+ ## 📦 Установка
21
+
22
+ ```bash
23
+ # Не требуется напрямую — используется внутри Mirta
24
+ pnpm add -D @mirta/package
25
+ ```
26
+ ⚠️ Этот пакет — часть внутренней инфраструктуры фреймворка Mirta. Обычно он не используется напрямую.
27
+
28
+ ## 🚀 Быстрый старт
29
+
30
+ ```ts
31
+ import { readPackage, readPackageAsync, PackageError } from '@mirta/package'
32
+
33
+ // Синхронное чтение
34
+
35
+ try {
36
+ const pkg = readPackage('packages/mirta-basics')
37
+ console.log(pkg.name)
38
+ } catch (err) {
39
+ if (err instanceof PackageError)
40
+ console.error('Ошибка:', err.message)
41
+ }
42
+
43
+ // Асинхронное чтение
44
+
45
+ try {
46
+ const pkg = await readPackageAsync('packages/mirta-basics')
47
+ console.log(pkg.name)
48
+ } catch (err) {
49
+ if (err instanceof PackageError)
50
+ console.error('Ошибка:', err.message)
51
+ }
52
+ ```
53
+
54
+ ## 🧰 API
55
+
56
+ `readPackage(path: string): Package`
57
+
58
+ Синхронно читает и парсит `package.json` по указанному пути.
59
+
60
+ Поддерживает:
61
+ - Путь к файлу: `'package.json'`, `'packages/core/package.json'`
62
+ - Путь к директории пакета: `'.'`, `'packages/core'`
63
+
64
+ Возвращает: объект типа `Package`.<br/>
65
+ Выбрасывает: `PackageError` с одним из кодов ошибок, перечисленных в разделе "[Возможные коды ошибок](#possible-error-codes)".
66
+
67
+ ---
68
+
69
+ `readPackageAsync(path: string): Promise<Package>`
70
+
71
+ Асинхронно читает и парсит `package.json` по указанному пути.
72
+
73
+ Полностью аналогичен `readPackage`, но работает асинхронно. Рекомендуется для использования в асинхронных контекстах (например, в плагинах сборщиков).
74
+
75
+ Выбрасывает: `PackageError` с одним из кодов ошибок, перечисленных в разделе "[Возможные коды ошибок](#possible-error-codes)".
76
+ Возвращает: промис с объектом типа Package.<br/>
77
+
78
+ ---
79
+
80
+ `parsePackageJson(content: string): Package`
81
+
82
+ Парсит строку с содержимым `package.json` в объект `Package`.
83
+
84
+ Используйте, если содержимое файла уже загружено (например, из кэша или теста).
85
+
86
+ ---
87
+ `PackageError`
88
+
89
+ Класс ошибок с понятными сообщениями и кодами. Помогает быстро выяснить, что пошло не так.
90
+
91
+ <a name="#possible-error-codes"></a>
92
+ Возможные коды ошибок:
93
+ - `notFound` — файл `package.json` не найден,
94
+ - `accessDenied` — нет прав на чтение файла,
95
+ - `invalidPath` — путь не ведёт к `package.json` или к папке пакета,
96
+ - `invalidJson` — повреждённый или невалидный JSON,
97
+ - `invalidJsonRoot` — корень JSON-файла не является объектом,
98
+ - `failedToRead` — не удалось прочитать файл.
99
+
100
+ Пример использования:
101
+
102
+ ```ts
103
+ if (err.code === 'notFound') {
104
+ console.error('Файл не найден:', err.message)
105
+ }
106
+ ```
107
+ ## 🧩 Поддерживаемые поля
108
+
109
+ Пакет читает только те поля `package.json`, которые нужны фреймворку:
110
+
111
+ `name`
112
+
113
+ Имя пакета, например: "@mirta/basics"
114
+
115
+ `exports`
116
+
117
+ Поддерживается упрощённый формат с `import`:
118
+
119
+ ```json
120
+ {
121
+ "exports": {
122
+ ".": {
123
+ "import": "./dist/index.mjs"
124
+ },
125
+ "./setup-global": "./dist/setup/global.mjs"
126
+ }
127
+ }
128
+ ```
129
+ Или с типами:
130
+
131
+ ```json
132
+ {
133
+ "exports": {
134
+ ".": {
135
+ "import": {
136
+ "types": "./dist/index.d.mts",
137
+ "default": "./dist/index.mjs"
138
+ }
139
+ }
140
+ }
141
+ }
142
+ ```
143
+ Игнорируются: `require`, `node`, `browser` и другие условия.
144
+
145
+ `workspaces`
146
+
147
+ Разрешён только массив строк: `["packages/*"]`<br/>
148
+ Объектный формат (`{ packages: [...] }`) не поддерживается.
149
+
150
+ ## ✅ Тестирование
151
+
152
+ Пакет полностью покрыт тестами:
153
+ - Успешное чтение `package.json`
154
+ - Обработка всех типов ошибок: файл не найден, нет доступа, невалидный JSON
155
+ - Поддержка разных путей
156
+ - Корректная миграция ошибок в `PackageError`
157
+
158
+ Используется Vitest, моки зависимостей, изолированные тесты.
159
+
160
+ ## ⚠️ Ограничения
161
+
162
+ - Работает только в Node.js (не в Duktape).
163
+ - Поддерживает только `import` в `exports`.
164
+ - Поле `workspaces` должно быть массивом строк.
165
+ - Для асинхронных операций используйте `readPackageAsync`.
166
+ - Синхронные операции не рекомендуются в асинхронных средах (используйте `readPackageAsync`).
167
+
168
+ ## 🔄 Использование в `@mirta/workspace`
169
+
170
+ Этот пакет используется в `@mirta/workspace` для:
171
+ - Чтения `package.json` корневого проекта.
172
+ - Проверки поля `workspaces`.
173
+ - Сбора информации о каждом пакете в монорепозитории.
174
+
175
+ Пример:
176
+
177
+ ```ts
178
+ const pkg = await readPackageAsync(`${rootDir}/packages/mirta-basics`)
179
+ ```
180
+ Это обеспечивает единый, надёжный способ доступа к метаданным пакетов.
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Путь внутри поля `exports` (например, `"./dist/index.mjs"`).
3
+ *
4
+ * Может быть строкой, `null` или `undefined`.
5
+ *
6
+ * @since 0.4.0
7
+ *
8
+ **/
9
+ type ExportsPath = string | null | undefined;
10
+ /**
11
+ * Объект с `types` и `default` внутри поля `exports`.
12
+ *
13
+ * Определяет альтернативные пути для условия `import`.
14
+ *
15
+ * @example
16
+ *
17
+ * ```json
18
+ * {
19
+ * "import": {
20
+ * "types": "./dist/index.d.mts",
21
+ * "default": "./dist/index.mjs"
22
+ * }
23
+ * }
24
+ *
25
+ * ```
26
+ * @since 0.4.0
27
+ *
28
+ **/
29
+ interface ExportsObject {
30
+ /** Путь к файлу типов (`.d.mts`). */
31
+ types?: ExportsPath;
32
+ /** Основной путь экспорта. */
33
+ default?: ExportsPath;
34
+ }
35
+ /**
36
+ * Упрощённая форма условного экспорта, поддерживаемая фреймворком Мирта.
37
+ *
38
+ * Поддерживается только условие `import`.
39
+ * Другие условия (`require`, `node`, `browser`) игнорируются.
40
+ *
41
+ * @example
42
+ *
43
+ * ```json
44
+ * {
45
+ * "exports": {
46
+ * ".": {
47
+ * "import": "./dist/index.mjs"
48
+ * }
49
+ * }
50
+ * }
51
+ *
52
+ * ```
53
+ * @example
54
+ *
55
+ * ```json
56
+ * {
57
+ * "exports": {
58
+ * ".": {
59
+ * "import": {
60
+ * "types": "./dist/index.d.mts",
61
+ * "default": "./dist/index.mjs"
62
+ * }
63
+ * }
64
+ * }
65
+ * }
66
+ *
67
+ * ```
68
+ *
69
+ * @since 0.4.0
70
+ *
71
+ **/
72
+ interface ExportsConditional {
73
+ /**
74
+ * Путь или объект экспорта для условной загрузки.
75
+ *
76
+ * @remarks
77
+ * Условие `import` — единственный поддерживаемый вариант в Мирте.
78
+ *
79
+ **/
80
+ import: ExportsPath | ExportsObject;
81
+ }
82
+ /**
83
+ * Любой допустимый тип в записи поля `exports`.
84
+ * Может быть строкой, объектом или условным экспортом.
85
+ *
86
+ * @since 0.4.0
87
+ *
88
+ **/
89
+ type ExportsEntry = ExportsPath | ExportsConditional | ExportsObject;
90
+ /**
91
+ * Упрощённая форма поля `exports` из package.json, поддерживаемая фреймворком Мирта.
92
+ *
93
+ * Поддерживает:
94
+ * - Простые пути: `"import": "./dist/index.mjs"`;
95
+ * - Объекты с `types` и `default`;
96
+ * - Дополнительные точки входа (например, `./setup-global`, `./context`).
97
+ *
98
+ * @example
99
+ *
100
+ * ```json
101
+ * {
102
+ * "exports": {
103
+ * ".": {
104
+ * "import": "./dist/index.mjs"
105
+ * }
106
+ * }
107
+ * }
108
+ * ```
109
+ * @since 0.4.0
110
+ *
111
+ **/
112
+ type PackageExports = ExportsPath | ExportsConditional | Record<string, ExportsEntry>;
113
+ /**
114
+ * Минимальный контракт `package.json`, необходимый для работы фреймворка Мирта.
115
+ *
116
+ * @since 0.4.0
117
+ *
118
+ **/
119
+ interface Package {
120
+ /**
121
+ * Имя пакета (например, `"@mirta/package"`).
122
+ *
123
+ **/
124
+ name?: string;
125
+ /**
126
+ * Семантическая версия пакета (SemVer).
127
+ *
128
+ * Обязательна при публикации в реестр. Рекомендуется указывать
129
+ * даже в приватных пакетах, для отслеживания изменений.
130
+ *
131
+ * Имеет формат `major.minor.patch` (например, `1.2.3`), где каждый
132
+ * сегмент обозначает разные уровни изменений:
133
+ * - `major` — крупные изменения, возможны breaking changes,
134
+ * - `minor` — добавление новых возможностей без нарушения совместимости,
135
+ * - `patch` — исправление ошибок.
136
+ *
137
+ * Версии до `1.0.0` (например, `0.4.0`) считаются экспериментальными:
138
+ * любое обновление может включать breaking changes.
139
+ *
140
+ * @example
141
+ * "0.4.0"
142
+ * "1.0.0-alpha.1"
143
+ *
144
+ **/
145
+ version?: string;
146
+ /**
147
+ * Признак того, что пакет не предназначен для публикации.
148
+ *
149
+ * Если значение `true`, пакет нельзя опубликовать в реестре (например, npm).
150
+ * Используется для защиты от случайной публикации внутренних или служебных пакетов.
151
+ *
152
+ **/
153
+ private?: boolean;
154
+ /**
155
+ * Именованные команды для автоматизации задач (сборка, тесты, форматирование и т.п.).
156
+ *
157
+ **/
158
+ scripts?: Record<string, string>;
159
+ /**
160
+ * Конфигурация экспорта модуля.
161
+ *
162
+ * Поддерживается упрощённый формат с условием `import`.
163
+ *
164
+ **/
165
+ exports?: PackageExports;
166
+ /**
167
+ * Список шаблонов рабочих пространств (workspaces).
168
+ * Используется для определения структуры монорепозитория.
169
+ *
170
+ **/
171
+ workspaces?: string[];
172
+ /**
173
+ * Зависимости, необходимые для работы пакета.
174
+ *
175
+ * Устанавливаются вместе с пакетом при его добавлении в проект.
176
+ *
177
+ * @since 0.4.0
178
+ *
179
+ **/
180
+ dependencies?: Record<string, string>;
181
+ /**
182
+ * Зависимости, необходимые при разработке пакета.
183
+ *
184
+ * Не устанавливаются вместе с пакетом при его добавлении в проект.
185
+ *
186
+ **/
187
+ devDependencies?: Record<string, string>;
188
+ /**
189
+ * Зависимости, которые ожидаются в основном проекте.
190
+ *
191
+ * Не устанавливаются автоматически, но требуются для корректной работы.
192
+ * Позволяют избежать дублирования пакетов.
193
+ *
194
+ **/
195
+ peerDependencies?: Record<string, string>;
196
+ /**
197
+ * Опциональные зависимости, которые устанавливаются, если возможно.
198
+ *
199
+ * Ошибки при их установке игнорируются. Используются, когда:
200
+ * - Зависимость работает только на определённых платформах (например, macOS, Windows);
201
+ * - Пакет может предоставить fallback-реализацию или работать с ограниченной функциональностью.
202
+ *
203
+ **/
204
+ optionalDependencies?: Record<string, string>;
205
+ }
206
+
207
+ /**
208
+ * Синхронно читает и парсит `package.json` по указанному пути.
209
+ *
210
+ * Поддерживается:
211
+ * - Прямой путь к файлу — `'package.json'`, `'packages/core/package.json'`
212
+ * - Путь к корневой директории пакета — `'.'`, `'..'`, `'../../shared'`, `'packages/core'`
213
+ *
214
+ * Не поддерживается:
215
+ * - Передача пути к произвольному файлу — `'src/index.ts'`
216
+ *
217
+ * При ошибках чтения файла или невалидном JSON выбрасывается {@link PackageError}
218
+ * с подробным описанием и контекстом.
219
+ *
220
+ * @param path - Путь к `package.json` или к корневой директории пакета.
221
+ * @returns Объект типа {@link Package}, представляющий минимальный контракт,
222
+ * необходимый для разрешения структуры монорепозитория и сборки проектов.
223
+ * @throws {PackageError} Если файл не найден, нет доступа или JSON повреждён.
224
+ *
225
+ * @since 0.4.0
226
+ *
227
+ **/
228
+ declare function readPackage(path: string): Package;
229
+ /**
230
+ * Асинхронно читает и парсит `package.json` по указанному пути.
231
+ *
232
+ * Поддерживается:
233
+ * - Прямой путь к файлу — `'package.json'`, `'packages/core/package.json'`
234
+ * - Путь к корневой директории пакета — `'.'`, `'..'`, `'../../shared'`, `'packages/core'`
235
+ *
236
+ * Не поддерживается:
237
+ * - Передача пути к произвольному файлу — `'src/index.ts'`
238
+ *
239
+ * При ошибках чтения файла или невалидном JSON выбрасывается {@link PackageError}
240
+ * с подробным описанием и контекстом.
241
+ *
242
+ * @param path - Путь к `package.json` или к корневой директории пакета.
243
+ * @returns Объект типа {@link Package}, представляющий минимальный контракт.
244
+ * @throws {PackageError} Если файл не найден, нет доступа или JSON повреждён.
245
+ *
246
+ * @since 0.4.0
247
+ *
248
+ **/
249
+ declare function readPackageAsync(path: string): Promise<Package>;
250
+
251
+ /**
252
+ * Парсит строку JSON и возвращает объект типа {@link Package}.
253
+ *
254
+ * Не выполняет чтение из файловой системы.
255
+ *
256
+ * @param content - Строка в формате JSON
257
+ * @returns Объект типа {@link Package}
258
+ * @throws {SyntaxError} Если JSON некорректен.
259
+ * Сообщение содержит детали: позицию, причину.
260
+ *
261
+ * @throws {PackageError} Если JSON не является объектом.
262
+ *
263
+ * @example
264
+ *
265
+ * ```ts
266
+ * parsePackageJson('{ "name": "my-package" }')
267
+ *
268
+ * ```
269
+ * @since 0.4.0
270
+ *
271
+ **/
272
+ declare function parsePackageJson(content: string): Package;
273
+
274
+ /**
275
+ * Резолвит путь к `package.json` на основе входного пути.
276
+ *
277
+ * Правила:
278
+ * - Если `path` заканчивается на `package.json` → возвращается как есть
279
+ * - Если `path` указывает на директорию (включая `.` и `..`) → возвращается `path/package.json`
280
+ * - Если `path` указывает на файл с расширением (например, `src/index.ts`), но не на `package.json` → ошибка
281
+ *
282
+ * Не выполняет проверку существования файла.
283
+ *
284
+ * @param path - Путь к `package.json` или к директории пакета.
285
+ * Может быть абсолютным или относительным.
286
+ * @returns Абсолютный или относительный путь к `package.json`
287
+ * @throws {PackageError} С кодом `invalidPath`, если путь указывает на файл с расширением,
288
+ * но не является `package.json`.
289
+ *
290
+ * @example
291
+ *
292
+ * ```ts
293
+ * resolvePackagePath('.') // → './package.json'
294
+ * resolvePackagePath('..') // → '../package.json'
295
+ * resolvePackagePath('packages/core') // → 'packages/core/package.json'
296
+ * resolvePackagePath('package.json') // → 'package.json'
297
+ * resolvePackagePath('src/index.ts') // → ошибка
298
+ *
299
+ * ```
300
+ *
301
+ * @since 0.4.0
302
+ *
303
+ **/
304
+ declare function resolvePackagePath(path: string): string;
305
+
306
+ /**
307
+ * Преобразует путь из формата Windows в формат POSIX.
308
+ *
309
+ * Заменяет все обратные слеши (`\`) на прямые (`/`), что необходимо для кросс-платформенной
310
+ * совместимости, особенно при сравнении путей или работе с инструментами сборки,
311
+ * которые ожидают стандартизированный формат пути.
312
+ *
313
+ * @param path - Входной путь, который может содержать разделители Windows (`\`).
314
+ * @returns Путь, в котором все разделители заменены на `/`.
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * toPosix('C:\\projects\\app\\src\\index.ts')
319
+ * // Результат: 'C:/projects/app/src/index.ts'
320
+ * ```
321
+ *
322
+ * @remarks
323
+ * Функция использует {@link nodePath.win32.sep} и {@link nodePath.posix.sep} для получения
324
+ * платформенно-зависимых разделителей, что делает её надёжной независимо от ОС,
325
+ * на которой выполняется код.
326
+ *
327
+ * @since 0.4.0
328
+ *
329
+ **/
330
+ declare function toPosix(path: string): string;
331
+ declare function toPosix(path: string | undefined): string | undefined;
332
+
333
+ /**
334
+ * Специализированный класс для обработки ошибок, связанных с чтением и парсингом файла `package.json`.
335
+ *
336
+ * Предоставляет структурированные и типизированные ошибки с использованием кодов, что упрощает
337
+ * программную обработку исключений в инструментах, работающих с пакетами.
338
+ *
339
+ * @example
340
+ * ```ts
341
+ * throw PackageError.get('notFound', '/path/to/package.json');
342
+ * ```
343
+ * @since 0.4.0
344
+ *
345
+ **/
346
+ declare class PackageError extends Error {
347
+ /**
348
+ * Код ошибки для программной идентификации.
349
+ *
350
+ * Позволяет точно определить причину ошибки в обработчиках `try/catch`.
351
+ *
352
+ **/
353
+ readonly code: string;
354
+ /**
355
+ * Приватный конструктор, используемый только внутри
356
+ * класса для создания экземпляров ошибки.
357
+ *
358
+ * @param message - Полное сообщение об ошибке.
359
+ * @param code - Код ошибки для идентификации.
360
+ * @param scope - Пространство имён или модуль, в котором возникла ошибка.
361
+ * По умолчанию — {@link THIS_PACKAGE_NAME}.
362
+ *
363
+ **/
364
+ private constructor();
365
+ /** Карта кодов ошибок с соответствующими сообщениями. */
366
+ private static readonly codeMappings;
367
+ /**
368
+ * Фабричный метод для создания экземпляра ошибки по её коду.
369
+ *
370
+ * Автоматически подставляет сообщение из `codeMappings` и формирует ошибку с заданными параметрами.
371
+ *
372
+ * @template T - Ограниченный ключами `codeMappings` тип, гарантирующий корректность кода.
373
+ * @param code - Код ошибки (например, `'notFound'`, `'invalidJson'`).
374
+ * @param args - Аргументы, соответствующие параметрам функции сообщения из `codeMappings`.
375
+ * @returns Новый экземпляр {@link PackageError} с шаблонным сообщением.
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * const error = PackageError.get('notFound', '/src/package.json');
380
+ * ```
381
+ */
382
+ static get<T extends keyof typeof PackageError['codeMappings']>(code: T, ...args: Parameters<typeof PackageError['codeMappings'][T]>): PackageError;
383
+ /**
384
+ * Фабричный метод, аналогичный `get`, но с возможностью указать
385
+ * пользовательское пространство имён (scope).
386
+ *
387
+ * Полезно при использовании в других модулях, где нужно указать
388
+ * иной контекст ошибки.
389
+ *
390
+ * @template TKey - Тип кода ошибки, аналогично `get`.
391
+ *
392
+ * @param scope - Пространство имён ошибки (например, `'@mirta/cli'`).
393
+ * @param code - Код ошибки.
394
+ * @param args - Аргументы для формирования сообщения.
395
+ *
396
+ * @returns Новый экземпляр {@link PackageError} с пользовательским
397
+ * префиксом и шаблонным сообщением.
398
+ *
399
+ * @example
400
+ *
401
+ * ```ts
402
+ * const error = PackageError.getScoped('@mirta/cli', 'invalidPath', '/invalid/path');
403
+ * ```
404
+ **/
405
+ static getScoped<TKey extends keyof typeof PackageError['codeMappings']>(scope: string, code: TKey, ...args: Parameters<typeof PackageError['codeMappings'][TKey]>): PackageError;
406
+ }
407
+
408
+ export { PackageError, parsePackageJson, readPackage, readPackageAsync, resolvePackagePath, toPosix };
409
+ export type { ExportsConditional, ExportsEntry, ExportsObject, ExportsPath, Package, PackageExports };
package/dist/index.mjs ADDED
@@ -0,0 +1,341 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import nodePath, { basename, posix } from 'node:path';
4
+
5
+ /**
6
+ * Имя текущего пакета в формате, используемом в npm-реестре.
7
+ *
8
+ * Используется для логирования, формирования сообщений об ошибках,
9
+ * а также в диагностических и пользовательских интерфейсах,
10
+ * чтобы явно указывать источник операций.
11
+ *
12
+ * Централизованное определение позволяет избежать жёсткой привязки
13
+ * к строковому значению в разных частях кода и упрощает поддержку
14
+ * при возможном переименовании пакета.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * console.log(`[${THIS_PACKAGE_NAME}] Запуск сборки...`);
19
+ * ```
20
+ *
21
+ * @since 0.4.0
22
+ *
23
+ **/
24
+ const THIS_PACKAGE_NAME = '@mirta/package';
25
+
26
+ /**
27
+ * Специализированный класс для обработки ошибок, связанных с чтением и парсингом файла `package.json`.
28
+ *
29
+ * Предоставляет структурированные и типизированные ошибки с использованием кодов, что упрощает
30
+ * программную обработку исключений в инструментах, работающих с пакетами.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * throw PackageError.get('notFound', '/path/to/package.json');
35
+ * ```
36
+ * @since 0.4.0
37
+ *
38
+ **/
39
+ class PackageError extends Error {
40
+ /**
41
+ * Код ошибки для программной идентификации.
42
+ *
43
+ * Позволяет точно определить причину ошибки в обработчиках `try/catch`.
44
+ *
45
+ **/
46
+ code;
47
+ /**
48
+ * Приватный конструктор, используемый только внутри
49
+ * класса для создания экземпляров ошибки.
50
+ *
51
+ * @param message - Полное сообщение об ошибке.
52
+ * @param code - Код ошибки для идентификации.
53
+ * @param scope - Пространство имён или модуль, в котором возникла ошибка.
54
+ * По умолчанию — {@link THIS_PACKAGE_NAME}.
55
+ *
56
+ **/
57
+ constructor(message, code, scope) {
58
+ super(`[${scope ?? THIS_PACKAGE_NAME}] ${message}`);
59
+ this.name = 'PackageError';
60
+ this.code = code;
61
+ // Захватываем стек вызовов, исключая фабричный метод `get`,
62
+ // чтобы улучшить читаемость трассировки.
63
+ //
64
+ if ('captureStackTrace' in Error)
65
+ Error.captureStackTrace(this, scope
66
+ // eslint-disable-next-line @typescript-eslint/unbound-method
67
+ ? PackageError.getScoped
68
+ // eslint-disable-next-line @typescript-eslint/unbound-method
69
+ : PackageError.get);
70
+ }
71
+ /** Карта кодов ошибок с соответствующими сообщениями. */
72
+ static codeMappings = {
73
+ /**
74
+ * Ошибка, возникающая, когда файл `package.json`
75
+ * не найден по указанному пути.
76
+ *
77
+ * @param filePath - Абсолютный или относительный путь к отсутствующему файлу.
78
+ *
79
+ **/
80
+ notFound: (filePath) => `File not found: "${filePath}"`,
81
+ /**
82
+ * Ошибка, возникающая при отсутствии прав на чтение файла.
83
+ *
84
+ * @param filePath - Путь к файлу, доступ к которому запрещён.
85
+ *
86
+ **/
87
+ accessDenied: (filePath) => `Access denied to file "${filePath}"`,
88
+ /**
89
+ * Ошибка, возникающая при передаче невалидного пути.
90
+ *
91
+ * @param path - Переданный путь, не соответствующий ожидаемому формату.
92
+ *
93
+ **/
94
+ invalidPath: (path) => `Invalid path "${path}": expected a path to "package.json" or a package directory`,
95
+ /**
96
+ * Ошибка парсинга JSON в файле `package.json`.
97
+ *
98
+ * @param filePath - Путь к файлу с некорректным JSON.
99
+ * @param message - Сообщение об ошибке от парсера (например, `Unexpected token }`).
100
+ *
101
+ **/
102
+ invalidJson: (filePath, message) => `Invalid JSON in file "${filePath}": ${message}`,
103
+ /**
104
+ * Ошибка, возникающая, если корневой элемент JSON не является объектом.
105
+ * Согласно спецификации, `package.json` должен начинаться с `{}`.
106
+ *
107
+ **/
108
+ invalidJsonRoot: () => 'Invalid JSON: root must be an object, not an array or primitive value',
109
+ /**
110
+ * Общая ошибка чтения файла с неуточнённой причиной.
111
+ * @param filePath - Путь к файлу.
112
+ * @param message - Возможное описание ошибки от файловой системы.
113
+ *
114
+ **/
115
+ failedToRead: (filePath, message) => `Failed to read "${filePath}": ${message ?? 'unknown reason'}`,
116
+ /**
117
+ * Ошибка, возникающая, если в `package.json` отсутствует поле `version`.
118
+ *
119
+ **/
120
+ noVersionField: () => 'No version field found in package.json',
121
+ };
122
+ /**
123
+ * Фабричный метод для создания экземпляра ошибки по её коду.
124
+ *
125
+ * Автоматически подставляет сообщение из `codeMappings` и формирует ошибку с заданными параметрами.
126
+ *
127
+ * @template T - Ограниченный ключами `codeMappings` тип, гарантирующий корректность кода.
128
+ * @param code - Код ошибки (например, `'notFound'`, `'invalidJson'`).
129
+ * @param args - Аргументы, соответствующие параметрам функции сообщения из `codeMappings`.
130
+ * @returns Новый экземпляр {@link PackageError} с шаблонным сообщением.
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * const error = PackageError.get('notFound', '/src/package.json');
135
+ * ```
136
+ */
137
+ static get(code, ...args) {
138
+ const messageFn = this.codeMappings[code];
139
+ const message = messageFn(...args);
140
+ return new PackageError(message, code);
141
+ }
142
+ /**
143
+ * Фабричный метод, аналогичный `get`, но с возможностью указать
144
+ * пользовательское пространство имён (scope).
145
+ *
146
+ * Полезно при использовании в других модулях, где нужно указать
147
+ * иной контекст ошибки.
148
+ *
149
+ * @template TKey - Тип кода ошибки, аналогично `get`.
150
+ *
151
+ * @param scope - Пространство имён ошибки (например, `'@mirta/cli'`).
152
+ * @param code - Код ошибки.
153
+ * @param args - Аргументы для формирования сообщения.
154
+ *
155
+ * @returns Новый экземпляр {@link PackageError} с пользовательским
156
+ * префиксом и шаблонным сообщением.
157
+ *
158
+ * @example
159
+ *
160
+ * ```ts
161
+ * const error = PackageError.getScoped('@mirta/cli', 'invalidPath', '/invalid/path');
162
+ * ```
163
+ **/
164
+ static getScoped(scope, code, ...args) {
165
+ const messageFn = this.codeMappings[code];
166
+ const message = messageFn(...args);
167
+ return new PackageError(message, code, scope);
168
+ }
169
+ }
170
+
171
+ function toPosix(path) {
172
+ if (path === '' || path === undefined)
173
+ return path;
174
+ return path.replaceAll(nodePath.win32.sep, nodePath.posix.sep);
175
+ }
176
+
177
+ /**
178
+ * Резолвит путь к `package.json` на основе входного пути.
179
+ *
180
+ * Правила:
181
+ * - Если `path` заканчивается на `package.json` → возвращается как есть
182
+ * - Если `path` указывает на директорию (включая `.` и `..`) → возвращается `path/package.json`
183
+ * - Если `path` указывает на файл с расширением (например, `src/index.ts`), но не на `package.json` → ошибка
184
+ *
185
+ * Не выполняет проверку существования файла.
186
+ *
187
+ * @param path - Путь к `package.json` или к директории пакета.
188
+ * Может быть абсолютным или относительным.
189
+ * @returns Абсолютный или относительный путь к `package.json`
190
+ * @throws {PackageError} С кодом `invalidPath`, если путь указывает на файл с расширением,
191
+ * но не является `package.json`.
192
+ *
193
+ * @example
194
+ *
195
+ * ```ts
196
+ * resolvePackagePath('.') // → './package.json'
197
+ * resolvePackagePath('..') // → '../package.json'
198
+ * resolvePackagePath('packages/core') // → 'packages/core/package.json'
199
+ * resolvePackagePath('package.json') // → 'package.json'
200
+ * resolvePackagePath('src/index.ts') // → ошибка
201
+ *
202
+ * ```
203
+ *
204
+ * @since 0.4.0
205
+ *
206
+ **/
207
+ function resolvePackagePath(path) {
208
+ const normalizedPath = toPosix(path);
209
+ if (normalizedPath.endsWith('package.json'))
210
+ return normalizedPath;
211
+ const base = basename(normalizedPath);
212
+ // Проверяем последний фрагмент пути, не допуская файлы.
213
+ if (base !== '.' && base !== '..' && base.includes('.'))
214
+ throw PackageError.get('invalidPath', normalizedPath);
215
+ return posix.join(normalizedPath, 'package.json');
216
+ }
217
+
218
+ /**
219
+ * Парсит строку JSON и возвращает объект типа {@link Package}.
220
+ *
221
+ * Не выполняет чтение из файловой системы.
222
+ *
223
+ * @param content - Строка в формате JSON
224
+ * @returns Объект типа {@link Package}
225
+ * @throws {SyntaxError} Если JSON некорректен.
226
+ * Сообщение содержит детали: позицию, причину.
227
+ *
228
+ * @throws {PackageError} Если JSON не является объектом.
229
+ *
230
+ * @example
231
+ *
232
+ * ```ts
233
+ * parsePackageJson('{ "name": "my-package" }')
234
+ *
235
+ * ```
236
+ * @since 0.4.0
237
+ *
238
+ **/
239
+ function parsePackageJson(content) {
240
+ const parsed = JSON.parse(content);
241
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
242
+ throw PackageError.get('invalidJsonRoot');
243
+ return parsed;
244
+ }
245
+
246
+ /**
247
+ * Обрабатывает ошибку, возникшую при чтении или парсинге файла `package.json`,
248
+ * и преобразует её в соответствующую ошибку типа {@link PackageError}.
249
+ *
250
+ * @param e - Неизвестное исключение, которое необходимо обработать.
251
+ * @param path - Путь к файлу `package.json`, на котором произошла ошибка.
252
+ * @returns Экземпляр {@link PackageError}, соответствующий типу исключения.
253
+ *
254
+ * @since 0.4.0
255
+ *
256
+ **/
257
+ function handleError(e, path) {
258
+ if (e instanceof PackageError)
259
+ return e;
260
+ if (e instanceof SyntaxError)
261
+ return PackageError.get('invalidJson', path, e.message);
262
+ if (e && typeof e === 'object' && 'code' in e) {
263
+ const code = e.code;
264
+ switch (code) {
265
+ case 'ENOENT':
266
+ return PackageError.get('notFound', path);
267
+ case 'EACCES':
268
+ case 'EPERM':
269
+ return PackageError.get('accessDenied', path);
270
+ }
271
+ }
272
+ const message = e instanceof Error
273
+ ? e.message
274
+ : String(e);
275
+ return PackageError.get('failedToRead', path, message);
276
+ }
277
+ /**
278
+ * Синхронно читает и парсит `package.json` по указанному пути.
279
+ *
280
+ * Поддерживается:
281
+ * - Прямой путь к файлу — `'package.json'`, `'packages/core/package.json'`
282
+ * - Путь к корневой директории пакета — `'.'`, `'..'`, `'../../shared'`, `'packages/core'`
283
+ *
284
+ * Не поддерживается:
285
+ * - Передача пути к произвольному файлу — `'src/index.ts'`
286
+ *
287
+ * При ошибках чтения файла или невалидном JSON выбрасывается {@link PackageError}
288
+ * с подробным описанием и контекстом.
289
+ *
290
+ * @param path - Путь к `package.json` или к корневой директории пакета.
291
+ * @returns Объект типа {@link Package}, представляющий минимальный контракт,
292
+ * необходимый для разрешения структуры монорепозитория и сборки проектов.
293
+ * @throws {PackageError} Если файл не найден, нет доступа или JSON повреждён.
294
+ *
295
+ * @since 0.4.0
296
+ *
297
+ **/
298
+ function readPackage(path) {
299
+ const resolvedPath = resolvePackagePath(path);
300
+ let content;
301
+ try {
302
+ content = readFileSync(resolvedPath, 'utf-8');
303
+ return parsePackageJson(content);
304
+ }
305
+ catch (e) {
306
+ throw handleError(e, resolvedPath);
307
+ }
308
+ }
309
+ /**
310
+ * Асинхронно читает и парсит `package.json` по указанному пути.
311
+ *
312
+ * Поддерживается:
313
+ * - Прямой путь к файлу — `'package.json'`, `'packages/core/package.json'`
314
+ * - Путь к корневой директории пакета — `'.'`, `'..'`, `'../../shared'`, `'packages/core'`
315
+ *
316
+ * Не поддерживается:
317
+ * - Передача пути к произвольному файлу — `'src/index.ts'`
318
+ *
319
+ * При ошибках чтения файла или невалидном JSON выбрасывается {@link PackageError}
320
+ * с подробным описанием и контекстом.
321
+ *
322
+ * @param path - Путь к `package.json` или к корневой директории пакета.
323
+ * @returns Объект типа {@link Package}, представляющий минимальный контракт.
324
+ * @throws {PackageError} Если файл не найден, нет доступа или JSON повреждён.
325
+ *
326
+ * @since 0.4.0
327
+ *
328
+ **/
329
+ async function readPackageAsync(path) {
330
+ const resolvedPath = resolvePackagePath(path);
331
+ let content;
332
+ try {
333
+ content = await readFile(resolvedPath, 'utf-8');
334
+ return parsePackageJson(content);
335
+ }
336
+ catch (e) {
337
+ throw handleError(e, resolvedPath);
338
+ }
339
+ }
340
+
341
+ export { PackageError, parsePackageJson, readPackage, readPackageAsync, resolvePackagePath, toPosix };
package/package.json CHANGED
@@ -1,10 +1,48 @@
1
1
  {
2
2
  "name": "@mirta/package",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @mirta/package",
3
+ "version": "0.4.0",
4
+ "sideEffects": false,
5
+ "description": "Internal type-safe reader & parser for package.json, used by Mirta Framework",
5
6
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
10
- }
7
+ "mirta",
8
+ "package.json",
9
+ "read",
10
+ "parse",
11
+ "exports",
12
+ "monorepo",
13
+ "typescript",
14
+ "config",
15
+ "utility"
16
+ ],
17
+ "license": "Unlicense",
18
+ "homepage": "https://github.com/wb-mirta/core#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/wb-mirta/core/issues"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/wb-mirta/core.git",
25
+ "directory": "packages/mirta-package"
26
+ },
27
+ "type": "module",
28
+ "types": "./dist/index.d.mts",
29
+ "files": [
30
+ "dist",
31
+ "LICENSE",
32
+ "README.md"
33
+ ],
34
+ "exports": {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/index.d.mts",
38
+ "default": "./dist/index.mjs"
39
+ }
40
+ }
41
+ },
42
+ "imports": {
43
+ "#src/*": "./src/*.js"
44
+ },
45
+ "engines": {
46
+ "node": ">=24.12.0"
47
+ }
48
+ }