@rigxyz/tapd 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -65,6 +65,12 @@ type WalkResult = {
65
65
  };
66
66
  declare function walk(rootDir: string, opts: {
67
67
  ignore: Ignore;
68
+ /**
69
+ * Mount points (posix, relative to rootDir) to hard-exclude — import
70
+ * subdirectories materialized by mirror subscriptions. Never scanned,
71
+ * never uploaded into this binding. Non-overridable by .tapignore.
72
+ */
73
+ excludePaths?: ReadonlyArray<string>;
68
74
  }): WalkResult;
69
75
 
70
76
  /**
@@ -121,7 +127,14 @@ declare class RelayClient {
121
127
  prepareUpload(body: PrepareUploadRequest): Promise<PrepareUploadResponse>;
122
128
  completeUpload(body: CompleteUploadRequest): Promise<CompleteUploadResponse>;
123
129
  downloadUrl(hash: string): Promise<DownloadUrlResponse>;
124
- /** PUT bytes to a presigned URL. Throws on non-2xx. */
130
+ /**
131
+ * PUT bytes to a presigned URL. Throws on non-2xx — except 409, which
132
+ * means the content-addressed object is already stored (same hash = same
133
+ * bytes). That's idempotent success, not a conflict: two files with
134
+ * identical content (e.g. several empty files), or an initial upload that
135
+ * overlaps the daemon's first scan, race to PUT the same key. Treating
136
+ * 409 as fatal aborts the whole push and wedges sync at "N pending".
137
+ */
125
138
  putObjectBytes(uploadUrl: string, bytes: Uint8Array | Buffer): Promise<void>;
126
139
  /** GET bytes from a presigned URL. Throws on non-2xx. */
127
140
  getObjectBytes(downloadUrl: string): Promise<Buffer>;
@@ -414,6 +427,19 @@ declare function conflictSidecarPath(path: string, ev: {
414
427
  id: string;
415
428
  actorDeviceId: string | null;
416
429
  }): string;
430
+ /**
431
+ * Apply mode.
432
+ *
433
+ * - `primary`: the local copy has write authority. Local-divergence
434
+ * guards protect unpushed edits (sidecars, keep-on-delete, refuse to
435
+ * clobber a dir) on the assumption scanAndPush carries them upstream.
436
+ * - `mirror`: a read-only import of another binding. The mount has no
437
+ * local authority, so **remote always wins** across every event type —
438
+ * every divergence guard flips to remote-authoritative. There is no
439
+ * scanAndPush to drain sidecars or re-submit kept files, so the primary
440
+ * guards would instead let edited imported content linger forever.
441
+ */
442
+ type ApplyMode = "primary" | "mirror";
417
443
  type ApplyEventError = {
418
444
  eventId: string;
419
445
  path: string;
@@ -443,6 +469,8 @@ declare function applyOnce(opts: {
443
469
  client: RelayClient;
444
470
  stateDb: StateDb;
445
471
  limit?: number;
472
+ /** Defaults to "primary". See ApplyMode. */
473
+ mode?: ApplyMode;
446
474
  }): Promise<ApplyResult>;
447
475
 
448
476
  /**
@@ -473,8 +501,260 @@ declare function scanAndPush(opts: {
473
501
  client: RelayClient;
474
502
  stateDb: StateDb;
475
503
  ignore: Ignore;
504
+ /** Import mount points to hard-exclude from the scan. See walk(). */
505
+ excludePaths?: ReadonlyArray<string>;
476
506
  }): Promise<ScanAndPushResult>;
477
507
 
