@unlimitechcloud/devlink 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +880 -0
- package/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/__tests__/e2e.spec.d.ts +8 -0
- package/dist/__tests__/e2e.spec.d.ts.map +1 -0
- package/dist/__tests__/e2e.spec.js +253 -0
- package/dist/__tests__/e2e.spec.js.map +1 -0
- package/dist/__tests__/integration.spec.d.ts +8 -0
- package/dist/__tests__/integration.spec.d.ts.map +1 -0
- package/dist/__tests__/integration.spec.js +274 -0
- package/dist/__tests__/integration.spec.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +610 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/consumers.d.ts +37 -0
- package/dist/commands/consumers.d.ts.map +1 -0
- package/dist/commands/consumers.js +107 -0
- package/dist/commands/consumers.js.map +1 -0
- package/dist/commands/docs.d.ts +59 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +262 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/docs.spec.d.ts +5 -0
- package/dist/commands/docs.spec.d.ts.map +1 -0
- package/dist/commands/docs.spec.js +213 -0
- package/dist/commands/docs.spec.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install.d.ts +31 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +234 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +22 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +45 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/list.spec.d.ts +5 -0
- package/dist/commands/list.spec.d.ts.map +1 -0
- package/dist/commands/list.spec.js +95 -0
- package/dist/commands/list.spec.js.map +1 -0
- package/dist/commands/prune.d.ts +27 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +74 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/publish.d.ts +16 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +225 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/publish.spec.d.ts +5 -0
- package/dist/commands/publish.spec.d.ts.map +1 -0
- package/dist/commands/publish.spec.js +98 -0
- package/dist/commands/publish.spec.js.map +1 -0
- package/dist/commands/push.d.ts +16 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +164 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/remove.d.ts +24 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +80 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/remove.spec.d.ts +5 -0
- package/dist/commands/remove.spec.d.ts.map +1 -0
- package/dist/commands/remove.spec.js +87 -0
- package/dist/commands/remove.spec.js.map +1 -0
- package/dist/commands/resolve.d.ts +20 -0
- package/dist/commands/resolve.d.ts.map +1 -0
- package/dist/commands/resolve.js +52 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/resolve.spec.d.ts +5 -0
- package/dist/commands/resolve.spec.d.ts.map +1 -0
- package/dist/commands/resolve.spec.js +87 -0
- package/dist/commands/resolve.spec.js.map +1 -0
- package/dist/commands/verify.d.ts +32 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +127 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +70 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +65 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +116 -0
- package/dist/constants.js.map +1 -0
- package/dist/constants.spec.d.ts +5 -0
- package/dist/constants.spec.d.ts.map +1 -0
- package/dist/constants.spec.js +72 -0
- package/dist/constants.spec.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/installations.d.ts +79 -0
- package/dist/core/installations.d.ts.map +1 -0
- package/dist/core/installations.js +207 -0
- package/dist/core/installations.js.map +1 -0
- package/dist/core/installations.spec.d.ts +5 -0
- package/dist/core/installations.spec.d.ts.map +1 -0
- package/dist/core/installations.spec.js +261 -0
- package/dist/core/installations.spec.js.map +1 -0
- package/dist/core/lock.d.ts +37 -0
- package/dist/core/lock.d.ts.map +1 -0
- package/dist/core/lock.js +198 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/lock.spec.d.ts +5 -0
- package/dist/core/lock.spec.d.ts.map +1 -0
- package/dist/core/lock.spec.js +161 -0
- package/dist/core/lock.spec.js.map +1 -0
- package/dist/core/registry.d.ts +80 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +231 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/registry.spec.d.ts +5 -0
- package/dist/core/registry.spec.d.ts.map +1 -0
- package/dist/core/registry.spec.js +281 -0
- package/dist/core/registry.spec.js.map +1 -0
- package/dist/core/resolver.d.ts +55 -0
- package/dist/core/resolver.d.ts.map +1 -0
- package/dist/core/resolver.js +127 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/core/resolver.spec.d.ts +5 -0
- package/dist/core/resolver.spec.d.ts.map +1 -0
- package/dist/core/resolver.spec.js +202 -0
- package/dist/core/resolver.spec.js.map +1 -0
- package/dist/core/store.d.ts +65 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +245 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/store.spec.d.ts +5 -0
- package/dist/core/store.spec.d.ts.map +1 -0
- package/dist/core/store.spec.js +195 -0
- package/dist/core/store.spec.js.map +1 -0
- package/dist/formatters/flat.d.ts +41 -0
- package/dist/formatters/flat.d.ts.map +1 -0
- package/dist/formatters/flat.js +131 -0
- package/dist/formatters/flat.js.map +1 -0
- package/dist/formatters/flat.spec.d.ts +5 -0
- package/dist/formatters/flat.spec.d.ts.map +1 -0
- package/dist/formatters/flat.spec.js +130 -0
- package/dist/formatters/flat.spec.js.map +1 -0
- package/dist/formatters/index.d.ts +6 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +6 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/tree.d.ts +29 -0
- package/dist/formatters/tree.d.ts.map +1 -0
- package/dist/formatters/tree.js +256 -0
- package/dist/formatters/tree.js.map +1 -0
- package/dist/formatters/tree.spec.d.ts +5 -0
- package/dist/formatters/tree.spec.d.ts.map +1 -0
- package/dist/formatters/tree.spec.js +127 -0
- package/dist/formatters/tree.spec.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/installer.d.ts +13 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +171 -0
- package/dist/installer.js.map +1 -0
- package/dist/store.d.ts +78 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +344 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +235 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/README.md +68 -0
- package/docs/inspection/consumers.md +178 -0
- package/docs/inspection/list.md +182 -0
- package/docs/inspection/resolve.md +172 -0
- package/docs/installation/configuration.md +238 -0
- package/docs/installation/install.md +184 -0
- package/docs/maintenance/prune.md +159 -0
- package/docs/maintenance/remove.md +174 -0
- package/docs/maintenance/verify.md +174 -0
- package/docs/publishing/publish.md +146 -0
- package/docs/publishing/push.md +146 -0
- package/docs/store/locking.md +118 -0
- package/docs/store/namespaces.md +141 -0
- package/docs/store/structure.md +163 -0
- package/package.json +58 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Push Command
|
|
2
|
+
|
|
3
|
+
Publishes a package and automatically updates all consumer projects.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
devlink push [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Options
|
|
12
|
+
|
|
13
|
+
| Option | Description |
|
|
14
|
+
|--------|-------------|
|
|
15
|
+
| `-n, --namespace <name>` | Target namespace (default: `global`) |
|
|
16
|
+
| `--repo <path>` | Use custom repo path |
|
|
17
|
+
|
|
18
|
+
## Description
|
|
19
|
+
|
|
20
|
+
The `push` command combines publishing with automatic consumer updates:
|
|
21
|
+
|
|
22
|
+
1. Publishes the package (same as `devlink publish`)
|
|
23
|
+
2. Finds all projects that have installed this package
|
|
24
|
+
3. Re-links the package in each consumer project
|
|
25
|
+
4. Updates signatures in `installations.json`
|
|
26
|
+
5. Updates `devlink.lock` files in consumer projects
|
|
27
|
+
|
|
28
|
+
This is the recommended command during active development.
|
|
29
|
+
|
|
30
|
+
## Example
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd my-sdk/packages/core
|
|
34
|
+
devlink push
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Output:
|
|
38
|
+
```
|
|
39
|
+
📦 @scope/core@1.0.0 published to global
|
|
40
|
+
Signature: abc123new
|
|
41
|
+
|
|
42
|
+
🔄 Pushing to 2 project(s):
|
|
43
|
+
✓ /home/user/project-a
|
|
44
|
+
✓ /home/user/project-b
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## How It Works
|
|
48
|
+
|
|
49
|
+
### 1. Publish Phase
|
|
50
|
+
|
|
51
|
+
Same as `devlink publish`:
|
|
52
|
+
- Copies files to store
|
|
53
|
+
- Updates registry
|
|
54
|
+
- Generates new signature
|
|
55
|
+
|
|
56
|
+
### 2. Find Consumers
|
|
57
|
+
|
|
58
|
+
Searches `installations.json` for projects that:
|
|
59
|
+
- Have installed this package
|
|
60
|
+
- From the same namespace
|
|
61
|
+
- With the same version
|
|
62
|
+
|
|
63
|
+
### 3. Update Consumers
|
|
64
|
+
|
|
65
|
+
For each consumer project:
|
|
66
|
+
- Verifies project still exists
|
|
67
|
+
- Re-creates symlink in `node_modules`
|
|
68
|
+
- Updates signature in `installations.json`
|
|
69
|
+
- Updates `devlink.lock` file
|
|
70
|
+
|
|
71
|
+
## Consumer Tracking
|
|
72
|
+
|
|
73
|
+
Projects become "consumers" when they run `devlink install`. The installation is recorded in `installations.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"projects": {
|
|
78
|
+
"/home/user/project-a": {
|
|
79
|
+
"packages": {
|
|
80
|
+
"@scope/core": {
|
|
81
|
+
"version": "1.0.0",
|
|
82
|
+
"namespace": "global",
|
|
83
|
+
"signature": "old-signature"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
After `push`, the signature is updated to match the new content.
|
|
92
|
+
|
|
93
|
+
## Use Cases
|
|
94
|
+
|
|
95
|
+
### Active Development
|
|
96
|
+
|
|
97
|
+
When developing a library used by multiple projects:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Make changes to library
|
|
101
|
+
vim src/index.ts
|
|
102
|
+
|
|
103
|
+
# Build
|
|
104
|
+
npm run build
|
|
105
|
+
|
|
106
|
+
# Push to all consumers
|
|
107
|
+
devlink push
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
All consumer projects immediately get the updated code.
|
|
111
|
+
|
|
112
|
+
### Feature Branch Development
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Publish to feature namespace
|
|
116
|
+
devlink push -n feature-v2
|
|
117
|
+
|
|
118
|
+
# Only consumers using feature-v2 namespace are updated
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Dead Projects
|
|
122
|
+
|
|
123
|
+
If a consumer project no longer exists (deleted), `push` will:
|
|
124
|
+
- Skip that project
|
|
125
|
+
- Show a warning
|
|
126
|
+
- Continue with other projects
|
|
127
|
+
|
|
128
|
+
To clean up dead projects:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
devlink consumers --prune
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Comparison with Publish
|
|
135
|
+
|
|
136
|
+
| Aspect | `publish` | `push` |
|
|
137
|
+
|--------|-----------|--------|
|
|
138
|
+
| Publishes package | ✓ | ✓ |
|
|
139
|
+
| Updates consumers | ✗ | ✓ |
|
|
140
|
+
| Use case | Initial publish | Active development |
|
|
141
|
+
|
|
142
|
+
## See Also
|
|
143
|
+
|
|
144
|
+
- [Publish Command](publish.md) - Publishing without consumer updates
|
|
145
|
+
- [Consumers Command](../inspection/consumers.md) - Managing consumer projects
|
|
146
|
+
- [Install Command](../installation/install.md) - How projects become consumers
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# File Locking
|
|
2
|
+
|
|
3
|
+
DevLink uses file locking to serialize write operations and prevent store corruption when multiple processes access the store simultaneously.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
When a command needs to modify the store, it:
|
|
8
|
+
|
|
9
|
+
1. Attempts to acquire an exclusive lock
|
|
10
|
+
2. If lock is held by another process, waits and retries
|
|
11
|
+
3. Executes the operation
|
|
12
|
+
4. Releases the lock
|
|
13
|
+
|
|
14
|
+
## Lock File
|
|
15
|
+
|
|
16
|
+
The lock is implemented as a file at `{store}/.lock`:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"pid": 12345,
|
|
21
|
+
"acquired": "2026-02-12T10:00:00Z",
|
|
22
|
+
"command": "devlink publish"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Operations Requiring Lock
|
|
27
|
+
|
|
28
|
+
| Command | Requires Lock | Reason |
|
|
29
|
+
|---------|---------------|--------|
|
|
30
|
+
| `publish` | ✓ | Modifies registry.json, writes files |
|
|
31
|
+
| `push` | ✓ | Modifies registry.json, installations.json |
|
|
32
|
+
| `install` | ✓ | Modifies installations.json |
|
|
33
|
+
| `remove` | ✓ | Modifies registry.json, deletes files |
|
|
34
|
+
| `verify --fix` | ✓ | Modifies registry.json |
|
|
35
|
+
| `prune` | ✓ | Modifies registry.json, deletes files |
|
|
36
|
+
| `consumers --prune` | ✓ | Modifies installations.json |
|
|
37
|
+
| `list` | ✗ | Read-only |
|
|
38
|
+
| `resolve` | ✗ | Read-only |
|
|
39
|
+
| `verify` | ✗ | Read-only |
|
|
40
|
+
| `consumers` | ✗ | Read-only |
|
|
41
|
+
|
|
42
|
+
## Lock Parameters
|
|
43
|
+
|
|
44
|
+
| Parameter | Value | Description |
|
|
45
|
+
|-----------|-------|-------------|
|
|
46
|
+
| Timeout | 30 seconds | Maximum wait time for lock |
|
|
47
|
+
| Retry interval | 100ms | Time between retry attempts |
|
|
48
|
+
| Stale detection | 10 seconds | Lock considered stale if process is dead |
|
|
49
|
+
|
|
50
|
+
## Stale Lock Detection
|
|
51
|
+
|
|
52
|
+
If a process crashes while holding the lock, DevLink detects this by:
|
|
53
|
+
|
|
54
|
+
1. Reading the PID from the lock file
|
|
55
|
+
2. Checking if that process is still running
|
|
56
|
+
3. If process is dead, removing the stale lock
|
|
57
|
+
|
|
58
|
+
This prevents deadlocks from crashed processes.
|
|
59
|
+
|
|
60
|
+
## Concurrent Access Example
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Terminal A: devlink publish Terminal B: devlink push
|
|
64
|
+
───────────────────────────── ─────────────────────────
|
|
65
|
+
|
|
66
|
+
1. Acquire lock ✓ 1. Acquire lock
|
|
67
|
+
⏳ Store locked by PID 1234
|
|
68
|
+
2. Read registry.json
|
|
69
|
+
3. Copy files 2. Retry (100ms)
|
|
70
|
+
4. Update registry.json ⏳ Still locked
|
|
71
|
+
5. Release lock ✓
|
|
72
|
+
3. Acquire lock ✓
|
|
73
|
+
4. Continue operation...
|
|
74
|
+
5. Release lock ✓
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Troubleshooting
|
|
78
|
+
|
|
79
|
+
### Lock Timeout
|
|
80
|
+
|
|
81
|
+
If you see "Lock timeout" errors:
|
|
82
|
+
|
|
83
|
+
1. Check if another DevLink process is running
|
|
84
|
+
2. Check for stale lock files (process crashed)
|
|
85
|
+
3. Manually remove `.lock` file if necessary
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Check lock file
|
|
89
|
+
cat ~/.devlink/.lock
|
|
90
|
+
|
|
91
|
+
# Remove stale lock (use with caution)
|
|
92
|
+
rm ~/.devlink/.lock
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Multiple Repos
|
|
96
|
+
|
|
97
|
+
Each repo has its own lock file, so operations on different repos don't block each other:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# These can run simultaneously
|
|
101
|
+
devlink --repo /repo-a publish &
|
|
102
|
+
devlink --repo /repo-b publish &
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Implementation Details
|
|
106
|
+
|
|
107
|
+
The lock uses atomic file operations:
|
|
108
|
+
|
|
109
|
+
1. Create lock file with `O_EXCL` flag (fails if exists)
|
|
110
|
+
2. Write lock info (PID, timestamp, command)
|
|
111
|
+
3. On release, delete lock file
|
|
112
|
+
|
|
113
|
+
This ensures only one process can hold the lock at a time.
|
|
114
|
+
|
|
115
|
+
## See Also
|
|
116
|
+
|
|
117
|
+
- [Store Structure](structure.md) - Lock file location
|
|
118
|
+
- [Verify Command](../maintenance/verify.md) - Check store integrity
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Namespaces
|
|
2
|
+
|
|
3
|
+
Namespaces provide isolated contexts for packages, allowing multiple versions or variants of the same package to coexist.
|
|
4
|
+
|
|
5
|
+
## Concept
|
|
6
|
+
|
|
7
|
+
A namespace is a logical container for packages. Each namespace is independent, meaning:
|
|
8
|
+
|
|
9
|
+
- The same package@version can exist in multiple namespaces with different content
|
|
10
|
+
- Projects can choose which namespaces to search when resolving packages
|
|
11
|
+
- Feature branches can have their own namespace without affecting stable packages
|
|
12
|
+
|
|
13
|
+
## The Global Namespace
|
|
14
|
+
|
|
15
|
+
The `global` namespace is special:
|
|
16
|
+
|
|
17
|
+
- **Reserved**: Cannot be deleted
|
|
18
|
+
- **Default**: Used when no namespace is specified
|
|
19
|
+
- **Fallback**: Typically the last namespace in precedence order
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# These are equivalent
|
|
23
|
+
devlink publish
|
|
24
|
+
devlink publish -n global
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Creating Namespaces
|
|
28
|
+
|
|
29
|
+
Namespaces are created automatically when you publish to them:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Creates 'feature-v2' namespace if it doesn't exist
|
|
33
|
+
devlink publish -n feature-v2
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Use Cases
|
|
37
|
+
|
|
38
|
+
### Feature Branch Development
|
|
39
|
+
|
|
40
|
+
Isolate experimental changes without affecting stable packages:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Developer working on v2 API
|
|
44
|
+
cd my-sdk
|
|
45
|
+
devlink publish -n sdk-v2
|
|
46
|
+
|
|
47
|
+
# Consumer project uses sdk-v2 first, falls back to global
|
|
48
|
+
# devlink.config.mjs:
|
|
49
|
+
# namespaces: ["sdk-v2", "global"]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Team Isolation
|
|
53
|
+
|
|
54
|
+
Different teams can have their own namespaces:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
devlink publish -n team-frontend
|
|
58
|
+
devlink publish -n team-backend
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Version Testing
|
|
62
|
+
|
|
63
|
+
Test new versions before promoting to global:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Publish beta to testing namespace
|
|
67
|
+
devlink publish -n testing
|
|
68
|
+
|
|
69
|
+
# After validation, publish to global
|
|
70
|
+
devlink publish -n global
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Namespace Precedence
|
|
74
|
+
|
|
75
|
+
When resolving packages, namespaces are searched in order:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// devlink.config.mjs
|
|
79
|
+
export default {
|
|
80
|
+
dev: () => ({
|
|
81
|
+
manager: "store",
|
|
82
|
+
namespaces: ["feature-v2", "global"],
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Resolution order:
|
|
88
|
+
1. Search in `feature-v2`
|
|
89
|
+
2. If not found, search in `global`
|
|
90
|
+
3. If not found anywhere, error
|
|
91
|
+
|
|
92
|
+
### Example
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
Store contents:
|
|
96
|
+
global/@scope/core@1.0.0
|
|
97
|
+
global/@scope/utils@1.0.0
|
|
98
|
+
feature-v2/@scope/core@1.0.0 (different code)
|
|
99
|
+
|
|
100
|
+
With namespaces: ["feature-v2", "global"]
|
|
101
|
+
|
|
102
|
+
Resolving @scope/core@1.0.0:
|
|
103
|
+
→ Found in feature-v2 ✓
|
|
104
|
+
|
|
105
|
+
Resolving @scope/utils@1.0.0:
|
|
106
|
+
→ Not in feature-v2
|
|
107
|
+
→ Found in global ✓
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Listing Namespaces
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# List all packages grouped by namespace
|
|
114
|
+
devlink list
|
|
115
|
+
|
|
116
|
+
# List specific namespaces
|
|
117
|
+
devlink list -n global,feature-v2
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Removing Namespaces
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Remove entire namespace (and all packages within)
|
|
124
|
+
devlink remove feature-v2
|
|
125
|
+
|
|
126
|
+
# Note: Cannot remove 'global' namespace
|
|
127
|
+
devlink remove global # Error!
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Best Practices
|
|
131
|
+
|
|
132
|
+
1. **Use descriptive names**: `feature-auth-v2`, `team-mobile`, `release-candidate`
|
|
133
|
+
2. **Clean up old namespaces**: Remove namespaces when feature branches are merged
|
|
134
|
+
3. **Keep global stable**: Only publish tested packages to global
|
|
135
|
+
4. **Document namespace usage**: Let team members know which namespaces to use
|
|
136
|
+
|
|
137
|
+
## See Also
|
|
138
|
+
|
|
139
|
+
- [Store Structure](structure.md) - How namespaces are stored on disk
|
|
140
|
+
- [Resolve Command](../inspection/resolve.md) - Debug namespace resolution
|
|
141
|
+
- [Configuration](../installation/configuration.md) - Configure namespace precedence
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Store Structure
|
|
2
|
+
|
|
3
|
+
The DevLink store is a centralized repository for locally published packages.
|
|
4
|
+
|
|
5
|
+
## Default Location
|
|
6
|
+
|
|
7
|
+
By default, the store is located at:
|
|
8
|
+
|
|
9
|
+
- **Linux/macOS**: `~/.devlink/`
|
|
10
|
+
- **Windows**: `%LOCALAPPDATA%\DevLink\`
|
|
11
|
+
|
|
12
|
+
## Custom Location
|
|
13
|
+
|
|
14
|
+
You can use a custom location via:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Command line flag
|
|
18
|
+
devlink --repo /path/to/repo list
|
|
19
|
+
|
|
20
|
+
# Environment variable
|
|
21
|
+
export DEVLINK_REPO=/path/to/repo
|
|
22
|
+
devlink list
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This allows maintaining multiple independent stores for different projects or teams.
|
|
26
|
+
|
|
27
|
+
## Directory Structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
~/.devlink/ # Store root
|
|
31
|
+
├── .lock # Lock file for write serialization
|
|
32
|
+
├── registry.json # Package index (metadata)
|
|
33
|
+
├── installations.json # Consumer project tracking
|
|
34
|
+
└── namespaces/ # Package storage
|
|
35
|
+
├── global/ # Default namespace (reserved)
|
|
36
|
+
│ ├── @scope/ # Scoped packages
|
|
37
|
+
│ │ └── package-name/
|
|
38
|
+
│ │ ├── 1.0.0/ # Version directory
|
|
39
|
+
│ │ │ ├── package.json
|
|
40
|
+
│ │ │ ├── devlink.sig # Content signature
|
|
41
|
+
│ │ │ └── dist/ # Package files
|
|
42
|
+
│ │ └── 2.0.0/
|
|
43
|
+
│ └── simple-package/ # Non-scoped packages
|
|
44
|
+
│ └── 1.0.0/
|
|
45
|
+
└── feature-branch/ # Custom namespace
|
|
46
|
+
└── @scope/
|
|
47
|
+
└── package-name/
|
|
48
|
+
└── 1.0.0/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Files
|
|
52
|
+
|
|
53
|
+
### registry.json
|
|
54
|
+
|
|
55
|
+
The registry is an index of all published packages. It contains metadata but not the actual package files.
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"version": "1.0.0",
|
|
60
|
+
"namespaces": {
|
|
61
|
+
"global": {
|
|
62
|
+
"created": "2026-02-12T10:00:00Z",
|
|
63
|
+
"packages": {
|
|
64
|
+
"@scope/package": {
|
|
65
|
+
"versions": {
|
|
66
|
+
"1.0.0": {
|
|
67
|
+
"signature": "6761ca1fefdde1b6e9ea372e7d6931e4",
|
|
68
|
+
"published": "2026-02-12T10:00:00Z",
|
|
69
|
+
"files": 15
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### installations.json
|
|
80
|
+
|
|
81
|
+
Tracks which projects have installed packages from the store. Used by the `push` command to update consumers.
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"version": "1.0.0",
|
|
86
|
+
"projects": {
|
|
87
|
+
"/home/user/my-project": {
|
|
88
|
+
"registered": "2026-02-12T10:00:00Z",
|
|
89
|
+
"packages": {
|
|
90
|
+
"@scope/package": {
|
|
91
|
+
"version": "1.0.0",
|
|
92
|
+
"namespace": "global",
|
|
93
|
+
"signature": "6761ca1f...",
|
|
94
|
+
"installedAt": "2026-02-12T10:05:00Z"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### .lock
|
|
103
|
+
|
|
104
|
+
A lock file used to serialize write operations. Contains information about the process holding the lock.
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"pid": 12345,
|
|
109
|
+
"acquired": "2026-02-12T10:00:00Z",
|
|
110
|
+
"command": "devlink publish"
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### devlink.sig
|
|
115
|
+
|
|
116
|
+
Each published package version contains a signature file with an MD5 hash of the package contents. Used for integrity verification.
|
|
117
|
+
|
|
118
|
+
## Package Storage
|
|
119
|
+
|
|
120
|
+
Packages are stored in a hierarchical structure:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
namespaces/{namespace}/{package-name}/{version}/
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
For scoped packages:
|
|
127
|
+
```
|
|
128
|
+
namespaces/{namespace}/@{scope}/{package-name}/{version}/
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Each version directory contains:
|
|
132
|
+
- `package.json` - Package manifest
|
|
133
|
+
- `devlink.sig` - Content signature
|
|
134
|
+
- All files specified in the package's `files` field
|
|
135
|
+
|
|
136
|
+
## Multiple Versions
|
|
137
|
+
|
|
138
|
+
Multiple versions of the same package can coexist:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
namespaces/global/@scope/core/
|
|
142
|
+
├── 1.0.0/
|
|
143
|
+
├── 1.1.0/
|
|
144
|
+
└── 2.0.0/
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Multiple Namespaces
|
|
148
|
+
|
|
149
|
+
The same package can exist in different namespaces with different content:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
namespaces/
|
|
153
|
+
├── global/
|
|
154
|
+
│ └── @scope/core/1.0.0/ # Stable version
|
|
155
|
+
└── feature-v2/
|
|
156
|
+
└── @scope/core/1.0.0/ # Development version (different code)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## See Also
|
|
160
|
+
|
|
161
|
+
- [Namespaces](namespaces.md) - Understanding namespace isolation
|
|
162
|
+
- [File Locking](locking.md) - Concurrency control
|
|
163
|
+
- [Publish Command](../publishing/publish.md) - Publishing packages
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unlimitechcloud/devlink",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Local package development and linking tool with namespace support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"devlink": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"docs",
|
|
20
|
+
"AGENTS.md"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/unlimitechcloud/devlink.git"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage",
|
|
32
|
+
"prepublishOnly": "npm run build",
|
|
33
|
+
"publish:local": "node dist/cli.js publish"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"npm",
|
|
37
|
+
"link",
|
|
38
|
+
"local",
|
|
39
|
+
"development",
|
|
40
|
+
"monorepo",
|
|
41
|
+
"packages",
|
|
42
|
+
"dependencies"
|
|
43
|
+
],
|
|
44
|
+
"author": "UnlimitechCloud",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
49
|
+
"typescript": "^5.5.0",
|
|
50
|
+
"vitest": "^2.0.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"cli-color": "^2.0.0"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.0.0"
|
|
57
|
+
}
|
|
58
|
+
}
|