knarr 0.0.1

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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -0
  3. package/dist/add-ODK52RZI.mjs +3 -0
  4. package/dist/bell-YD6IWNXO.mjs +2 -0
  5. package/dist/check-YVEJEI2G.mjs +6 -0
  6. package/dist/chokidar-LVDD2IK4.mjs +4 -0
  7. package/dist/chunk-23HXXAGG.mjs +5 -0
  8. package/dist/chunk-2EZDTBUU.mjs +3 -0
  9. package/dist/chunk-2GDRDQA5.mjs +3 -0
  10. package/dist/chunk-2QPLXLJW.mjs +3 -0
  11. package/dist/chunk-2VCW5RWI.mjs +3 -0
  12. package/dist/chunk-3KNUBUPH.mjs +3 -0
  13. package/dist/chunk-7DZPDPP6.mjs +3 -0
  14. package/dist/chunk-7HVPEBK5.mjs +7 -0
  15. package/dist/chunk-7JG555TZ.mjs +3 -0
  16. package/dist/chunk-B3DZ5HVQ.mjs +3 -0
  17. package/dist/chunk-BS4VKVYH.mjs +3 -0
  18. package/dist/chunk-FU7FCNTW.mjs +3 -0
  19. package/dist/chunk-FUINO5RD.mjs +3 -0
  20. package/dist/chunk-HQ7NKBQW.mjs +4 -0
  21. package/dist/chunk-IM555H3S.mjs +4 -0
  22. package/dist/chunk-KXLQGVT2.mjs +13 -0
  23. package/dist/chunk-MBKCCWSD.mjs +3 -0
  24. package/dist/chunk-NBSJGM2X.mjs +3 -0
  25. package/dist/chunk-OLUZ7T7G.mjs +3 -0
  26. package/dist/chunk-OXI2KGCW.mjs +14 -0
  27. package/dist/chunk-SFLWVTJC.mjs +3 -0
  28. package/dist/chunk-SYADAYF4.mjs +3 -0
  29. package/dist/chunk-TEFMLGCB.mjs +3 -0
  30. package/dist/chunk-U5ZZAYNU.mjs +13 -0
  31. package/dist/chunk-V2ED74ZQ.mjs +3 -0
  32. package/dist/chunk-XQPVRRTN.mjs +3 -0
  33. package/dist/chunk-XQVMCMO7.mjs +7 -0
  34. package/dist/chunk-YZCBBQCH.mjs +19 -0
  35. package/dist/chunk-Z22BYXWQ.mjs +3 -0
  36. package/dist/clean-XMLDIZDZ.mjs +3 -0
  37. package/dist/cli.mjs +10 -0
  38. package/dist/dev-7L35BV6M.mjs +3 -0
  39. package/dist/doctor-4TTAYNGW.mjs +4 -0
  40. package/dist/fs-35635IS7.mjs +2 -0
  41. package/dist/history-XUZSDCNE.mjs +2 -0
  42. package/dist/index.d.ts +434 -0
  43. package/dist/index.mjs +3530 -0
  44. package/dist/init-OBJFQ6OB.mjs +7 -0
  45. package/dist/list-AQKUBZ2I.mjs +5 -0
  46. package/dist/migrate-7B7ACQHY.mjs +8 -0
  47. package/dist/preflight-TVJFHRI2.mjs +2 -0
  48. package/dist/publish-Q4JYQPQP.mjs +3 -0
  49. package/dist/push-NHCPN6MO.mjs +3 -0
  50. package/dist/remove-PDERBH66.mjs +2 -0
  51. package/dist/reset-3FXWAAPQ.mjs +3 -0
  52. package/dist/restore-YGPO42W4.mjs +11 -0
  53. package/dist/rollback-FKNGLGFC.mjs +3 -0
  54. package/dist/status-3VUPPR5D.mjs +4 -0
  55. package/dist/tailwind-source-ND5FE6PQ.mjs +5 -0
  56. package/dist/topo-sort-WEIVPJKN.mjs +2 -0
  57. package/dist/tracker-R4ZZIDJV.mjs +2 -0
  58. package/dist/update-QPBWYDSG.mjs +3 -0
  59. package/dist/use-NKLXGPIZ.mjs +3 -0
  60. package/dist/vite-config-URP2SYRQ.mjs +2 -0
  61. package/dist/vite-plugin.d.ts +5 -0
  62. package/dist/vite-plugin.mjs +215 -0
  63. package/dist/watch-orchestrator-F6S5WQQX.mjs +3 -0
  64. package/dist/watcher-PTPUN2HE.mjs +3 -0
  65. package/dist/webpack-plugin.d.ts +47 -0
  66. package/dist/webpack-plugin.mjs +143 -0
  67. package/dist/workspace-L5CGPK7U.mjs +2 -0
  68. package/dist/xxhash-wasm-DTW44IIQ.mjs +3 -0
  69. package/package.json +126 -0