508
+ /**
509
+ * Rig imports — read-only live mirrors of another binding into a
510
+ * subdirectory (see ~/Code/rig/docs/rig-imports.md).
511
+ *
512
+ * This module owns the *declaration* side: the ImportSpec shape, on-disk
513
+ * path helpers, and the security-critical validator. The daemon wiring
514
+ * (mirror subscriptions, orchestration) lives in start.ts; the
515
+ * apply-time behavior (remote-wins) lives in applier.ts (mode: "mirror").
516
+ *
517
+ * The validator is the single highest-risk part of the feature: a bad
518
+ * mount point is how an import could silently re-share — or, because
519
+ * mirror mode is remote-authoritative, destroy — primary content. Treat
520
+ * every rule here as security code, not input hygiene.
521
+ */
522
+ type ImportSpec = {
523
+ /** Boring slug — becomes the token filename + state-db dir name. */
524
+ name: string;
525
+ bindingId: string;
526
+ relayUrl: string;
527
+ /** Per-import capability token (read + subscribe). Machine-local. */
528
+ token: string;
529
+ /** Mount point: subdirectory relative to the rig root (posix). */
530
+ path: string;
531
+ };
532
+ /**
533
+ * On-disk shape of a per-import mount file
534
+ * (`.rig/tap/imports/<name>.local.json`). Machine-local, gitignored,
535
+ * never synced — mirrors `tap-binding.local.json`. Carries the capability
536
+ * secret plus enough to start a mirror subscription without parsing
537
+ * `rig.toml` (tapd has no TOML parser; the daemon reads JSON like it does
538
+ * for the primary binding). `ops` is persisted from the accept-invite
539
+ * response so the daemon can refuse a token that lacks read+subscribe.
540
+ */
541
+ type ImportMountFile = {
542
+ bindingId: string;
543
+ relayUrl: string;
544
+ token: string;
545
+ ops: ReadonlyArray<"read" | "write" | "subscribe">;
546
+ /** Mount point: subdirectory relative to the rig root (posix). */
547
+ path: string;
548
+ /** Import-edge id from the relay (inter-rig graph). Lets `rig import remove`
549
+ * tombstone the exact edge. Absent for anonymous imports / pre-edge mounts. */
550
+ edgeId?: string;
551
+ };
552
+ type ImportValidationError = {
553
+ name: string;
554
+ path: string;
555
+ reason: string;
556
+ };
557
+ declare function validateImportName(name: string): string | null;
558
+ /**
559
+ * Canonicalize a declared import path to a posix form with `.` and empty
560
+ * segments collapsed (`./sources/alex` and `sources/./alex` → `sources/alex`).
561
+ * `..` is deliberately preserved so validateImportPath can reject it. This
562
+ * canonical form is what the daemon uses for BOTH the mirror root and the
563
+ * primary writer's exclude set — they must be byte-identical or a mirror
564
+ * could materialize at `sources/alex` while the writer excludes
565
+ * `./sources/alex` (which never matches walker paths) and re-uploads it.
566
+ */
567
+ declare function normalizeImportPath(p: string): string;
568
+ /**
569
+ * Static + symlink validation of a single mount point. Returns a reason
570
+ * string on rejection, or null if the path is a legal mount.
571
+ *
572
+ * The mount may not exist on disk yet (first materialization hasn't
573
+ * run), so we can't realpath the full path. Instead we realpath the
574
+ * nearest existing ancestor and re-attach the not-yet-created remainder,
575
+ * then assert the result stays inside the (realpathed) rig root. This
576
+ * catches a symlinked ancestor that escapes the root even before the
577
+ * mount dir exists.
578
+ */
579
+ declare function validateImportPath(rootDir: string, importPath: string): string | null;
580
+ /**
581
+ * Validate a batch of imports against each other and against the
582
+ * primary's already-tracked content. Never throws — returns the imports
583
+ * that passed plus a structured error per rejection, so the orchestrator
584
+ * can degrade a bad mount without taking down the daemon.
585
+ */
586
+ declare function validateImports(opts: {
587
+ rootDir: string;
588
+ imports: ReadonlyArray<ImportSpec>;
589
+ /** Paths the primary binding already tracks (state-db listPaths). */
590
+ primaryTrackedPaths: ReadonlyArray<string>;
591
+ }): {
592
+ valid: ImportSpec[];
593
+ errors: ImportValidationError[];
594
+ };
595
+ /** `.rig/tap/state.local.db` — the primary binding's cursor/state. */
596
+ declare function primaryStateDbPath(rootDir: string): string;
597
+ /** `.rig/tap/imports/<name>/state.local.db` — per-import cursor/state. */
598
+ declare function importStateDbPath(rootDir: string, name: string): string;
599
+ /** `.rig/tap/imports` — holds `<name>.local.json` token files + `<name>/` state dirs. */
600
+ declare function importsDir(rootDir: string): string;
601
+ /** `.rig/tap/imports/<name>.local.json` — per-import token file. */
602
+ declare function importMountFile(rootDir: string, name: string): string;
603
+ declare function writeImportMount(rootDir: string, name: string, mount: ImportMountFile): void;
604
+ /**
605
+ * Read + validate a single mount file. Returns the spec on success or a
606
+ * structured reason on failure — never throws, so one broken mount can be
607
+ * degraded without taking down the daemon (gotcha #7).
608
+ */
609
+ declare function readImportMount(rootDir: string, name: string): {
610
+ ok: true;
611
+ spec: ImportSpec;
612
+ } | {
613
+ ok: false;
614
+ reason: string;
615
+ };
616
+ /**
617
+ * Enumerate `.rig/tap/imports/*.local.json` and resolve each to an
618
+ * ImportSpec. Broken mount files are reported, not thrown. This is the
619
+ * daemon's source of truth for which mirrors to run — read fresh at every
620
+ * `tapd start` (v1 "reload" = restart).
621
+ */
622
+ declare function loadImportMounts(rootDir: string): {
623
+ ready: ImportSpec[];
624
+ broken: ImportValidationError[];
625
+ };
626
+
627
+ /**
628
+ * A single binding's apply loop: SSE subscriber + poll fallback +
629
+ * apply-mutex → applyOnce. This is the "download direction" of the
630
+ * daemon, extracted from start.ts so it can run N times — once for the
631
+ * primary binding (mode "primary") and once per import (mode "mirror").
632
+ *
633
+ * It does NOT own the watcher or scanAndPush — that "upload direction"
634
+ * stays attached only to the primary binding, in start.ts. A mirror is a
635
+ * degenerate daemon: apply-only, no uploader.
636
+ *
637
+ * Each subscription owns its own state DB (separate cursor per binding)
638
+ * and its own RelayClient. stop() closes the state DB, so the caller
639
+ * must stop any writer that shares it FIRST.
640
+ */
641
+
642
+ /** Minimal connection config — the apply side never needs deviceId. */
643
+ type SubscriptionConfig = {
644
+ bindingId: string;
645
+ relayUrl: string;
646
+ token: string;
647
+ };
648
+ type SubscriptionHandle = {
649
+ /** Stop SSE + poll, drain the in-flight apply, then close the state DB. */
650
+ stop(): Promise<void>;
651
+ /** Force one apply cycle now (through the mutex). */
652
+ applyNow(): Promise<ApplyResult>;
653
+ /** Underlying state DB. Caller MUST NOT close it — stop() does. */
654
+ stateDb: StateDb;
655
+ };
656
+ type StartSubscriptionOptions = {
657
+ /** Directory this binding materializes into (primary root, or a mount subdir). */
658
+ rootDir: string;
659
+ config: SubscriptionConfig;
660
+ /** Separate db per binding → separate cursor. */
661
+ stateDbPath: string;
662
+ mode: ApplyMode;
663
+ fetch?: typeof fetch;
664
+ pollSeconds?: number;
665
+ /** Test seam — disable SSE (poll-only). */
666
+ noSse?: boolean;
667
+ sseHeartbeatTimeoutMs?: number;
668
+ };
669
+ declare function startSubscription(opts: StartSubscriptionOptions): Promise<SubscriptionHandle>;
670
+
671
+ /**
672
+ * `tapd import` — accept an invite to another binding and mount it
673
+ * read-only into a subdirectory of this rig (see rig-imports.md).
674
+ *
675
+ * Mirror of `join.ts`, but instead of making this folder a binding root
676
+ * it writes a per-import mount file (`.rig/tap/imports/<name>.local.json`)
677
+ * that the daemon picks up as a mirror subscription. Nothing about the
678
+ * primary binding (if any) changes.
679
+ *
680
+ * 1. Canonicalize + validate the mount (name slug, path, symlink/parent
681
+ * collisions, overlap with other mounts + primary content) BEFORE any
682
+ * network call — reusing validateImports so the rules can't drift.
683
+ * 2. Parse the invite URL → (baseUrl, secret).
684
+ * 3. acceptInvite → { bindingId, token: { secret, ops } }.
685
+ * 4. Refuse a token without read+subscribe (a mirror can't run on it).
686
+ * 5. Write the mount file (mode 0600). The daemon must be (re)started to
687
+ * pick it up — v1 "reload" = restart.
688
+ */
689
+ declare class ImportValidationFailed extends Error {
690
+ readonly reason: string;
691
+ constructor(reason: string);
692
+ }
693
+ declare class ImportTokenScopeError extends Error {
694
+ readonly ops?: ReadonlyArray<string> | undefined;
695
+ constructor(ops?: ReadonlyArray<string> | undefined);
696
+ }
697
+ type AddImportOptions = {
698
+ rootDir: string;
699
+ inviteUrl: string;
700
+ /** Mount point (subdir, relative to the rig root). */
701
+ path: string;
702
+ /** Slug; defaults to the last path segment. */
703
+ name?: string;
704
+ accessToken?: string | null;
705
+ deviceLabel?: string;
706
+ fetch?: typeof fetch;
707
+ };
708
+ type AddImportResult = {
709
+ name: string;
710
+ path: string;
711
+ bindingId: string;
712
+ ops: ReadonlyArray<"read" | "write" | "subscribe">;
713
+ /** Import-edge id recorded by the relay (absent for anonymous imports). */
714
+ edgeId?: string;
715
+ /** False when we sent our binding as the importer but the relay couldn't
716
+ * verify membership — the edge was recorded as a personal import (you → S),
717
+ * not rig → S. The CLI surfaces this as a warning. Undefined when we sent no
718
+ * binding (import-only) or no edge was recorded. */
719
+ importerBindingVerified?: boolean;
720
+ };
721
+ declare function addImport(opts: AddImportOptions): Promise<AddImportResult>;
722
+ /**
723
+ * Outcome of the best-effort server-side revoke half of a remove:
724
+ * - revoked — edge tombstoned + token revoked on the relay
725
+ * - not-creator — 403: the grant belongs to another user; left active
726
+ * - gone — 404: already revoked/removed server-side
727
+ * - no-edge — anonymous / pre-edge mount; nothing to revoke
728
+ * - no-token — not logged in; can't reach the user plane (local-only)
729
+ * - offline — relay unreachable / unexpected error
730
+ */
731
+ type RemoveImportRevoke = "revoked" | "not-creator" | "gone" | "no-edge" | "no-token" | "offline";
732
+ type RemoveImportResult = {
733
+ /** False if there was no mount file by that name. */
734
+ removed: boolean;
735
+ /** The mount point that was removed (for an optional purge), if known. */
736
+ path: string | null;
737
+ /** Whether the materialized subdir was deleted (--purge). */
738
+ purged: boolean;
739
+ /** What happened to the server-side grant. */
740
+ revoke: RemoveImportRevoke;
741
+ };
742
+ /**
743
+ * Remove a mount: relinquish the grant on the relay (best-effort), then delete
744
+ * the local token file + per-import state dir. With `purge`, also delete the
745
+ * materialized subdir. The local removal ALWAYS happens — even offline, even
746
+ * when the grant isn't ours — so the daemon stops mirroring locally. The
747
+ * caller restarts the daemon. See docs/inter-rig-graph.md §7.
748
+ */
749
+ declare function removeImport(opts: {
750
+ rootDir: string;
751
+ name: string;
752
+ purge?: boolean;
753
+ /** Hub token for the self-revoke. Omit → local-only ("no-token"). */
754
+ accessToken?: string | null;
755
+ fetch?: typeof fetch;
756
+ }): Promise<RemoveImportResult>;
757
+
478
758
  /**
479
759
  * SSE consumer for the relay's /stream endpoint.
480
760
  *
@@ -518,21 +798,24 @@ type SseSubscriber = {
518
798
  declare function subscribe(opts: SseSubscriberOptions): SseSubscriber;
519
799
 
520
800
  /**
521
- * `tapd start` — the daemon main loop.
801
+ * `tapd start` — the daemon orchestrator.
802
+ *
803
+ * A daemon = N subscriptions (apply loops) + 1 writer (watcher + scan).
804
+ * - The **primary** binding gets a subscription (mode "primary") AND
805
+ * the writer: chokidar → debounced `scanAndPush` pushes local diffs
806
+ * upstream.
807
+ * - Each **import** gets an apply-only subscription (mode "mirror")
808
+ * materializing another binding into a subdirectory, read-only. No
809
+ * writer — a mirror never pushes.
522
810
  *
523
- * Three concurrent jobs (Phase 4):
524
- * - SSE subscriber: opens /v1/bindings/:id/stream and triggers
525
- * applyOnce on every push. Fast path — latency is network +
526
- * download time, not pollSeconds.
527
- * - poll loop: every `pollSeconds`, runs applyOnce as a fallback
528
- * for SSE outages (and for multi-relay deployments where the SSE
529
- * bus is single-process; see relay's event-bus.ts).
530
- * - watcher: chokidar emits add / change / unlink / addDir / unlinkDir.
531
- * Debounced rescan calls `scanAndPush` so file diffs flow upstream.
811
+ * The subscription machinery (SSE + poll + apply-mutex) lives in
812
+ * subscription.ts; this file wires the pieces together and owns the
813
+ * primary writer.
532
814
  *
533
- * All three share the state DB and the same RelayClient. Echo
534
- * suppression in `applyEvent` prevents a self-write from being applied
535
- * back over the same bytes.
815
+ * Critical invariant: import mount points are HARD-excluded from the
816
+ * primary writer (watcher `ignored` + walker `excludePaths`), so a
817
+ * mirrored subtree is never re-uploaded into the primary's own binding
818
+ * — the "accidental re-share".
536
819
  */
