npmdata 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -9
- package/dist/npmdata-0.0.1.tgz +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,260 @@
|
|
|
1
|
-
# npmdata
|
|
1
|
+
# npmdata
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Publish folders as npm packages and extract them in any workspace. Use it to distribute shared assets — ML datasets, documentation, ADRs, configuration files — across multiple projects through any npm-compatible registry.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
- **Publisher**: a project that has folders to share. Running `init` prepares its `package.json` so those folders are included when the package is published.
|
|
8
|
+
- **Consumer**: any project that installs that package and runs `extract` to download the files locally. A `.publisher` marker file is written alongside the managed files to track ownership and enable safe updates.
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
### 1. Prepare the publisher package
|
|
13
|
+
|
|
14
|
+
In the project whose folders you want to share:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
pnpm dlx npmdata init --folders "docs,data,configs"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This updates `package.json` with the right `files`, `bin`, and `dependencies` fields so those folders are included when the package is published. Then publish normally:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm publish
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Extract files in a consumer project
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
# extract all files from the package
|
|
30
|
+
npx npmdata extract --packages my-shared-assets --output ./data
|
|
31
|
+
|
|
32
|
+
# extract from a specific version
|
|
33
|
+
npx npmdata extract --packages my-shared-assets@^2.0.0 --output ./data
|
|
34
|
+
|
|
35
|
+
# extract from multiple packages at once
|
|
36
|
+
npx npmdata extract --packages "my-shared-assets@^2.0.0,another-pkg@1.x" --output ./data
|
|
37
|
+
|
|
38
|
+
# extract only markdown files
|
|
39
|
+
npx npmdata extract --packages my-shared-assets --files "**/*.md" --output ./docs
|
|
40
|
+
|
|
41
|
+
# extract only files whose content matches a regex
|
|
42
|
+
npx npmdata extract --packages my-shared-assets --content-regex "env: production" --output ./configs
|
|
43
|
+
|
|
44
|
+
# overwrite files that are unmanaged or owned by a different package;
|
|
45
|
+
# the new package takes ownership in the marker file
|
|
46
|
+
npx npmdata extract --packages my-shared-assets --output ./data --force
|
|
47
|
+
|
|
48
|
+
# also write .gitignore entries for managed files
|
|
49
|
+
npx npmdata extract --packages my-shared-assets --output ./data --gitignore
|
|
50
|
+
|
|
51
|
+
# preview what would change without writing any files
|
|
52
|
+
npx npmdata extract --packages my-shared-assets --output ./data --dry-run
|
|
53
|
+
|
|
54
|
+
# force-reinstall the package even if already installed (e.g. after a floating tag moves)
|
|
55
|
+
npx npmdata extract --packages my-shared-assets@latest --output ./data --upgrade
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`extract` logs every file change as it happens:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
A data/users-dataset/user1.json
|
|
62
|
+
M data/configs/app.config.json
|
|
63
|
+
D data/old-file.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If the published package includes its own bin script (normally when it's prepared using "init") you can also call it directly so it extracts data that is inside the package itself:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
npx my-shared-assets extract --output ./data
|
|
70
|
+
npx my-shared-assets check --output ./data
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Check the /examples folder to see this in action
|
|
74
|
+
|
|
75
|
+
### 3. Check files are in sync
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx npmdata check --packages my-shared-assets --output ./data
|
|
79
|
+
# exit 0 = in sync, exit 2 = differences found
|
|
80
|
+
|
|
81
|
+
# check multiple packages
|
|
82
|
+
npx npmdata check --packages "my-shared-assets,another-pkg" --output ./data
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The check command reports differences per package:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
my-shared-assets@^2.0.0 FAIL
|
|
89
|
+
missing: data/new-file.json
|
|
90
|
+
modified: data/configs/app.config.json
|
|
91
|
+
extra: data/old-file.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. List managed files
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
# list all files managed by npmdata in an output directory
|
|
98
|
+
npx npmdata list --output ./data
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Output is grouped by package:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
my-shared-assets@2.1.0
|
|
105
|
+
data/users-dataset/user1.json
|
|
106
|
+
data/configs/app.config.json
|
|
107
|
+
|
|
108
|
+
another-pkg@1.0.0
|
|
109
|
+
data/other-file.txt
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## CLI reference
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Usage:
|
|
116
|
+
npx npmdata [init|extract|check|list] [options]
|
|
117
|
+
|
|
118
|
+
Commands:
|
|
119
|
+
init Set up publishing configuration in a package
|
|
120
|
+
extract Extract files from a published package into a local directory
|
|
121
|
+
check Verify local files are in sync with the published package
|
|
122
|
+
list List all files managed by npmdata in an output directory
|
|
123
|
+
|
|
124
|
+
Global options:
|
|
125
|
+
--help, -h Show help
|
|
126
|
+
--version, -v Show version
|
|
127
|
+
|
|
128
|
+
Init options:
|
|
129
|
+
--folders <list> Comma-separated folders to publish (required)
|
|
130
|
+
|
|
131
|
+
Extract options:
|
|
132
|
+
--packages <specs> Comma-separated package specs (required).
|
|
133
|
+
Each spec is "name" or "name@version", e.g.
|
|
134
|
+
"my-pkg@^1.0.0,other-pkg@2.x"
|
|
135
|
+
--output, -o <dir> Output directory (default: current directory)
|
|
136
|
+
--force Overwrite existing unmanaged files or files owned by a different package
|
|
137
|
+
--gitignore Create/update .gitignore for managed files
|
|
138
|
+
--files <patterns> Comma-separated glob patterns to filter files
|
|
139
|
+
--content-regex <regex> Regex to filter files by content
|
|
140
|
+
--dry-run Preview changes without writing any files
|
|
141
|
+
--upgrade Reinstall the package even if already present
|
|
142
|
+
|
|
143
|
+
Check options:
|
|
144
|
+
--packages <specs> Same format as extract (required)
|
|
145
|
+
--output, -o <dir> Output directory to check (default: current directory)
|
|
146
|
+
|
|
147
|
+
List options:
|
|
148
|
+
--output, -o <dir> Output directory to inspect (default: current directory)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Library usage
|
|
152
|
+
|
|
153
|
+
`npmdata` also exports a programmatic API:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { extract, check, list, initPublisher, parsePackageSpec, isBinaryFile } from 'npmdata';
|
|
157
|
+
import type { ConsumerConfig, ConsumerResult, CheckResult, ProgressEvent } from 'npmdata';
|
|
158
|
+
|
|
159
|
+
// extract files from one package
|
|
160
|
+
const result = await extract({
|
|
161
|
+
packages: ['my-shared-assets@^2.0.0'],
|
|
162
|
+
outputDir: './data',
|
|
163
|
+
gitignore: true,
|
|
164
|
+
});
|
|
165
|
+
console.log(result.added, result.modified, result.deleted);
|
|
166
|
+
|
|
167
|
+
// dry-run: preview changes without writing files
|
|
168
|
+
const preview = await extract({
|
|
169
|
+
packages: ['my-shared-assets@^2.0.0'],
|
|
170
|
+
outputDir: './data',
|
|
171
|
+
dryRun: true,
|
|
172
|
+
});
|
|
173
|
+
console.log('Would add', preview.added, 'files');
|
|
174
|
+
|
|
175
|
+
// force-reinstall the package even if already present
|
|
176
|
+
await extract({
|
|
177
|
+
packages: ['my-shared-assets@latest'],
|
|
178
|
+
outputDir: './data',
|
|
179
|
+
upgrade: true,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// track progress file-by-file
|
|
183
|
+
await extract({
|
|
184
|
+
packages: ['my-shared-assets@^2.0.0'],
|
|
185
|
+
outputDir: './data',
|
|
186
|
+
onProgress: (event: ProgressEvent) => {
|
|
187
|
+
if (event.type === 'file-added') console.log('A', event.file);
|
|
188
|
+
if (event.type === 'file-modified') console.log('M', event.file);
|
|
189
|
+
if (event.type === 'file-deleted') console.log('D', event.file);
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// extract files from multiple packages into the same output directory
|
|
194
|
+
const multiResult = await extract({
|
|
195
|
+
packages: ['my-shared-assets@^2.0.0', 'another-pkg@1.x'],
|
|
196
|
+
outputDir: './data',
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// check sync status — per-package breakdown
|
|
200
|
+
const status = await check({
|
|
201
|
+
packages: ['my-shared-assets'],
|
|
202
|
+
outputDir: './data',
|
|
203
|
+
});
|
|
204
|
+
if (!status.ok) {
|
|
205
|
+
console.log('Overall differences:', status.differences);
|
|
206
|
+
for (const pkg of status.sourcePackages) {
|
|
207
|
+
if (!pkg.ok) {
|
|
208
|
+
console.log(pkg.name, 'missing:', pkg.differences.missing);
|
|
209
|
+
console.log(pkg.name, 'modified:', pkg.differences.modified);
|
|
210
|
+
console.log(pkg.name, 'extra:', pkg.differences.extra);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// list all files managed by npmdata in an output directory
|
|
216
|
+
const managed = await list('./data');
|
|
217
|
+
// managed is Record<string, string[]> keyed by "package@version"
|
|
218
|
+
|
|
219
|
+
// initialize a publisher package
|
|
220
|
+
await initPublisher(['docs', 'data'], { workingDir: './my-package' });
|
|
221
|
+
|
|
222
|
+
// utility: parse a package spec string
|
|
223
|
+
const { name, version } = parsePackageSpec('my-pkg@^1.0.0');
|
|
224
|
+
|
|
225
|
+
// utility: detect whether a file is binary
|
|
226
|
+
const binary = isBinaryFile('/path/to/file.bin');
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### `ProgressEvent` type
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
type ProgressEvent =
|
|
233
|
+
| { type: 'package-start'; packageName: string; packageVersion: string }
|
|
234
|
+
| { type: 'package-end'; packageName: string; packageVersion: string }
|
|
235
|
+
| { type: 'file-added'; packageName: string; file: string }
|
|
236
|
+
| { type: 'file-modified'; packageName: string; file: string }
|
|
237
|
+
| { type: 'file-deleted'; packageName: string; file: string }
|
|
238
|
+
| { type: 'file-skipped'; packageName: string; file: string };
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
See [lib/README.md](lib/README.md) for the full API reference.
|
|
242
|
+
|
|
243
|
+
## Managed file tracking
|
|
244
|
+
|
|
245
|
+
Extracted files are set read-only (`444`) and tracked in a `.publisher` marker file in each output directory. On subsequent extractions:
|
|
246
|
+
|
|
247
|
+
- Unchanged files are skipped.
|
|
248
|
+
- Updated files are overwritten.
|
|
249
|
+
- Files removed from the package are deleted locally.
|
|
250
|
+
|
|
251
|
+
The marker file uses a `|`-delimited format; files written by older versions of `npmdata` using the comma-delimited format are read correctly for backward compatibility.
|
|
252
|
+
|
|
253
|
+
Multiple packages can coexist in the same output directory; each owns its own files.
|
|
254
|
+
|
|
255
|
+
## Developer Notes
|
|
256
|
+
|
|
257
|
+
### Module overview
|
|
6
258
|
|
|
7
259
|
| Module | Purpose |
|
|
8
260
|
|---|---|
|
|
@@ -13,11 +265,11 @@ This document covers the internal architecture for contributors working on this
|
|
|
13
265
|
| `utils.ts` | File I/O helpers: glob matching via `minimatch`, SHA-256 hashing, CSV marker read/write, package manager detection |
|
|
14
266
|
| `types.ts` | Shared TypeScript types and constants (e.g. `DEFAULT_FILENAME_PATTERNS`) |
|
|
15
267
|
|
|
16
|
-
|
|
268
|
+
### Publish side (`publisher.ts`)
|
|
17
269
|
|
|
18
270
|
`initPublisher()` modifies the target `package.json` to include `files`, `bin`, and `dependencies` fields, then writes a thin `bin/npmdata.js` that calls `runner.run(__dirname)`. The generated script is kept minimal on purpose — all logic lives in this library.
|
|
19
271
|
|
|
20
|
-
|
|
272
|
+
### Consumer side (`consumer.ts`)
|
|
21
273
|
|
|
22
274
|
`extract()` flow:
|
|
23
275
|
1. Detects the package manager (`pnpm` / `yarn` / `npm`) via lock-file presence.
|
|
@@ -28,19 +280,18 @@ This document covers the internal architecture for contributors working on this
|
|
|
28
280
|
|
|
29
281
|
`check()` performs the same resolution for each package in `config.packages` but compares SHA-256 hashes without writing any files.
|
|
30
282
|
|
|
31
|
-
|
|
283
|
+
### Marker file (`.publisher`)
|
|
32
284
|
|
|
33
285
|
Each output directory that contains managed files gets a `.publisher` CSV file. Columns: `path`, `packageName`, `packageVersion`, `sha256`. This is the source of truth for drift detection and clean removal.
|
|
34
286
|
|
|
35
|
-
|
|
287
|
+
### Key design decisions
|
|
36
288
|
|
|
37
289
|
- No runtime dependencies beyond `semver` and `minimatch` to keep the consumer install footprint small.
|
|
38
290
|
- File identity is tracked by path + hash, not by timestamp, to be deterministic across machines.
|
|
39
291
|
- The bin script generated by `initPublisher` contains no logic; all behaviour is versioned inside this library.
|
|
40
292
|
|
|
41
|
-
|
|
293
|
+
### Dev workflow
|
|
42
294
|
|
|
43
295
|
```
|
|
44
296
|
make build lint-fix test
|
|
45
297
|
```
|
|
46
|
-
|
package/dist/npmdata-0.0.1.tgz
CHANGED
|
Binary file
|