@@ -0,0 +1,434 @@
1
+ interface PublishOptions {
2
+ allowPrivate?: boolean;
3
+ /** Whether to run prepack/postpack lifecycle hooks (default: true) */
4
+ runScripts?: boolean;
5
+ /** Force publish, bypassing hash comparison */
6
+ force?: boolean;
7
+ /** Max historical builds to keep (default: 3). Set to 0 to disable. */
8
+ historyLimit?: number;
9
+ }
10
+ interface PublishResult {
11
+ name: string;
12
+ version: string;
13
+ fileCount: number;
14
+ /** True if content was unchanged and publish was skipped */
15
+ skipped: boolean;
16
+ contentHash: string;
17
+ /** 8-char hex identifier generated on each successful publish */
18
+ buildId: string;
19
+ }
20
+ /**
21
+ * Publish a package from a directory to the Knarr store.
22
+ *
23
+ * 1. Read package.json, validate name and version
24
+ * 2. Resolve publishable files
25
+ * 3. Compute content hash
26
+ * 4. Skip if hash matches existing store entry
27
+ * 5. Copy files to temp dir, then atomic rename to store
28
+ * 6. Write .knarr-meta.json
29
+ */
30
+ declare function publish(packageDir: string, options?: PublishOptions): Promise<PublishResult>;
31
+
32
+ /** Metadata stored alongside each package in the Knarr store */
33
+ interface KnarrMeta {
34
+ schemaVersion?: number;
35
+ contentHash: string;
36
+ publishedAt: string;
37
+ sourcePath: string;
38
+ /** 8-char hex ID derived from content hash. Missing in pre-buildId store entries. */
39
+ buildId?: string;
40
+ }
41
+ /** A store entry representing a published package */
42
+ interface StoreEntry {
43
+ name: string;
44
+ version: string;
45
+ packageDir: string;
46
+ meta: KnarrMeta;
47
+ }
48
+ /** Tracks a single linked package in a consumer project */
49
+ interface LinkEntry {
50
+ version: string;
51
+ contentHash: string;
52
+ linkedAt: string;
53
+ sourcePath: string;
54
+ backupExists: boolean;
55
+ packageManager: PackageManager;
56
+ /** 8-char hex ID. Missing in pre-buildId state files. */
57
+ buildId?: string;
58
+ }
59
+ /** Consumer project state file (.knarr/state.json) */
60
+ interface ConsumerState {
61
+ version: "1";
62
+ packageManager?: PackageManager;
63
+ role?: "consumer" | "library";
64
+ links: Record<string, LinkEntry>;
65
+ }
66
+ /** Global consumers registry (~/.knarr/consumers.json) */
67
+ interface ConsumersRegistry {
68
+ /** Maps package name → array of consumer project paths */
69
+ [packageName: string]: string[];
70
+ }
71
+ type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
72
+ /** A historical build stored in the store's history directory */
73
+ interface HistoryEntry {
74
+ buildId: string;
75
+ contentHash: string;
76
+ publishedAt: string;
77
+ sourcePath: string;
78
+ /** Path to the history entry's package directory */
79
+ packageDir: string;
80
+ }
81
+ /** Options for the watch mode */
82
+ interface WatchOptions {
83
+ /** Glob patterns to watch (default: src, lib, dist) */
84
+ patterns?: string[];
85
+ /** Build command to run before publishing */
86
+ buildCmd?: string;
87
+ /** Debounce delay in ms (default: 500) */
88
+ debounce?: number;
89
+ /** Minimum time between builds in ms (default: 500) */
90
+ cooldown?: number;
91
+ /** Ring terminal bell on push success/failure */
92
+ notify?: boolean;
93
+ /** Enable awaitWriteFinish for large/slow writes (auto-enabled when no buildCmd) */
94
+ awaitWriteFinish?: boolean | {
95
+ stabilityThreshold: number;
96
+ pollInterval: number;
97
+ };
98
+ }
99
+ /** Package.json fields we care about */
100
+ interface PackageJson {
101
+ name: string;
102
+ version: string;
103
+ files?: string[];
104
+ bin?: string | Record<string, string>;
105
+ dependencies?: Record<string, string>;
106
+ devDependencies?: Record<string, string>;
107
+ peerDependencies?: Record<string, string>;
108
+ optionalDependencies?: Record<string, string>;
109
+ peerDependenciesMeta?: Record<string, {
110
+ optional?: boolean;
111
+ }>;
112
+ main?: string;
113
+ module?: string;
114
+ exports?: unknown;
115
+ type?: string;
116
+ private?: boolean;
117
+ scripts?: Record<string, string>;
118
+ types?: string;
119
+ typings?: string;
120
+ browser?: string | Record<string, string>;
121
+ /** Corepack packageManager field, e.g. "pnpm@9.0.0" */
122
+ packageManager?: string;
123
+ publishConfig?: {
124
+ main?: string;
125
+ module?: string;
126
+ exports?: unknown;
127
+ types?: string;
128
+ typings?: string;
129
+ browser?: string | Record<string, string>;
130
+ bin?: string | Record<string, string>;
131
+ directory?: string;
132
+ };
133
+ }
134
+
135
+ interface InjectResult {
136
+ copied: number;
137
+ removed: number;
138
+ skipped: number;
139
+ binLinks: number;
140
+ }
141
+ interface InjectOptions {
142
+ /** Force copy all files, bypassing hash comparison */
143
+ force?: boolean;
144
+ }
145
+ /**
146
+ * Inject a package from the store into a consumer's node_modules.
147
+ * Strategy depends on the package manager:
148
+ * - npm/yarn/bun: direct node_modules/<pkg>/
149
+ * - pnpm: follow .pnpm/ structure
150
+ */
151
+ declare function inject(storeEntry: StoreEntry, consumerPath: string, pm: PackageManager, options?: InjectOptions): Promise<InjectResult>;
152
+ /**
153
+ * Back up the existing installed version of a package before overwriting.
154
+ */
155
+ declare function backupExisting(consumerPath: string, packageName: string, pm: PackageManager): Promise<boolean>;
156
+ /**
157
+ * Restore a backed-up package to node_modules.
158
+ */
159
+ declare function restoreBackup(consumerPath: string, packageName: string, pm: PackageManager): Promise<boolean>;
160
+ /**
161
+ * Remove an injected package from node_modules.
162
+ */
163
+ declare function removeInjected(consumerPath: string, packageName: string, pm: PackageManager): Promise<void>;
164
+ /**
165
+ * Check for missing transitive dependencies.
166
+ * Returns a list of dependency names that are in the linked package's
167
+ * dependencies but not installed in the consumer's node_modules.
168
+ */
169
+ declare function checkMissingDeps(storeEntry: StoreEntry, consumerPath: string): Promise<string[]>;
170
+
171
+ /** Get a store entry if it exists */
172
+ declare function getStoreEntry(name: string, version: string): Promise<StoreEntry | null>;
173
+ /** Find a store entry by name (any version). Returns the latest by publishedAt. */
174
+ declare function findStoreEntry(name: string): Promise<StoreEntry | null>;
175
+ /** List all entries in the store */
176
+ declare function listStoreEntries(): Promise<StoreEntry[]>;
177
+
178
+ /** Read the consumer state file, or return an empty state if not found */
179
+ declare function readConsumerState(consumerPath: string): Promise<ConsumerState>;
180
+ /**
181
+ * Read consumer state with reliability information.
182
+ * Returns `reliable: true` when the state is trustworthy (valid file or ENOENT).
183
+ * Returns `reliable: false` when the file exists but is corrupt/unreadable,
184
+ * meaning the consumer might have links we can't see.
185
+ */
186
+ declare function readConsumerStateSafe(consumerPath: string): Promise<{
187
+ state: ConsumerState;
188
+ reliable: boolean;
189
+ }>;
190
+ /** Add or update a link entry in the consumer state */
191
+ declare function addLink(consumerPath: string, packageName: string, entry: LinkEntry): Promise<void>;
192
+ /** Remove a link entry from the consumer state */
193
+ declare function removeLink(consumerPath: string, packageName: string): Promise<void>;
194
+ /** Get a specific link entry */
195
+ declare function getLink(consumerPath: string, packageName: string): Promise<LinkEntry | null>;
196
+ /** Register a consumer for a package */
197
+ declare function registerConsumer(packageName: string, consumerPath: string): Promise<void>;
198
+ /** Unregister a consumer for a package */
199
+ declare function unregisterConsumer(packageName: string, consumerPath: string): Promise<void>;
200
+ /** Get all consumers for a package */
201
+ declare function getConsumers(packageName: string): Promise<string[]>;
202
+ /**
203
+ * Clean stale consumers — remove registrations for directories that no longer exist.
204
+ * Returns the number of stale entries removed.
205
+ */
206
+ declare function cleanStaleConsumers(): Promise<{
207
+ removedConsumers: number;
208
+ removedPackages: number;
209
+ }>;
210
+
211
+ /**
212
+ * knarr configuration stored in package.json under the "knarr" key.
213
+ * Provides persistent defaults for watch/build/dev behavior.
214
+ */
215
+ interface KnarrConfig {
216
+ buildCmd?: string;
217
+ watchPatterns?: string[];
218
+ debounce?: number;
219
+ cooldown?: number;
220
+ historyLimit?: number;
221
+ notify?: boolean;
222
+ }
223
+ /**
224
+ * Load knarr configuration from package.json#knarr.
225
+ */
226
+ declare function loadKnarrConfig(projectDir: string): Promise<KnarrConfig>;
227
+
228
+ interface PushOptions {
229
+ runScripts?: boolean;
230
+ /** Force copy all files, bypassing hash comparison */
231
+ force?: boolean;
232
+ /** Max historical builds to keep per package */
233
+ historyLimit?: number;
234
+ }
235
+ /**
236
+ * Publish a package to the store, then inject into all registered consumers.
237
+ * Shared by both `push` and `dev` commands.
238
+ */
239
+ declare function doPush(packageDir: string, options?: PushOptions): Promise<void>;
240
+ /** Common CLI args shared by push --watch and dev */
241
+ interface WatchArgs {
242
+ build?: string;
243
+ "skip-build"?: boolean;
244
+ debounce?: string;
245
+ cooldown?: string;
246
+ notify?: boolean;
247
+ "no-cascade"?: boolean;
248
+ }
249
+
250
+ /**
251
+ * Push all workspace packages in topological (dependency-first) order.
252
+ * Each package is published and injected sequentially to ensure
253
+ * dependencies are available before dependents.
254
+ */
255
+ declare function doPushAll(startDir: string, options?: PushOptions): Promise<void>;
256
+
257
+ /**
258
+ * Capture the current store entry as a history entry before it gets replaced.
259
+ * Moves the old package/ and .knarr-meta.json into history/<buildId>/.
260
+ */
261
+ declare function captureHistory(name: string, version: string, oldEntryDir: string, historyLimit?: number): Promise<void>;
262
+ /**
263
+ * List all history entries for a package, sorted by publishedAt (newest first).
264
+ */
265
+ declare function listHistory(name: string, version: string): Promise<HistoryEntry[]>;
266
+ /**
267
+ * Get a specific history entry by buildId.
268
+ */
269
+ declare function getHistoryEntry(name: string, version: string, buildId: string): Promise<HistoryEntry | null>;
270
+ /**
271
+ * Restore a history entry as the current store entry.
272
+ * Moves the history entry back to the main store position.
273
+ */
274
+ declare function restoreHistoryEntry(name: string, version: string, buildId: string, historyLimit?: number): Promise<HistoryEntry | null>;
275
+ /**
276
+ * Prune history entries to keep only the most recent `limit` entries.
277
+ */
278
+ declare function pruneHistory(name: string, version: string, limit: number): Promise<number>;
279
+ /**
280
+ * Remove all history for a package.
281
+ */
282
+ declare function clearHistory(name: string, version: string): Promise<void>;
283
+ /** Resolve the effective history limit from config or default */
284
+ declare function resolveHistoryLimit(configValue?: number): number;
285
+
286
+ /** Kill the active build process if one is running */
287
+ declare function killActiveBuild(): void;
288
+ /**
289
+ * Start watching a directory for changes and trigger a callback.
290
+ *
291
+ * Uses a "debounce effects, not detection" strategy (inspired by Vite):
292
+ * - File changes are detected immediately
293
+ * - The push callback is coalesced: rapid changes within `debounceMs` are batched
294
+ * - If a push is already running when new changes arrive, a re-push is queued
295
+ * so the final state is always pushed
296
+ */
297
+ declare function startWatcher(watchDir: string, options: WatchOptions, onChange: () => Promise<void>): Promise<{
298
+ close: () => Promise<void>;
299
+ }>;
300
+ /**
301
+ * Run a build command and return true if it succeeds.
302
+ */
303
+ declare function runBuildCommand(cmd: string, cwd: string): Promise<boolean>;
304
+
305
+ /**
306
+ * Orchestrates watch mode for all workspace packages with optional
307
+ * cascading rebuilds. When a package is pushed, its dependents in
308
+ * the workspace are automatically rebuilt and pushed.
309
+ *
310
+ * State machine per package prevents infinite loops:
311
+ * idle → building → idle (normal)
312
+ * building + trigger → queued → building (coalesced)
313
+ * queued + trigger → queued (no-op)
314
+ */
315
+ declare class WatchOrchestrator {
316
+ private packages;
317
+ private dependents;
318
+ private cascade;
319
+ private pushOptions;
320
+ constructor(cascade: boolean);
321
+ start(startDir: string, args: WatchArgs, pushOptions: PushOptions): Promise<void>;
322
+ private onPackagePushed;
323
+ private requestRebuild;
324
+ close(): Promise<void>;
325
+ }
326
+
327
+ /**
328
+ * Detect the package manager used in a project directory.
329
+ * Checks `packageManager` field in package.json first (Corepack convention),
330
+ * then falls back to lockfile presence, walking up to the filesystem root.
331
+ * Closest match wins. Within the same directory, priority order is maintained.
332
+ * Falls back to "npm" if nothing is found.
333
+ */
334
+ declare function detectPackageManager(projectDir: string): Promise<PackageManager>;
335
+
336
+ /**
337
+ * Topological sort using Kahn's algorithm.
338
+ * Used to order workspace packages so dependencies are processed first.
339
+ */
340
+ declare class CycleError extends Error {
341
+ readonly cycle: string[];
342
+ constructor(cycle: string[]);
343
+ }
344
+ /**
345
+ * Sort nodes topologically (dependency-first order).
346
+ * @param graph Map of node → Set of its dependencies (nodes it depends on)
347
+ * @returns Nodes in dependency-first order
348
+ * @throws CycleError if a cycle is detected
349
+ */
350
+ declare function topoSort(graph: Map<string, Set<string>>): string[];
351
+
352
+ interface WorkspacePackage {
353
+ name: string;
354
+ version: string;
355
+ dir: string;
356
+ pkg: PackageJson;
357
+ }
358
+ interface WorkspaceGraph {
359
+ packages: WorkspacePackage[];
360
+ /** Map of package name → Set of in-workspace dependency names */
361
+ adjacency: Map<string, Set<string>>;
362
+ }
363
+ /**
364
+ * Build a workspace dependency graph for topological sorting.
365
+ * Reads all workspace packages and builds an adjacency map of
366
+ * in-workspace dependencies (both dependencies and devDependencies).
367
+ */
368
+ declare function buildWorkspaceGraph(startDir: string): Promise<WorkspaceGraph>;
369
+ /**
370
+ * Build a reverse adjacency map: for each package, which packages depend on it.
371
+ * Used by WatchOrchestrator to trigger cascading rebuilds.
372
+ */
373
+ declare function buildReverseAdjacency(adjacency: Map<string, Set<string>>): Map<string, Set<string>>;
374
+
375
+ type PreflightSeverity = "warn" | "error";
376
+ interface PreflightIssue {
377
+ code: string;
378
+ severity: PreflightSeverity;
379
+ message: string;
380
+ }
381
+ /**
382
+ * Run pre-flight validation checks on a package before publishing.
383
+ * Checks entry points, exports, types, and bin paths exist on disk.
384
+ * Returns an array of issues found (empty = all good).
385
+ */
386
+ declare function runPreflightChecks(packageDir: string): Promise<PreflightIssue[]>;
387
+
388
+ /**
389
+ * Ring the terminal bell (BEL character).
390
+ * Writes to stderr so it doesn't interfere with --json output on stdout.
391
+ */
392
+ declare function ringBell(enabled: boolean): void;
393
+
394
+ /**
395
+ * Simple timer for measuring command execution time.
396
+ */
397
+ declare class Timer {
398
+ private start;
399
+ /** Return elapsed time in ms */
400
+ elapsedMs(): number;
401
+ /** Return human-readable elapsed time (e.g., "1.2s" or "150ms") */
402
+ elapsed(): string;
403
+ }
404
+
405
+ /** Type guard for Node.js system errors with an error code */
406
+ declare function isNodeError(err: unknown): err is NodeJS.ErrnoException;
407
+
408
+ /** Normalize a file path to use forward slashes (for cross-platform consistency). */
409
+ declare function normalizePath(p: string): string;
410
+
411
+ type MutationType = "copy" | "remove" | "move" | "mkdir" | "write" | "bin-link" | "bin-unlink" | "cache-invalidate" | "lock-skip" | "lifecycle-skip";
412
+ interface DryRunMutation {
413
+ type: MutationType;
414
+ path: string;
415
+ dest?: string;
416
+ detail?: string;
417
+ }
418
+ /** Record a mutation that was skipped due to --dry-run */
419
+ declare function recordMutation(mutation: DryRunMutation): void;
420
+ /** Print a summary of all recorded dry-run mutations */
421
+ declare function printDryRunReport(): void;
422
+ /** Reset recorded mutations (for testing) */
423
+ declare function resetMutations(): void;
424
+
425
+ /**
426
+ * Heuristic to detect configs that are too complex for automatic rewriting.
427
+ * Returns null if safe to rewrite, or a reason string if too complex.
428
+ */
429
+ declare function isComplexConfig(content: string): {
430
+ complex: boolean;
431
+ reason?: string;
432
+ };
433
+
434
+ export { type ConsumerState, type ConsumersRegistry, CycleError, type DryRunMutation, type HistoryEntry, type InjectOptions, type InjectResult, type KnarrConfig, type KnarrMeta, type LinkEntry, type MutationType, type PackageJson, type PackageManager, type PreflightIssue, type PreflightSeverity, type PublishOptions, type PublishResult, type PushOptions, type StoreEntry, Timer, type WatchOptions, WatchOrchestrator, type WorkspaceGraph, type WorkspacePackage, addLink, backupExisting, buildReverseAdjacency, buildWorkspaceGraph, captureHistory, checkMissingDeps, cleanStaleConsumers, clearHistory, detectPackageManager, doPush, doPushAll, findStoreEntry, getConsumers, getHistoryEntry, getLink, getStoreEntry, inject, isComplexConfig, isNodeError, killActiveBuild, listHistory, listStoreEntries, loadKnarrConfig, normalizePath, printDryRunReport, pruneHistory, publish, readConsumerState, readConsumerStateSafe, recordMutation, registerConsumer, removeInjected, removeLink, resetMutations, resolveHistoryLimit, restoreBackup, restoreHistoryEntry, ringBell, runBuildCommand, runPreflightChecks, startWatcher, topoSort, unregisterConsumer };