537
820
 
538
821
  type StartOptions = {
@@ -540,6 +823,13 @@ type StartOptions = {
540
823
  pollSeconds?: number;
541
824
  /** Quiescence window before the watcher triggers a rescan. */
542
825
  debounceMs?: number;
826
+ /**
827
+ * Read-only imports to mount into subdirectories. When omitted, the
828
+ * daemon loads them from `.rig/tap/imports/*.local.json` (the normal
829
+ * path). Pass explicitly to bypass disk loading (tests / programmatic).
830
+ * Each carries its own binding + capability token.
831
+ */
832
+ imports?: ReadonlyArray<ImportSpec>;
543
833
  /** Test seam — override fetch (passed to RelayClient + SSE subscriber). */
544
834
  fetch?: typeof fetch;
545
835
  /** Test seam — disable the chokidar watcher (poll loop only). */
@@ -549,16 +839,25 @@ type StartOptions = {
549
839
  /** SSE watchdog window in ms. Default 45s. */
550
840
  sseHeartbeatTimeoutMs?: number;
551
841
  };
842
+ /** A live import mount — exposed for status + tests. */
843
+ type ImportHandle = {
844
+ name: string;
845
+ path: string;
846
+ applyNow(): Promise<ApplyResult>;
847
+ stateDb: StateDb;
848
+ };
552
849
  type DaemonHandle = {
553
- /** Cleanly shut down the watcher + poll loop + close the state DB. */
850
+ /** Cleanly shut down the writer + every subscription + close state DBs. */
554
851
  stop(): Promise<void>;
555
- /** Force one apply cycle now. Useful for tests + `tapd status`. */
852
+ /** Force one primary apply cycle now. No-op for an import-only daemon. */
556
853
  applyNow(): Promise<ApplyResult>;
557
- /** Force one upstream scan+push now. Useful for tests + `tapd status`. */
854
+ /** Force one upstream scan+push now. No-op for an import-only daemon. */
558
855
  scanNow(): Promise<ScanAndPushResult>;
559
- /** Underlying state DB. Caller MUST NOT close it — stop() does that. */
856
+ /** Primary state DB (or first mount's, if import-only). Do NOT close it. */
560
857
  stateDb: StateDb;
858
+ /** Live import mounts, in declaration order (valid ones only). */
859
+ imports: ImportHandle[];
561
860
  };
562
861
  declare function start(opts: StartOptions): Promise<DaemonHandle>;
563
862
 
564
- export { AlreadyInitializedError, AlreadyJoinedError, type ApplyResult, BINDING_CONFIG_PATH, BUILTIN_IGNORE_LINES, type BindingConfig, type DaemonHandle, type InitOptions, type InitResult, InvalidInviteUrlError, type JoinOptions, type JoinResult, type LocalPathState, type MintInviteOptions, NotInitializedError, RelayClient, type RelayClientOptions, RelayError, STATE_KEY_CONFLICT_COUNT, type ScanAndPushResult, type SseSubscriber, type SseSubscriberOptions, type StartOptions, type StateDb, type WalkFile, type WalkResult, type WalkWarning, applyOnce, bindingConfigFile, conflictSidecarPath, createBinding, hashFile, init, isAlwaysExcluded, join, list as listInvites, loadIgnore, mint as mintInvite, openStateDb, parseInviteUrl, readBindingConfig, revoke as revokeInvite, scanAndPush, subscribe as sseSubscribe, start, walk, writeBindingConfig };
863
+ export { type AddImportOptions, type AddImportResult, AlreadyInitializedError, AlreadyJoinedError, type ApplyMode, type ApplyResult, BINDING_CONFIG_PATH, BUILTIN_IGNORE_LINES, type BindingConfig, type DaemonHandle, type ImportHandle, type ImportMountFile, type ImportSpec, ImportTokenScopeError, type ImportValidationError, ImportValidationFailed, type InitOptions, type InitResult, InvalidInviteUrlError, type JoinOptions, type JoinResult, type LocalPathState, type MintInviteOptions, NotInitializedError, RelayClient, type RelayClientOptions, RelayError, type RemoveImportResult, STATE_KEY_CONFLICT_COUNT, type ScanAndPushResult, type SseSubscriber, type SseSubscriberOptions, type StartOptions, type StartSubscriptionOptions, type StateDb, type SubscriptionConfig, type SubscriptionHandle, type WalkFile, type WalkResult, type WalkWarning, addImport, applyOnce, bindingConfigFile, conflictSidecarPath, createBinding, hashFile, importMountFile, importStateDbPath, importsDir, init, isAlwaysExcluded, join, list as listInvites, loadIgnore, loadImportMounts, mint as mintInvite, normalizeImportPath, openStateDb, parseInviteUrl, primaryStateDbPath, readBindingConfig, readImportMount, removeImport, revoke as revokeInvite, scanAndPush, subscribe as sseSubscribe, start, startSubscription, validateImportName, validateImportPath, validateImports, walk, writeBindingConfig, writeImportMount };
package/dist/index.js CHANGED
@@ -4,61 +4,93 @@ import {
4
4
  AlreadyJoinedError,
5
5
  BINDING_CONFIG_PATH,
6
6
  BUILTIN_IGNORE_LINES,
7
+ ImportTokenScopeError,
8
+ ImportValidationFailed,
7
9
  InvalidInviteUrlError,
8
10
  NotInitializedError,
9
11
  RelayClient,
10
12
  RelayError,
11
13
  STATE_KEY_CONFLICT_COUNT,
14
+ addImport,
12
15
  applyOnce,
13
16
  bindingConfigFile,
14
17
  conflictSidecarPath,
15
18
  createBinding,
16
19
  hashFile,
20
+ importMountFile,
21
+ importStateDbPath,
22
+ importsDir,
17
23
  init,
18
24
  isAlwaysExcluded,
19
25
  join,
20
26
  list,
21
27
  loadIgnore,
28
+ loadImportMounts,
22
29
  mint,
30
+ normalizeImportPath,
23
31
  openStateDb,
24
32
  parseInviteUrl,
33
+ primaryStateDbPath,
25
34
  readBindingConfig,
35
+ readImportMount,
36
+ removeImport,
26
37
  revoke,
27
38
  scanAndPush,
28
39
  start,
40
+ startSubscription,
29
41
  subscribe,
42
+ validateImportName,
43
+ validateImportPath,
44
+ validateImports,
30
45
  walk,
31
- writeBindingConfig
32
- } from "./chunk-N3KRCOBG.js";
46
+ writeBindingConfig,
47
+ writeImportMount
48
+ } from "./chunk-JBX2ZRMD.js";
33
49
  export {
34
50
  AlreadyInitializedError,
35
51
  AlreadyJoinedError,
36
52
  BINDING_CONFIG_PATH,
37
53
  BUILTIN_IGNORE_LINES,
54
+ ImportTokenScopeError,
55
+ ImportValidationFailed,
38
56
  InvalidInviteUrlError,
39
57
  NotInitializedError,
40
58
  RelayClient,
41
59
  RelayError,
42
60
  STATE_KEY_CONFLICT_COUNT,
61
+ addImport,
43
62
  applyOnce,
44
63
  bindingConfigFile,
45
64
  conflictSidecarPath,
46
65
  createBinding,
47
66
  hashFile,
67
+ importMountFile,
68
+ importStateDbPath,
69
+ importsDir,
48
70
  init,
49
71
  isAlwaysExcluded,
50
72
  join,
51
73
  list as listInvites,
52
74
  loadIgnore,
75
+ loadImportMounts,
53
76
  mint as mintInvite,
77
+ normalizeImportPath,
54
78
  openStateDb,
55
79
  parseInviteUrl,
80
+ primaryStateDbPath,
56
81
  readBindingConfig,
82
+ readImportMount,
83
+ removeImport,
57
84
  revoke as revokeInvite,
58
85
  scanAndPush,
59
86
  subscribe as sseSubscribe,
60
87
  start,
88
+ startSubscription,
89
+ validateImportName,
90
+ validateImportPath,
91
+ validateImports,
61
92
  walk,
62
- writeBindingConfig
93
+ writeBindingConfig,
94
+ writeImportMount
63
95
  };
64
96
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigxyz/tapd",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Local daemon for the hosted Tap relay — watches files, hashes content, uploads/downloads objects, applies remote changes. Pairs with @rigxyz/cli for shared-rig sync.",
5
5
  "license": "MIT",
6
6
  "author": "Dylan Bourgeois <dtsbourg@gmail.com>",
@@ -29,6 +29,13 @@
29
29
  "publishConfig": {
30
30
  "access": "public"
31
31
  },
32
+ "scripts": {
33
+ "build": "tsup",
34
+ "dev": "tsup --watch",
35
+ "typecheck": "tsc --noEmit",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest"
38
+ },
32
39
  "dependencies": {
33
40
  "better-sqlite3": "^11.5.0",
34
41
  "chokidar": "^4.0.1",
@@ -36,20 +43,13 @@
36
43
  "kleur": "^4.1.5"
37
44
  },
38
45
  "devDependencies": {
46
+ "@tap/core": "workspace:*",
47
+ "@tap/relay": "workspace:*",
39
48
  "@types/better-sqlite3": "^7.6.12",
40
49
  "@types/pg": "^8.20.0",
41
50
  "pg": "^8.21.0",
42
51
  "tsup": "^8.3.5",
43
52
  "typescript": "^5.7.2",
44
- "vitest": "^2.1.9",
45
- "@tap/core": "0.1.0",
46
- "@tap/relay": "0.1.0"
47
- },
48
- "scripts": {
49
- "build": "tsup",
50
- "dev": "tsup --watch",
51
- "typecheck": "tsc --noEmit",
52
- "test": "vitest run",
53
- "test:watch": "vitest"
53
+ "vitest": "^2.1.9"
54
54
  }
55
- }
55
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Dylan Bourgeois
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.