@open-mercato/cli 0.6.6-develop.5654.1.ca21e35f26 → 0.6.6-develop.5675.1.d585628349
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/dist/agentic/shared/AGENTS.md.template +1 -1
- package/dist/agentic/shared/ai/skills/om-code-review/SKILL.md +9 -45
- package/dist/agentic/shared/ai/skills/om-code-review/references/review-checklist.md +1 -1
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +4 -14
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +10 -6
- package/dist/lib/module-install-args.js +9 -1
- package/dist/lib/module-install-args.js.map +2 -2
- package/dist/lib/module-install.js +22 -11
- package/dist/lib/module-install.js.map +2 -2
- package/dist/lib/module-package.js +2 -2
- package/dist/lib/module-package.js.map +2 -2
- package/dist/mercato.js +8 -8
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/lib/__tests__/module-install-args.test.ts +23 -0
- package/src/lib/__tests__/module-install.test.ts +66 -1
- package/src/lib/__tests__/module-package.test.ts +27 -0
- package/src/lib/module-install-args.ts +12 -1
- package/src/lib/module-install.ts +25 -9
- package/src/lib/module-package.ts +2 -2
- package/src/mercato.ts +8 -8
|
@@ -147,7 +147,7 @@ When the user asks to **create a new application** or a **new module**, do not i
|
|
|
147
147
|
| **Backend admin pages** | Auto-discovered files under `src/modules/<id>/backend/**`, paired `page.meta.ts` with `requireAuth` + `requireFeatures` + `pageGroup`/`pageGroupKey`/`pageOrder` | `.ai/skills/om-backend-ui-design/SKILL.md`, `.ai/skills/om-module-scaffold/references/navigation-patterns.md`; <https://docs.open-mercato.dev/framework/modules/routes-and-pages> |
|
|
148
148
|
| **Frontend public pages** | Auto-discovered files under `src/modules/<id>/frontend/**`. Customer portal pages live under `frontend/[orgSlug]/portal/<path>/page.tsx` with `requireCustomerAuth` / `requireCustomerFeatures` in `page.meta.ts` | `.ai/guides/ui.md` → Portal Extension; <https://docs.open-mercato.dev/framework/modules/routes-and-pages> |
|
|
149
149
|
| **API routes** | Files under `src/modules/<id>/api/**/route.ts` exporting handlers + `metadata` (per-method `requireAuth` / `requireFeatures`) + `openApi`. NEVER write a top-level `export const requireAuth` — the registry no longer recognises it | `.ai/guides/core.md` → API Routes; <https://docs.open-mercato.dev/framework/api/api-development-guide> |
|
|
150
|
-
| **CRUD APIs (factory)** | `makeCrudRoute({
|
|
150
|
+
| **CRUD APIs (factory)** | `makeCrudRoute({ metadata, orm, list, create, update, del, indexer })` from `@open-mercato/shared/lib/crud/factory` (`orm` is required; `list`/`create`/`update`/`del` are the per-operation configs). Always set `indexer` so query-index coverage stays correct. Custom (non-`makeCrudRoute`) write routes MUST call `validateCrudMutationGuard` before the mutation and `runCrudMutationGuardAfterSuccess` after success | `.ai/skills/om-module-scaffold/SKILL.md` → Create API Routes; <https://docs.open-mercato.dev/framework/api/crud-factory> |
|
|
151
151
|
| **CRUD forms in admin** | `<CrudForm entityId apiPath mode fields />` from `@open-mercato/ui/backend/CrudForm`; helpers `createCrud` / `updateCrud` / `deleteCrud` from `@open-mercato/ui/backend/utils/crud`; `createCrudFormError` from `@open-mercato/ui/backend/utils/serverErrors`. Never raw `<form>`, never raw `fetch` | `.ai/skills/om-backend-ui-design/SKILL.md`; <https://docs.open-mercato.dev/framework/admin-ui/crud-form> |
|
|
152
152
|
| **DataTables in admin** | `<DataTable entityId apiPath title columns />` from `@open-mercato/ui/backend/DataTable`. Keep `entityId` and `extensionTableId` stable so widget injection (columns, row actions, bulk actions, filters, toolbar) keeps working | `.ai/skills/om-backend-ui-design/SKILL.md`; <https://docs.open-mercato.dev/framework/admin-ui/data-grids> |
|
|
153
153
|
| **Authorization (RBAC)** | Declare features in `<module>/acl.ts`, grant them in `<module>/setup.ts` `defaultRoleFeatures`, gate pages and routes with `requireFeatures` in `metadata` / `page.meta.ts`. NEVER use `requireRoles` (role names mutate). Run `yarn mercato auth sync-role-acls` after adding new features | `.ai/guides/core.md` → Access Control; <https://docs.open-mercato.dev/framework/rbac/overview> |
|
|
@@ -81,51 +81,15 @@ Omit empty severity sections.
|
|
|
81
81
|
|
|
82
82
|
## Quick Rule Reference
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- **
|
|
87
|
-
- **
|
|
88
|
-
- **
|
|
89
|
-
- **
|
|
90
|
-
- **
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- **Validate all inputs with zod** in `data/validators.ts`
|
|
95
|
-
- **Use `findWithDecryption`** instead of raw `em.find`/`em.findOne`
|
|
96
|
-
- **Hash passwords with bcryptjs (cost >= 10)** — never log credentials
|
|
97
|
-
- **Every endpoint MUST declare auth guards** (`requireAuth`, `requireRoles`, `requireFeatures`)
|
|
98
|
-
|
|
99
|
-
### Data Integrity
|
|
100
|
-
|
|
101
|
-
- **Migration files and snapshots must match entity intent** — prefer `yarn db:generate`; scoped manual SQL is allowed only to avoid unrelated generated churn and must include `.snapshot-open-mercato.json`
|
|
102
|
-
- **Validate migration scope** — autogenerated doesn't mean correct
|
|
103
|
-
- **Workers/subscribers MUST be idempotent**
|
|
104
|
-
- **Commands MUST be undoable** — include before/after snapshots
|
|
105
|
-
|
|
106
|
-
### Naming
|
|
107
|
-
|
|
108
|
-
- Modules: **plural, snake_case** (folders and `id`)
|
|
109
|
-
- JS/TS identifiers: **camelCase**
|
|
110
|
-
- Database: **snake_case**, table names plural
|
|
111
|
-
- Standard columns: `id`, `created_at`, `updated_at`, `deleted_at`, `is_active`, `organization_id`
|
|
112
|
-
|
|
113
|
-
### UI & HTTP
|
|
114
|
-
|
|
115
|
-
- Forms: `CrudForm` — never custom
|
|
116
|
-
- Tables: `DataTable` — never manual markup
|
|
117
|
-
- Notifications: `flash()` — never `alert()` or custom toast
|
|
118
|
-
- API calls: `apiCall`/`apiCallOrThrow` — never raw `fetch`
|
|
119
|
-
- Dialogs: `Cmd/Ctrl+Enter` (submit), `Escape` (cancel)
|
|
120
|
-
- `pageSize` MUST be <= 100
|
|
121
|
-
|
|
122
|
-
### Code Quality
|
|
123
|
-
|
|
124
|
-
- No `any` types — use zod + `z.infer`
|
|
125
|
-
- No empty `catch` blocks
|
|
126
|
-
- No one-letter variable names
|
|
127
|
-
- Boolean parsing: use `parseBooleanToken`/`parseBooleanWithDefault`
|
|
128
|
-
- Don't add docstrings/comments to code you didn't change
|
|
84
|
+
`AGENTS.md` is the single source of truth for these rules — read it there instead of relying on a copy, so this skill never drifts from the canon. Map the dimension you are reviewing to the owning section:
|
|
85
|
+
|
|
86
|
+
- **Architecture** (FK-only cross-module links, `organization_id` scoping, DI/Awilix, events for side effects, extension entities) → `AGENTS.md` → Architecture Rules + Mandatory Module Mechanisms
|
|
87
|
+
- **Security** (zod validation, `findWithDecryption` over raw `em.find`/`em.findOne`, bcryptjs ≥ 10, never log credentials) → `AGENTS.md` → Data & Security
|
|
88
|
+
- **Authorization (RBAC)** — gate pages and routes with `requireFeatures`; **NEVER `requireRoles`** (role names mutate and can be spoofed) → `AGENTS.md` → Data & Security (RBAC) + Access Control
|
|
89
|
+
- **Data Integrity** (migration files + snapshots match intent, idempotent workers/subscribers, undoable commands) → `AGENTS.md` → CRITICAL Rules + Data & Security
|
|
90
|
+
- **Naming & standard columns** → `AGENTS.md` → Naming Conventions / Conventions
|
|
91
|
+
- **UI & HTTP** (`CrudForm`, `DataTable`, `flash()`, `apiCall` over raw `fetch`, dialog `Cmd/Ctrl+Enter`/`Escape`, `pageSize` ≤ 100) → `AGENTS.md` → UI & HTTP + Mandatory Module Mechanisms
|
|
92
|
+
- **Code Quality** (no `any`, no empty `catch`, no one-letter names, `parseBooleanToken`/`parseBooleanWithDefault`, don't comment code you didn't change) → `AGENTS.md` → Code Quality
|
|
129
93
|
|
|
130
94
|
## Review Heuristics
|
|
131
95
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
- [ ] All inputs validated with zod in `data/validators.ts`
|
|
14
14
|
- [ ] No `any` types
|
|
15
|
-
- [ ] Auth guards on all endpoints (`requireAuth
|
|
15
|
+
- [ ] Auth guards on all endpoints (`requireAuth` + `requireFeatures`; never `requireRoles` — role names mutate)
|
|
16
16
|
- [ ] Passwords hashed with bcryptjs (cost >= 10)
|
|
17
17
|
- [ ] No credentials logged or in error messages
|
|
18
18
|
- [ ] `findWithDecryption` used instead of raw `em.find`/`em.findOne`
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Naming Conventions Quick Reference
|
|
2
2
|
|
|
3
|
+
> **Source of truth:** `AGENTS.md` (Naming Conventions / Conventions, Architecture Rules, Multi-tenant scoping) owns these rules. This file is an example-oriented cheat sheet for scaffolding — when it disagrees with `AGENTS.md`, `AGENTS.md` wins.
|
|
4
|
+
|
|
3
5
|
## Module & Files
|
|
4
6
|
|
|
5
7
|
| Element | Convention | Example |
|
|
@@ -25,17 +27,7 @@
|
|
|
25
27
|
|
|
26
28
|
## Standard Entity Columns
|
|
27
29
|
|
|
28
|
-
Every tenant-scoped entity MUST
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
id: string // UUID v4 primary key
|
|
32
|
-
organization_id: string // Tenant organization (indexed)
|
|
33
|
-
tenant_id: string // Tenant ID (indexed)
|
|
34
|
-
is_active: boolean // Soft active flag (default: true)
|
|
35
|
-
created_at: Date // Creation timestamp
|
|
36
|
-
updated_at: Date // Last update timestamp (auto-updated)
|
|
37
|
-
deleted_at: Date | null // Soft delete timestamp
|
|
38
|
-
```
|
|
30
|
+
Every tenant-scoped entity MUST carry the standard columns (`id`, `organization_id`, `tenant_id`, `is_active`, `created_at`, `updated_at`, `deleted_at`) with `organization_id`/`tenant_id` indexed. See `AGENTS.md` → Conventions / Multi-tenant scoping for the authoritative list and types.
|
|
39
31
|
|
|
40
32
|
## API Routes
|
|
41
33
|
|
|
@@ -55,6 +47,4 @@ All HTTP methods live in a **single** `api/<entities>/route.ts` that exports nam
|
|
|
55
47
|
|
|
56
48
|
## Cross-Module References
|
|
57
49
|
|
|
58
|
-
-
|
|
59
|
-
- Never use `@ManyToOne` / `@OneToMany` decorators across modules
|
|
60
|
-
- Fetch related data via separate API calls or enrichers
|
|
50
|
+
Store cross-module links as `uuid` FK fields (`customer_id`, `order_id`) and fetch related data via separate API calls or enrichers — never `@ManyToOne` / `@OneToMany` decorators across modules. See `AGENTS.md` → Architecture Rules for the authoritative rule.
|
|
@@ -130,7 +130,7 @@ When in doubt about whether an action mutates state, treat it as mutating and as
|
|
|
130
130
|
|
|
131
131
|
2. **Do pages export `metadata` with `requireAuth`?**
|
|
132
132
|
```typescript
|
|
133
|
-
export const metadata = { requireAuth: true,
|
|
133
|
+
export const metadata = { requireAuth: true, requireFeatures: ['<module_id>.view'] }
|
|
134
134
|
```
|
|
135
135
|
Proposed fix: Add metadata export.
|
|
136
136
|
|
|
@@ -209,12 +209,16 @@ When in doubt about whether an action mutates state, treat it as mutating and as
|
|
|
209
209
|
**Checklist**:
|
|
210
210
|
|
|
211
211
|
1. **Is the file in the correct path?**
|
|
212
|
-
`src/modules/<module_id>/api/<
|
|
213
|
-
Method folders: `get/`, `post/`, `put/`, `delete/`
|
|
212
|
+
`src/modules/<module_id>/api/<resource>/route.ts` — all HTTP methods live in a single `route.ts`. Use path-based folders (`<resource>/`, `<resource>/[id]/`), never per-method `get/`/`post/`/`put/`/`delete/` folders.
|
|
214
213
|
|
|
215
|
-
2. **Does it export
|
|
214
|
+
2. **Does it export per-method handlers plus `metadata`?**
|
|
216
215
|
```typescript
|
|
217
|
-
export
|
|
216
|
+
export const metadata = {
|
|
217
|
+
GET: { requireAuth: true, requireFeatures: ['<module_id>.view'] },
|
|
218
|
+
POST: { requireAuth: true, requireFeatures: ['<module_id>.manage'] },
|
|
219
|
+
}
|
|
220
|
+
export async function GET(req: Request) { /* ... */ }
|
|
221
|
+
export async function POST(req: Request) { /* ... */ }
|
|
218
222
|
```
|
|
219
223
|
|
|
220
224
|
3. **Does it export `openApi`?**
|
|
@@ -290,7 +294,7 @@ export const metadata = { icon: <Trophy className="size-4" /> }
|
|
|
290
294
|
1. **Check browser network tab** — look for the POST/PUT request and response
|
|
291
295
|
2. **Is the zod schema matching the form fields?** Mismatched field names cause silent failures
|
|
292
296
|
3. **Are required fields filled?** Check form validation
|
|
293
|
-
4. **Does the API route handle the HTTP method?** Check `api
|
|
297
|
+
4. **Does the API route handle the HTTP method?** Check `api/<resource>/route.ts` exports a `POST`/`PUT` handler (and lists it in `metadata`)
|
|
294
298
|
|
|
295
299
|
---
|
|
296
300
|
|
|
@@ -2,6 +2,7 @@ function parseModuleInstallArgs(args) {
|
|
|
2
2
|
let packageSpec = null;
|
|
3
3
|
let eject = false;
|
|
4
4
|
let moduleId = null;
|
|
5
|
+
let allowThirdParty = false;
|
|
5
6
|
for (let index = 0; index < args.length; index += 1) {
|
|
6
7
|
const arg = args[index];
|
|
7
8
|
if (!arg) continue;
|
|
@@ -12,6 +13,13 @@ function parseModuleInstallArgs(args) {
|
|
|
12
13
|
if (arg.startsWith("--eject=")) {
|
|
13
14
|
throw new Error("--eject does not accept a value");
|
|
14
15
|
}
|
|
16
|
+
if (arg === "--allow-third-party") {
|
|
17
|
+
allowThirdParty = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (arg.startsWith("--allow-third-party=")) {
|
|
21
|
+
throw new Error("--allow-third-party does not accept a value");
|
|
22
|
+
}
|
|
15
23
|
if (arg === "--module") {
|
|
16
24
|
const next = args[index + 1];
|
|
17
25
|
if (next && !next.startsWith("-")) {
|
|
@@ -32,7 +40,7 @@ function parseModuleInstallArgs(args) {
|
|
|
32
40
|
packageSpec = arg;
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
|
-
return { packageSpec, eject, moduleId };
|
|
43
|
+
return { packageSpec, eject, moduleId, allowThirdParty };
|
|
36
44
|
}
|
|
37
45
|
export {
|
|
38
46
|
parseModuleInstallArgs
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/module-install-args.ts"],
|
|
4
|
-
"sourcesContent": ["export type ParsedModuleInstallArgs = {\n packageSpec: string | null\n eject: boolean\n moduleId: string | null\n}\n\nexport function parseModuleInstallArgs(args: string[]): ParsedModuleInstallArgs {\n let packageSpec: string | null = null\n let eject = false\n let moduleId: string | null = null\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index]\n if (!arg) continue\n\n if (arg === '--eject') {\n eject = true\n continue\n }\n\n if (arg.startsWith('--eject=')) {\n throw new Error('--eject does not accept a value')\n }\n\n if (arg === '--module') {\n const next = args[index + 1]\n if (next && !next.startsWith('-')) {\n moduleId = next\n index += 1\n continue\n }\n throw new Error(`--module requires a moduleId value`)\n }\n\n if (arg.startsWith('--module=')) {\n moduleId = arg.slice('--module='.length) || null\n continue\n }\n\n if (arg.startsWith('-')) {\n throw new Error(`Unsupported option: ${arg}`)\n }\n\n if (!arg.startsWith('-') && !packageSpec) {\n packageSpec = arg\n }\n }\n\n return { packageSpec, eject, moduleId }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export type ParsedModuleInstallArgs = {\n packageSpec: string | null\n eject: boolean\n moduleId: string | null\n allowThirdParty: boolean\n}\n\nexport function parseModuleInstallArgs(args: string[]): ParsedModuleInstallArgs {\n let packageSpec: string | null = null\n let eject = false\n let moduleId: string | null = null\n let allowThirdParty = false\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index]\n if (!arg) continue\n\n if (arg === '--eject') {\n eject = true\n continue\n }\n\n if (arg.startsWith('--eject=')) {\n throw new Error('--eject does not accept a value')\n }\n\n if (arg === '--allow-third-party') {\n allowThirdParty = true\n continue\n }\n\n if (arg.startsWith('--allow-third-party=')) {\n throw new Error('--allow-third-party does not accept a value')\n }\n\n if (arg === '--module') {\n const next = args[index + 1]\n if (next && !next.startsWith('-')) {\n moduleId = next\n index += 1\n continue\n }\n throw new Error(`--module requires a moduleId value`)\n }\n\n if (arg.startsWith('--module=')) {\n moduleId = arg.slice('--module='.length) || null\n continue\n }\n\n if (arg.startsWith('-')) {\n throw new Error(`Unsupported option: ${arg}`)\n }\n\n if (!arg.startsWith('-') && !packageSpec) {\n packageSpec = arg\n }\n }\n\n return { packageSpec, eject, moduleId, allowThirdParty }\n}\n"],
|
|
5
|
+
"mappings": "AAOO,SAAS,uBAAuB,MAAyC;AAC9E,MAAI,cAA6B;AACjC,MAAI,QAAQ;AACZ,MAAI,WAA0B;AAC9B,MAAI,kBAAkB;AAEtB,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,CAAC,IAAK;AAEV,QAAI,QAAQ,WAAW;AACrB,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,UAAU,GAAG;AAC9B,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,QAAI,QAAQ,uBAAuB;AACjC,wBAAkB;AAClB;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,sBAAsB,GAAG;AAC1C,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AAEA,QAAI,QAAQ,YAAY;AACtB,YAAM,OAAO,KAAK,QAAQ,CAAC;AAC3B,UAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;AACjC,mBAAW;AACX,iBAAS;AACT;AAAA,MACF;AACA,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAEA,QAAI,IAAI,WAAW,WAAW,GAAG;AAC/B,iBAAW,IAAI,MAAM,YAAY,MAAM,KAAK;AAC5C;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,GAAG,GAAG;AACvB,YAAM,IAAI,MAAM,uBAAuB,GAAG,EAAE;AAAA,IAC9C;AAEA,QAAI,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,aAAa;AACxC,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,OAAO,UAAU,gBAAgB;AACzD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
} from "./module-package.js";
|
|
10
10
|
import { ensureModuleRegistration } from "./modules-config.js";
|
|
11
11
|
import { resolveSpawnCommand } from "./spawn.js";
|
|
12
|
-
const
|
|
12
|
+
const OFFICIAL_PACKAGE_SCOPE = "@open-mercato/";
|
|
13
|
+
const SAFE_PACKAGE_SPEC_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@.+)?$/i;
|
|
13
14
|
const SAFE_PACKAGE_TAG_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
14
15
|
const SAFE_PACKAGE_FILE_LOCATOR_PATTERN = /^file:[A-Za-z0-9_./: \\-]+$/;
|
|
15
16
|
function resolveYarnBinary() {
|
|
@@ -91,18 +92,30 @@ async function runGeneratorsWithRegistrationNotice(resolver, moduleId) {
|
|
|
91
92
|
);
|
|
92
93
|
}
|
|
93
94
|
}
|
|
95
|
+
function isOfficialPackage(packageName) {
|
|
96
|
+
return packageName.startsWith(OFFICIAL_PACKAGE_SCOPE);
|
|
97
|
+
}
|
|
94
98
|
function assertPackageName(packageName) {
|
|
95
|
-
if (!packageName
|
|
96
|
-
throw new Error(
|
|
99
|
+
if (!packageName) {
|
|
100
|
+
throw new Error("Could not determine a package name from the provided spec.");
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
|
-
function
|
|
103
|
+
function assertThirdPartyAllowed(packageName, allowThirdParty) {
|
|
104
|
+
if (isOfficialPackage(packageName) || allowThirdParty) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Package "${packageName}" is outside the ${OFFICIAL_PACKAGE_SCOPE}* scope. Re-run with --allow-third-party to install third-party module packages.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function assertSupportedPackageSpec(packageSpec, allowThirdParty) {
|
|
100
112
|
const trimmed = packageSpec.trim();
|
|
101
113
|
if (!SAFE_PACKAGE_SPEC_PATTERN.test(trimmed)) {
|
|
102
|
-
throw new Error("Unsupported package spec.
|
|
114
|
+
throw new Error("Unsupported package spec. Provide a valid npm package name with an optional tag/version or file: locator.");
|
|
103
115
|
}
|
|
104
116
|
const packageName = parsePackageNameFromSpec(trimmed);
|
|
105
117
|
assertPackageName(packageName);
|
|
118
|
+
assertThirdPartyAllowed(packageName, allowThirdParty);
|
|
106
119
|
if (trimmed === packageName) {
|
|
107
120
|
return trimmed;
|
|
108
121
|
}
|
|
@@ -159,18 +172,16 @@ async function registerResolvedOfficialModule(resolver, modulePackage, packageNa
|
|
|
159
172
|
registrationChanged: registration.changed
|
|
160
173
|
};
|
|
161
174
|
}
|
|
162
|
-
async function addOfficialModule(resolver, packageSpec, eject, moduleId) {
|
|
163
|
-
const safePackageSpec = assertSupportedPackageSpec(packageSpec);
|
|
175
|
+
async function addOfficialModule(resolver, packageSpec, eject, moduleId, allowThirdParty = false) {
|
|
176
|
+
const safePackageSpec = assertSupportedPackageSpec(packageSpec, allowThirdParty);
|
|
164
177
|
const packageName = parsePackageNameFromSpec(safePackageSpec);
|
|
165
178
|
assertPackageName(packageName);
|
|
166
179
|
await installPackageSpec(resolver, safePackageSpec);
|
|
167
180
|
const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId);
|
|
168
181
|
return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject);
|
|
169
182
|
}
|
|
170
|
-
async function enableOfficialModule(resolver, packageName, moduleId, eject = false) {
|
|
171
|
-
|
|
172
|
-
throw new Error('Only @open-mercato/* packages can be enabled with "mercato module enable".');
|
|
173
|
-
}
|
|
183
|
+
async function enableOfficialModule(resolver, packageName, moduleId, eject = false, allowThirdParty = false) {
|
|
184
|
+
assertThirdPartyAllowed(packageName, allowThirdParty);
|
|
174
185
|
const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId);
|
|
175
186
|
return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject);
|
|
176
187
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/module-install.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport spawn from 'cross-spawn'\nimport { copyDirRecursive, rewriteCrossModuleImports } from './eject'\nimport {\n parsePackageNameFromSpec,\n resolveInstalledOfficialModulePackage,\n validateEjectBoundaries,\n type ValidatedOfficialModulePackage,\n} from './module-package'\nimport { ensureModuleRegistration } from './modules-config'\nimport type { PackageResolver } from './resolver'\nimport { resolveSpawnCommand } from './spawn'\n\ntype ModuleCommandResult = {\n moduleId: string\n packageName: string\n from: string\n registrationChanged: boolean\n}\n\ntype InstallTarget = {\n cwd: string\n args: string[]\n}\n\nconst
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport spawn from 'cross-spawn'\nimport { copyDirRecursive, rewriteCrossModuleImports } from './eject'\nimport {\n parsePackageNameFromSpec,\n resolveInstalledOfficialModulePackage,\n validateEjectBoundaries,\n type ValidatedOfficialModulePackage,\n} from './module-package'\nimport { ensureModuleRegistration } from './modules-config'\nimport type { PackageResolver } from './resolver'\nimport { resolveSpawnCommand } from './spawn'\n\ntype ModuleCommandResult = {\n moduleId: string\n packageName: string\n from: string\n registrationChanged: boolean\n}\n\ntype InstallTarget = {\n cwd: string\n args: string[]\n}\n\nconst OFFICIAL_PACKAGE_SCOPE = '@open-mercato/'\nconst SAFE_PACKAGE_SPEC_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*(?:@.+)?$/i\nconst SAFE_PACKAGE_TAG_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/\nconst SAFE_PACKAGE_FILE_LOCATOR_PATTERN = /^file:[A-Za-z0-9_./: \\\\-]+$/\n\nfunction resolveYarnBinary(): string {\n return process.platform === 'win32' ? 'yarn.cmd' : 'yarn'\n}\n\nfunction readAppPackageName(appDir: string): string {\n const packageJsonPath = path.join(appDir, 'package.json')\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`App package.json not found at ${packageJsonPath}.`)\n }\n\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string }\n if (!packageJson.name) {\n throw new Error(`App package.json at ${packageJsonPath} is missing the \"name\" field.`)\n }\n\n return packageJson.name\n}\n\nfunction resolveInstallTarget(resolver: PackageResolver): InstallTarget {\n if (!resolver.isMonorepo()) {\n return {\n cwd: resolver.getAppDir(),\n args: ['add'],\n }\n }\n\n return {\n cwd: resolver.getRootDir(),\n args: ['workspace', readAppPackageName(resolver.getAppDir()), 'add'],\n }\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const resolvedSpawn = resolveSpawnCommand(command, args)\n const child = spawn(resolvedSpawn.command, resolvedSpawn.args, {\n cwd,\n env: process.env,\n stdio: 'inherit',\n ...resolvedSpawn.spawnOptions,\n })\n\n child.on('error', reject)\n child.on('exit', (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Command failed: ${command} ${args.join(' ')} (exit ${code ?? 'unknown'}).`))\n })\n })\n}\n\nasync function installPackageSpec(\n resolver: PackageResolver,\n packageSpec: string,\n): Promise<void> {\n const target = resolveInstallTarget(resolver)\n await runCommand(resolveYarnBinary(), [...target.args, packageSpec], target.cwd)\n}\n\nexport async function runModuleGenerators(\n resolver: PackageResolver,\n quiet = true,\n): Promise<void> {\n const {\n generateEntityIds,\n generateModuleDi,\n generateModuleEntities,\n generateModulePackageSources,\n generateModuleRegistry,\n generateModuleRegistryApp,\n generateModuleRegistryCli,\n generateOpenApi,\n } = await import('./generators')\n\n await generateEntityIds({ resolver, quiet })\n await generateModuleRegistry({ resolver, quiet })\n await generateModuleRegistryApp({ resolver, quiet })\n await generateModuleRegistryCli({ resolver, quiet })\n await generateModuleEntities({ resolver, quiet })\n await generateModuleDi({ resolver, quiet })\n await generateModulePackageSources({ resolver, quiet })\n await generateOpenApi({ resolver, quiet })\n}\n\nasync function runGeneratorsWithRegistrationNotice(\n resolver: PackageResolver,\n moduleId: string,\n): Promise<void> {\n try {\n await runModuleGenerators(resolver)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(\n `Module \"${moduleId}\" is enabled, but generated artifacts are stale because generation failed. Rerun \"yarn mercato generate\" after fixing the underlying error. ${message}`,\n )\n }\n}\n\nfunction isOfficialPackage(packageName: string): boolean {\n return packageName.startsWith(OFFICIAL_PACKAGE_SCOPE)\n}\n\nfunction assertPackageName(packageName: string | null): asserts packageName is string {\n if (!packageName) {\n throw new Error('Could not determine a package name from the provided spec.')\n }\n}\n\nfunction assertThirdPartyAllowed(packageName: string, allowThirdParty: boolean): void {\n if (isOfficialPackage(packageName) || allowThirdParty) {\n return\n }\n\n throw new Error(\n `Package \"${packageName}\" is outside the ${OFFICIAL_PACKAGE_SCOPE}* scope. Re-run with --allow-third-party to install third-party module packages.`,\n )\n}\n\nfunction assertSupportedPackageSpec(packageSpec: string, allowThirdParty: boolean): string {\n const trimmed = packageSpec.trim()\n\n if (!SAFE_PACKAGE_SPEC_PATTERN.test(trimmed)) {\n throw new Error('Unsupported package spec. Provide a valid npm package name with an optional tag/version or file: locator.')\n }\n\n const packageName = parsePackageNameFromSpec(trimmed)\n assertPackageName(packageName)\n assertThirdPartyAllowed(packageName, allowThirdParty)\n\n if (trimmed === packageName) {\n return trimmed\n }\n\n const suffix = trimmed.slice(packageName.length + 1)\n if (SAFE_PACKAGE_TAG_PATTERN.test(suffix) || SAFE_PACKAGE_FILE_LOCATOR_PATTERN.test(suffix)) {\n return trimmed\n }\n\n throw new Error('Unsupported package spec suffix. Use a tag/version token or a file: locator.')\n}\n\nfunction validateBeforeRegistration(\n modulePackage: ValidatedOfficialModulePackage,\n resolver: PackageResolver,\n eject: boolean,\n): string {\n const appModuleDir = path.join(resolver.getAppDir(), 'src', 'modules', modulePackage.metadata.moduleId)\n\n if (eject && fs.existsSync(appModuleDir)) {\n throw new Error(`Destination directory already exists: ${appModuleDir}. Remove it first or rerun without --eject.`)\n }\n\n return appModuleDir\n}\n\nfunction prepareRegistrationSource(\n modulePackage: ValidatedOfficialModulePackage,\n resolver: PackageResolver,\n packageName: string,\n eject: boolean,\n): string {\n const appModuleDir = validateBeforeRegistration(modulePackage, resolver, eject)\n\n if (!eject) {\n return packageName\n }\n\n if (!modulePackage.metadata.ejectable) {\n throw new Error(`Package \"${packageName}\" is not ejectable. --eject requires open-mercato.ejectable === true.`)\n }\n\n validateEjectBoundaries(modulePackage)\n copyDirRecursive(modulePackage.sourceModuleDir, appModuleDir)\n rewriteCrossModuleImports(\n modulePackage.sourceModuleDir,\n appModuleDir,\n modulePackage.metadata.moduleId,\n packageName,\n )\n\n return '@app'\n}\n\nasync function registerResolvedOfficialModule(\n resolver: PackageResolver,\n modulePackage: ValidatedOfficialModulePackage,\n packageName: string,\n eject: boolean,\n): Promise<ModuleCommandResult> {\n const from = prepareRegistrationSource(modulePackage, resolver, packageName, eject)\n\n const registration = ensureModuleRegistration(\n resolver.getModulesConfigPath(),\n {\n id: modulePackage.metadata.moduleId,\n from,\n },\n )\n\n if (!registration.changed) {\n throw new Error(\n `Module \"${modulePackage.metadata.moduleId}\" from \"${from}\" is already enabled in modules.ts.`,\n )\n }\n\n await runGeneratorsWithRegistrationNotice(resolver, modulePackage.metadata.moduleId)\n\n return {\n moduleId: modulePackage.metadata.moduleId,\n packageName,\n from,\n registrationChanged: registration.changed,\n }\n}\n\nexport async function addOfficialModule(\n resolver: PackageResolver,\n packageSpec: string,\n eject: boolean,\n moduleId?: string,\n allowThirdParty = false,\n): Promise<ModuleCommandResult> {\n const safePackageSpec = assertSupportedPackageSpec(packageSpec, allowThirdParty)\n const packageName = parsePackageNameFromSpec(safePackageSpec)\n assertPackageName(packageName)\n\n await installPackageSpec(resolver, safePackageSpec)\n\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId)\n return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject)\n}\n\nexport async function enableOfficialModule(\n resolver: PackageResolver,\n packageName: string,\n moduleId?: string,\n eject = false,\n allowThirdParty = false,\n): Promise<ModuleCommandResult> {\n assertThirdPartyAllowed(packageName, allowThirdParty)\n\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId)\n return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -168,8 +168,8 @@ function readOfficialModulePackageFromRoot(packageRoot, expectedPackageName, tar
|
|
|
168
168
|
}
|
|
169
169
|
const packageJson = readPackageJson(packageJsonPath);
|
|
170
170
|
const packageName = packageJson.name;
|
|
171
|
-
if (!packageName
|
|
172
|
-
throw new Error(`Package at ${
|
|
171
|
+
if (!packageName) {
|
|
172
|
+
throw new Error(`Package manifest at ${packageJsonPath} is missing the "name" field.`);
|
|
173
173
|
}
|
|
174
174
|
if (expectedPackageName && packageName !== expectedPackageName) {
|
|
175
175
|
throw new Error(`Resolved package "${packageName}" does not match requested package "${expectedPackageName}".`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/module-package.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { createRequire } from 'node:module'\nimport type { PackageResolver } from './resolver'\n\ntype PackageJsonRecord = {\n name?: string\n version?: string\n dependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n}\n\nexport type ModulePackageMetadata = {\n moduleId: string\n ejectable: boolean\n}\n\nexport type ModuleInfoSnapshot = {\n title?: string\n description?: string\n}\n\nexport type ValidatedOfficialModulePackage = {\n packageName: string\n packageRoot: string\n packageJson: PackageJsonRecord\n metadata: ModulePackageMetadata\n moduleInfo: ModuleInfoSnapshot\n sourceModuleDir: string\n distModuleDir: string\n}\n\ntype DiscoveredModule = {\n moduleId: string\n ejectable: boolean\n}\n\nconst SOURCE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nconst SKIP_DIRS = new Set(['__tests__', '__mocks__', 'node_modules'])\nconst MODULE_ID_PATTERN = /^[a-z0-9]+(?:_[a-z0-9]+)*$/\nconst requireFromCli = createRequire(path.join(process.cwd(), 'package.json'))\n\nfunction shouldSkipEntryName(name: string): boolean {\n return SKIP_DIRS.has(name) || name === '.DS_Store' || name.startsWith('._')\n}\n\nfunction readPackageJson(packageJsonPath: string): PackageJsonRecord {\n try {\n const raw = fs.readFileSync(packageJsonPath, 'utf8')\n return JSON.parse(raw) as PackageJsonRecord\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(`Failed to read package manifest at ${packageJsonPath}: ${message}`)\n }\n}\n\nfunction parseModuleInfo(indexPath: string): { title?: string; description?: string; ejectable?: boolean } {\n if (!fs.existsSync(indexPath)) return {}\n\n const source = fs.readFileSync(indexPath, 'utf8')\n const result: { title?: string; description?: string; ejectable?: boolean } = {}\n\n const titleMatch = source.match(/\\btitle\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (titleMatch) result.title = titleMatch[1]\n\n const descriptionMatch = source.match(/\\bdescription\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descriptionMatch) result.description = descriptionMatch[1]\n\n const ejectableMatch = source.match(/\\bejectable\\s*:\\s*(true|false)/)\n if (ejectableMatch) result.ejectable = ejectableMatch[1] === 'true'\n\n return result\n}\n\nexport function discoverModulesInPackage(packageRoot: string): DiscoveredModule[] {\n const srcModulesDir = path.join(packageRoot, 'src', 'modules')\n const distModulesDir = path.join(packageRoot, 'dist', 'modules')\n\n const enumerationDir = fs.existsSync(srcModulesDir)\n ? srcModulesDir\n : fs.existsSync(distModulesDir)\n ? distModulesDir\n : null\n\n if (!enumerationDir) return []\n\n const modules: DiscoveredModule[] = []\n\n for (const entry of fs.readdirSync(enumerationDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || shouldSkipEntryName(entry.name) || !MODULE_ID_PATTERN.test(entry.name)) continue\n\n const moduleId = entry.name\n const srcIndexPath = path.join(packageRoot, 'src', 'modules', moduleId, 'index.ts')\n const distIndexPath = path.join(packageRoot, 'dist', 'modules', moduleId, 'index.js')\n const indexPath = fs.existsSync(srcIndexPath) ? srcIndexPath : distIndexPath\n\n const info = parseModuleInfo(indexPath)\n modules.push({ moduleId, ejectable: info.ejectable ?? false })\n }\n\n return modules\n}\n\nfunction resolveRelativeImportTarget(sourceFile: string, importPath: string): string | null {\n if (!importPath.startsWith('.')) return null\n\n const basePath = path.resolve(path.dirname(sourceFile), importPath)\n const candidates = [basePath]\n\n for (const ext of SOURCE_FILE_EXTENSIONS) {\n candidates.push(`${basePath}${ext}`)\n candidates.push(path.join(basePath, `index${ext}`))\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\nfunction collectSourceFiles(dir: string): string[] {\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n files.push(...collectSourceFiles(fullPath))\n continue\n }\n\n const ext = path.extname(entry.name)\n if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue\n files.push(fullPath)\n }\n\n return files\n}\n\nfunction collectBoundaryViolations(moduleDir: string): string[] {\n const modulesRoot = path.resolve(moduleDir, '..')\n const modulePrefix = `${moduleDir}${path.sep}`\n const modulesPrefix = `${modulesRoot}${path.sep}`\n const files = collectSourceFiles(moduleDir)\n const violations = new Set<string>()\n\n for (const filePath of files) {\n const content = fs.readFileSync(filePath, 'utf8')\n const matches = [\n ...content.matchAll(/\\bfrom\\s*['\"]([^'\"]+)['\"]/g),\n ...content.matchAll(/\\bimport\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g),\n ]\n\n for (const match of matches) {\n const specifier = match[1]\n if (!specifier) continue\n const resolvedTarget = resolveRelativeImportTarget(filePath, specifier)\n if (!resolvedTarget) continue\n if (resolvedTarget.startsWith(modulePrefix)) continue\n if (resolvedTarget.startsWith(modulesPrefix)) continue\n\n const relativeSource = path.relative(moduleDir, filePath).split(path.sep).join('/')\n const relativeTarget = path.relative(path.dirname(filePath), resolvedTarget).split(path.sep).join('/')\n violations.add(`${relativeSource} -> ${relativeTarget}`)\n }\n }\n\n return Array.from(violations).sort((left, right) => left.localeCompare(right))\n}\n\nfunction findResolvedPackageRoot(\n resolvedPath: string,\n packageName: string,\n): string | null {\n let currentPath = fs.statSync(resolvedPath).isDirectory()\n ? resolvedPath\n : path.dirname(resolvedPath)\n\n while (currentPath !== path.dirname(currentPath)) {\n const packageJsonPath = path.join(currentPath, 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = readPackageJson(packageJsonPath)\n if (packageJson.name === packageName) {\n return currentPath\n }\n }\n currentPath = path.dirname(currentPath)\n }\n\n return null\n}\n\nfunction resolveInstalledPackageRootWithRequire(packageName: string, appDir: string): string | null {\n const specifiers = [`${packageName}/package.json`, packageName]\n\n for (const specifier of specifiers) {\n try {\n const resolvedPath = requireFromCli.resolve(specifier, {\n paths: [appDir],\n })\n const packageRoot =\n specifier === packageName\n ? findResolvedPackageRoot(resolvedPath, packageName)\n : path.dirname(resolvedPath)\n\n if (packageRoot) {\n return packageRoot\n }\n } catch {\n continue\n }\n }\n\n return null\n}\n\nexport function parsePackageNameFromSpec(packageSpec: string): string | null {\n const trimmed = packageSpec.trim()\n if (!trimmed) return null\n\n if (trimmed.startsWith('@')) {\n const slashIndex = trimmed.indexOf('/')\n if (slashIndex < 0) return null\n const versionSeparator = trimmed.indexOf('@', slashIndex + 1)\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n }\n\n const versionSeparator = trimmed.indexOf('@')\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n}\n\nexport function resolveInstalledPackageRoot(\n resolver: PackageResolver,\n packageName: string,\n): string {\n const resolvedWithRequire = resolveInstalledPackageRootWithRequire(packageName, resolver.getAppDir())\n if (resolvedWithRequire) {\n return resolvedWithRequire\n }\n\n const fallback = resolver.getPackageRoot(packageName)\n if (fs.existsSync(path.join(fallback, 'package.json'))) {\n return fallback\n }\n\n // In monorepo mode, getPackageRoot resolves to packages/<name> (workspace convention),\n // but externally installed packages land in root node_modules \u2014 check there too.\n const nodeModulesFallback = path.join(resolver.getRootDir(), 'node_modules', packageName)\n if (fs.existsSync(path.join(nodeModulesFallback, 'package.json'))) {\n return nodeModulesFallback\n }\n\n throw new Error(`Package \"${packageName}\" is not installed in ${resolver.getAppDir()}.`)\n}\n\nexport function readOfficialModulePackageFromRoot(\n packageRoot: string,\n expectedPackageName?: string,\n targetModuleId?: string,\n): ValidatedOfficialModulePackage {\n const packageJsonPath = path.join(packageRoot, 'package.json')\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`Package manifest not found at ${packageJsonPath}.`)\n }\n\n const packageJson = readPackageJson(packageJsonPath)\n const packageName = packageJson.name\n if (!packageName || !packageName.startsWith('@open-mercato/')) {\n throw new Error(`Package at ${packageRoot} is not under the @open-mercato scope.`)\n }\n\n if (expectedPackageName && packageName !== expectedPackageName) {\n throw new Error(`Resolved package \"${packageName}\" does not match requested package \"${expectedPackageName}\".`)\n }\n\n const discoveredModules = discoverModulesInPackage(packageRoot)\n\n if (discoveredModules.length === 0) {\n throw new Error(`Package \"${packageName}\" has no modules in src/modules/ or dist/modules/.`)\n }\n\n let selected: DiscoveredModule\n\n if (targetModuleId) {\n const found = discoveredModules.find((m) => m.moduleId === targetModuleId)\n if (!found) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" does not contain module \"${targetModuleId}\". Available: ${available}`,\n )\n }\n selected = found\n } else {\n if (discoveredModules.length > 1) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" contains multiple modules (${available}). Specify one with --module <moduleId>.`,\n )\n }\n selected = discoveredModules[0]\n }\n\n const { moduleId } = selected\n const sourceModuleDir = path.join(packageRoot, 'src', 'modules', moduleId)\n const distModuleDir = path.join(packageRoot, 'dist', 'modules', moduleId)\n\n if (!fs.existsSync(sourceModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing src/modules/${moduleId}.`)\n }\n\n if (!fs.existsSync(distModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing dist/modules/${moduleId}.`)\n }\n\n const info = parseModuleInfo(path.join(sourceModuleDir, 'index.ts'))\n\n return {\n packageName,\n packageRoot,\n packageJson,\n metadata: { moduleId, ejectable: selected.ejectable },\n moduleInfo: { title: info.title, description: info.description },\n sourceModuleDir,\n distModuleDir,\n }\n}\n\nexport function resolveInstalledOfficialModulePackage(\n resolver: PackageResolver,\n packageName: string,\n moduleId?: string,\n): ValidatedOfficialModulePackage {\n const packageRoot = resolveInstalledPackageRoot(resolver, packageName)\n return readOfficialModulePackageFromRoot(packageRoot, packageName, moduleId)\n}\n\nexport function validateEjectBoundaries(modulePackage: ValidatedOfficialModulePackage): void {\n const violations = collectBoundaryViolations(modulePackage.sourceModuleDir)\n if (violations.length === 0) {\n return\n }\n\n throw new Error(\n [\n `Package \"${modulePackage.packageName}\" cannot be added with --eject because it imports files outside src/modules/${modulePackage.metadata.moduleId}.`,\n 'Invalid imports:',\n ...violations.map((violation) => `- ${violation}`),\n ].join('\\n'),\n )\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { createRequire } from 'node:module'\nimport type { PackageResolver } from './resolver'\n\ntype PackageJsonRecord = {\n name?: string\n version?: string\n dependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n}\n\nexport type ModulePackageMetadata = {\n moduleId: string\n ejectable: boolean\n}\n\nexport type ModuleInfoSnapshot = {\n title?: string\n description?: string\n}\n\nexport type ValidatedOfficialModulePackage = {\n packageName: string\n packageRoot: string\n packageJson: PackageJsonRecord\n metadata: ModulePackageMetadata\n moduleInfo: ModuleInfoSnapshot\n sourceModuleDir: string\n distModuleDir: string\n}\n\ntype DiscoveredModule = {\n moduleId: string\n ejectable: boolean\n}\n\nconst SOURCE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nconst SKIP_DIRS = new Set(['__tests__', '__mocks__', 'node_modules'])\nconst MODULE_ID_PATTERN = /^[a-z0-9]+(?:_[a-z0-9]+)*$/\nconst requireFromCli = createRequire(path.join(process.cwd(), 'package.json'))\n\nfunction shouldSkipEntryName(name: string): boolean {\n return SKIP_DIRS.has(name) || name === '.DS_Store' || name.startsWith('._')\n}\n\nfunction readPackageJson(packageJsonPath: string): PackageJsonRecord {\n try {\n const raw = fs.readFileSync(packageJsonPath, 'utf8')\n return JSON.parse(raw) as PackageJsonRecord\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(`Failed to read package manifest at ${packageJsonPath}: ${message}`)\n }\n}\n\nfunction parseModuleInfo(indexPath: string): { title?: string; description?: string; ejectable?: boolean } {\n if (!fs.existsSync(indexPath)) return {}\n\n const source = fs.readFileSync(indexPath, 'utf8')\n const result: { title?: string; description?: string; ejectable?: boolean } = {}\n\n const titleMatch = source.match(/\\btitle\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (titleMatch) result.title = titleMatch[1]\n\n const descriptionMatch = source.match(/\\bdescription\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descriptionMatch) result.description = descriptionMatch[1]\n\n const ejectableMatch = source.match(/\\bejectable\\s*:\\s*(true|false)/)\n if (ejectableMatch) result.ejectable = ejectableMatch[1] === 'true'\n\n return result\n}\n\nexport function discoverModulesInPackage(packageRoot: string): DiscoveredModule[] {\n const srcModulesDir = path.join(packageRoot, 'src', 'modules')\n const distModulesDir = path.join(packageRoot, 'dist', 'modules')\n\n const enumerationDir = fs.existsSync(srcModulesDir)\n ? srcModulesDir\n : fs.existsSync(distModulesDir)\n ? distModulesDir\n : null\n\n if (!enumerationDir) return []\n\n const modules: DiscoveredModule[] = []\n\n for (const entry of fs.readdirSync(enumerationDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || shouldSkipEntryName(entry.name) || !MODULE_ID_PATTERN.test(entry.name)) continue\n\n const moduleId = entry.name\n const srcIndexPath = path.join(packageRoot, 'src', 'modules', moduleId, 'index.ts')\n const distIndexPath = path.join(packageRoot, 'dist', 'modules', moduleId, 'index.js')\n const indexPath = fs.existsSync(srcIndexPath) ? srcIndexPath : distIndexPath\n\n const info = parseModuleInfo(indexPath)\n modules.push({ moduleId, ejectable: info.ejectable ?? false })\n }\n\n return modules\n}\n\nfunction resolveRelativeImportTarget(sourceFile: string, importPath: string): string | null {\n if (!importPath.startsWith('.')) return null\n\n const basePath = path.resolve(path.dirname(sourceFile), importPath)\n const candidates = [basePath]\n\n for (const ext of SOURCE_FILE_EXTENSIONS) {\n candidates.push(`${basePath}${ext}`)\n candidates.push(path.join(basePath, `index${ext}`))\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\nfunction collectSourceFiles(dir: string): string[] {\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n files.push(...collectSourceFiles(fullPath))\n continue\n }\n\n const ext = path.extname(entry.name)\n if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue\n files.push(fullPath)\n }\n\n return files\n}\n\nfunction collectBoundaryViolations(moduleDir: string): string[] {\n const modulesRoot = path.resolve(moduleDir, '..')\n const modulePrefix = `${moduleDir}${path.sep}`\n const modulesPrefix = `${modulesRoot}${path.sep}`\n const files = collectSourceFiles(moduleDir)\n const violations = new Set<string>()\n\n for (const filePath of files) {\n const content = fs.readFileSync(filePath, 'utf8')\n const matches = [\n ...content.matchAll(/\\bfrom\\s*['\"]([^'\"]+)['\"]/g),\n ...content.matchAll(/\\bimport\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g),\n ]\n\n for (const match of matches) {\n const specifier = match[1]\n if (!specifier) continue\n const resolvedTarget = resolveRelativeImportTarget(filePath, specifier)\n if (!resolvedTarget) continue\n if (resolvedTarget.startsWith(modulePrefix)) continue\n if (resolvedTarget.startsWith(modulesPrefix)) continue\n\n const relativeSource = path.relative(moduleDir, filePath).split(path.sep).join('/')\n const relativeTarget = path.relative(path.dirname(filePath), resolvedTarget).split(path.sep).join('/')\n violations.add(`${relativeSource} -> ${relativeTarget}`)\n }\n }\n\n return Array.from(violations).sort((left, right) => left.localeCompare(right))\n}\n\nfunction findResolvedPackageRoot(\n resolvedPath: string,\n packageName: string,\n): string | null {\n let currentPath = fs.statSync(resolvedPath).isDirectory()\n ? resolvedPath\n : path.dirname(resolvedPath)\n\n while (currentPath !== path.dirname(currentPath)) {\n const packageJsonPath = path.join(currentPath, 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = readPackageJson(packageJsonPath)\n if (packageJson.name === packageName) {\n return currentPath\n }\n }\n currentPath = path.dirname(currentPath)\n }\n\n return null\n}\n\nfunction resolveInstalledPackageRootWithRequire(packageName: string, appDir: string): string | null {\n const specifiers = [`${packageName}/package.json`, packageName]\n\n for (const specifier of specifiers) {\n try {\n const resolvedPath = requireFromCli.resolve(specifier, {\n paths: [appDir],\n })\n const packageRoot =\n specifier === packageName\n ? findResolvedPackageRoot(resolvedPath, packageName)\n : path.dirname(resolvedPath)\n\n if (packageRoot) {\n return packageRoot\n }\n } catch {\n continue\n }\n }\n\n return null\n}\n\nexport function parsePackageNameFromSpec(packageSpec: string): string | null {\n const trimmed = packageSpec.trim()\n if (!trimmed) return null\n\n if (trimmed.startsWith('@')) {\n const slashIndex = trimmed.indexOf('/')\n if (slashIndex < 0) return null\n const versionSeparator = trimmed.indexOf('@', slashIndex + 1)\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n }\n\n const versionSeparator = trimmed.indexOf('@')\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n}\n\nexport function resolveInstalledPackageRoot(\n resolver: PackageResolver,\n packageName: string,\n): string {\n const resolvedWithRequire = resolveInstalledPackageRootWithRequire(packageName, resolver.getAppDir())\n if (resolvedWithRequire) {\n return resolvedWithRequire\n }\n\n const fallback = resolver.getPackageRoot(packageName)\n if (fs.existsSync(path.join(fallback, 'package.json'))) {\n return fallback\n }\n\n // In monorepo mode, getPackageRoot resolves to packages/<name> (workspace convention),\n // but externally installed packages land in root node_modules \u2014 check there too.\n const nodeModulesFallback = path.join(resolver.getRootDir(), 'node_modules', packageName)\n if (fs.existsSync(path.join(nodeModulesFallback, 'package.json'))) {\n return nodeModulesFallback\n }\n\n throw new Error(`Package \"${packageName}\" is not installed in ${resolver.getAppDir()}.`)\n}\n\nexport function readOfficialModulePackageFromRoot(\n packageRoot: string,\n expectedPackageName?: string,\n targetModuleId?: string,\n): ValidatedOfficialModulePackage {\n const packageJsonPath = path.join(packageRoot, 'package.json')\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`Package manifest not found at ${packageJsonPath}.`)\n }\n\n const packageJson = readPackageJson(packageJsonPath)\n const packageName = packageJson.name\n if (!packageName) {\n throw new Error(`Package manifest at ${packageJsonPath} is missing the \"name\" field.`)\n }\n\n if (expectedPackageName && packageName !== expectedPackageName) {\n throw new Error(`Resolved package \"${packageName}\" does not match requested package \"${expectedPackageName}\".`)\n }\n\n const discoveredModules = discoverModulesInPackage(packageRoot)\n\n if (discoveredModules.length === 0) {\n throw new Error(`Package \"${packageName}\" has no modules in src/modules/ or dist/modules/.`)\n }\n\n let selected: DiscoveredModule\n\n if (targetModuleId) {\n const found = discoveredModules.find((m) => m.moduleId === targetModuleId)\n if (!found) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" does not contain module \"${targetModuleId}\". Available: ${available}`,\n )\n }\n selected = found\n } else {\n if (discoveredModules.length > 1) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" contains multiple modules (${available}). Specify one with --module <moduleId>.`,\n )\n }\n selected = discoveredModules[0]\n }\n\n const { moduleId } = selected\n const sourceModuleDir = path.join(packageRoot, 'src', 'modules', moduleId)\n const distModuleDir = path.join(packageRoot, 'dist', 'modules', moduleId)\n\n if (!fs.existsSync(sourceModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing src/modules/${moduleId}.`)\n }\n\n if (!fs.existsSync(distModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing dist/modules/${moduleId}.`)\n }\n\n const info = parseModuleInfo(path.join(sourceModuleDir, 'index.ts'))\n\n return {\n packageName,\n packageRoot,\n packageJson,\n metadata: { moduleId, ejectable: selected.ejectable },\n moduleInfo: { title: info.title, description: info.description },\n sourceModuleDir,\n distModuleDir,\n }\n}\n\nexport function resolveInstalledOfficialModulePackage(\n resolver: PackageResolver,\n packageName: string,\n moduleId?: string,\n): ValidatedOfficialModulePackage {\n const packageRoot = resolveInstalledPackageRoot(resolver, packageName)\n return readOfficialModulePackageFromRoot(packageRoot, packageName, moduleId)\n}\n\nexport function validateEjectBoundaries(modulePackage: ValidatedOfficialModulePackage): void {\n const violations = collectBoundaryViolations(modulePackage.sourceModuleDir)\n if (violations.length === 0) {\n return\n }\n\n throw new Error(\n [\n `Package \"${modulePackage.packageName}\" cannot be added with --eject because it imports files outside src/modules/${modulePackage.metadata.moduleId}.`,\n 'Invalid imports:',\n ...violations.map((violation) => `- ${violation}`),\n ].join('\\n'),\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["versionSeparator"]
|
|
7
7
|
}
|
package/dist/mercato.js
CHANGED
|
@@ -1016,20 +1016,20 @@ async function run(argv = process.argv) {
|
|
|
1016
1016
|
const commandArgs = remaining.filter(Boolean);
|
|
1017
1017
|
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
1018
1018
|
console.log("Usage: yarn mercato module <add|enable|eject> ...");
|
|
1019
|
-
console.log(" yarn mercato module add <packageSpec> [--module <moduleId>] [--eject]");
|
|
1020
|
-
console.log(" yarn mercato module enable <packageName> [--module <moduleId>] [--eject]");
|
|
1019
|
+
console.log(" yarn mercato module add <packageSpec> [--module <moduleId>] [--eject] [--allow-third-party]");
|
|
1020
|
+
console.log(" yarn mercato module enable <packageName> [--module <moduleId>] [--eject] [--allow-third-party]");
|
|
1021
1021
|
console.log(" yarn mercato module eject <moduleId>");
|
|
1022
1022
|
return 0;
|
|
1023
1023
|
}
|
|
1024
1024
|
if (subcommand === "add") {
|
|
1025
1025
|
const { createResolver } = await import("./lib/resolver.js");
|
|
1026
1026
|
const { addOfficialModule } = await import("./lib/module-install.js");
|
|
1027
|
-
const { packageSpec, eject, moduleId } = parseModuleInstallArgs(commandArgs);
|
|
1027
|
+
const { packageSpec, eject, moduleId, allowThirdParty } = parseModuleInstallArgs(commandArgs);
|
|
1028
1028
|
if (!packageSpec) {
|
|
1029
|
-
console.error("Usage: yarn mercato module add <packageSpec> [--module <moduleId>] [--eject]");
|
|
1029
|
+
console.error("Usage: yarn mercato module add <packageSpec> [--module <moduleId>] [--eject] [--allow-third-party]");
|
|
1030
1030
|
return 1;
|
|
1031
1031
|
}
|
|
1032
|
-
const result = await addOfficialModule(createResolver(), packageSpec, eject, moduleId ?? void 0);
|
|
1032
|
+
const result = await addOfficialModule(createResolver(), packageSpec, eject, moduleId ?? void 0, allowThirdParty);
|
|
1033
1033
|
console.log(`
|
|
1034
1034
|
\u2705 Module "${result.moduleId}" enabled from ${result.from}.
|
|
1035
1035
|
`);
|
|
@@ -1041,13 +1041,13 @@ async function run(argv = process.argv) {
|
|
|
1041
1041
|
if (subcommand === "enable") {
|
|
1042
1042
|
const packageName = commandArgs.find((arg) => !arg.startsWith("-"));
|
|
1043
1043
|
if (!packageName) {
|
|
1044
|
-
console.error("Usage: yarn mercato module enable <packageName> [--module <moduleId>] [--eject]");
|
|
1044
|
+
console.error("Usage: yarn mercato module enable <packageName> [--module <moduleId>] [--eject] [--allow-third-party]");
|
|
1045
1045
|
return 1;
|
|
1046
1046
|
}
|
|
1047
1047
|
const { createResolver } = await import("./lib/resolver.js");
|
|
1048
1048
|
const { enableOfficialModule } = await import("./lib/module-install.js");
|
|
1049
|
-
const { moduleId, eject } = parseModuleInstallArgs(commandArgs);
|
|
1050
|
-
const result = await enableOfficialModule(createResolver(), packageName, moduleId ?? void 0, eject);
|
|
1049
|
+
const { moduleId, eject, allowThirdParty } = parseModuleInstallArgs(commandArgs);
|
|
1050
|
+
const result = await enableOfficialModule(createResolver(), packageName, moduleId ?? void 0, eject, allowThirdParty);
|
|
1051
1051
|
console.log(`
|
|
1052
1052
|
\u2705 Module "${result.moduleId}" enabled from ${result.from}.
|
|
1053
1053
|
`);
|