@superblocksteam/workspace-sync 0.0.0-stage → 2.0.178-next.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 (123) hide show
  1. package/LICENSE.txt +87 -0
  2. package/README.md +43 -2
  3. package/dist/atomic-write.d.ts +7 -0
  4. package/dist/atomic-write.d.ts.map +1 -0
  5. package/dist/atomic-write.js +33 -0
  6. package/dist/atomic-write.js.map +1 -0
  7. package/dist/branch-write-guard.d.ts +32 -0
  8. package/dist/branch-write-guard.d.ts.map +1 -0
  9. package/dist/branch-write-guard.js +38 -0
  10. package/dist/branch-write-guard.js.map +1 -0
  11. package/dist/control.d.ts +237 -0
  12. package/dist/control.d.ts.map +1 -0
  13. package/dist/control.js +242 -0
  14. package/dist/control.js.map +1 -0
  15. package/dist/dbfs-transport.d.ts +52 -0
  16. package/dist/dbfs-transport.d.ts.map +1 -0
  17. package/dist/dbfs-transport.js +21 -0
  18. package/dist/dbfs-transport.js.map +1 -0
  19. package/dist/download.d.ts +54 -0
  20. package/dist/download.d.ts.map +1 -0
  21. package/dist/download.js +475 -0
  22. package/dist/download.js.map +1 -0
  23. package/dist/draft-helpers.d.ts +114 -0
  24. package/dist/draft-helpers.d.ts.map +1 -0
  25. package/dist/draft-helpers.js +760 -0
  26. package/dist/draft-helpers.js.map +1 -0
  27. package/dist/draft-journal-store.d.ts +30 -0
  28. package/dist/draft-journal-store.d.ts.map +1 -0
  29. package/dist/draft-journal-store.js +7 -0
  30. package/dist/draft-journal-store.js.map +1 -0
  31. package/dist/draft-state-report-metrics.d.ts +5 -0
  32. package/dist/draft-state-report-metrics.d.ts.map +1 -0
  33. package/dist/draft-state-report-metrics.js +36 -0
  34. package/dist/draft-state-report-metrics.js.map +1 -0
  35. package/dist/file-draft-journal-store.d.ts +26 -0
  36. package/dist/file-draft-journal-store.d.ts.map +1 -0
  37. package/dist/file-draft-journal-store.js +123 -0
  38. package/dist/file-draft-journal-store.js.map +1 -0
  39. package/dist/flush-scheduler.d.ts +24 -0
  40. package/dist/flush-scheduler.d.ts.map +1 -0
  41. package/dist/flush-scheduler.js +36 -0
  42. package/dist/flush-scheduler.js.map +1 -0
  43. package/dist/hash-cache.d.ts +16 -0
  44. package/dist/hash-cache.d.ts.map +1 -0
  45. package/dist/hash-cache.js +62 -0
  46. package/dist/hash-cache.js.map +1 -0
  47. package/dist/hash-dir-tree.d.ts +10 -0
  48. package/dist/hash-dir-tree.d.ts.map +1 -0
  49. package/dist/hash-dir-tree.js +53 -0
  50. package/dist/hash-dir-tree.js.map +1 -0
  51. package/dist/index.d.ts +27 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +27 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/list-dir.d.ts +31 -0
  56. package/dist/list-dir.d.ts.map +1 -0
  57. package/dist/list-dir.js +153 -0
  58. package/dist/list-dir.js.map +1 -0
  59. package/dist/logger.d.ts +16 -0
  60. package/dist/logger.d.ts.map +1 -0
  61. package/dist/logger.js +16 -0
  62. package/dist/logger.js.map +1 -0
  63. package/dist/native-draft-session.d.ts +28 -0
  64. package/dist/native-draft-session.d.ts.map +1 -0
  65. package/dist/native-draft-session.js +154 -0
  66. package/dist/native-draft-session.js.map +1 -0
  67. package/dist/rpc-client.d.ts +7 -0
  68. package/dist/rpc-client.d.ts.map +1 -0
  69. package/dist/rpc-client.js +2 -0
  70. package/dist/rpc-client.js.map +1 -0
  71. package/dist/safe-directory-reader.d.ts +28 -0
  72. package/dist/safe-directory-reader.d.ts.map +1 -0
  73. package/dist/safe-directory-reader.js +136 -0
  74. package/dist/safe-directory-reader.js.map +1 -0
  75. package/dist/server-tree.d.ts +56 -0
  76. package/dist/server-tree.d.ts.map +1 -0
  77. package/dist/server-tree.js +179 -0
  78. package/dist/server-tree.js.map +1 -0
  79. package/dist/session-draft-journal-store.d.ts +42 -0
  80. package/dist/session-draft-journal-store.d.ts.map +1 -0
  81. package/dist/session-draft-journal-store.js +177 -0
  82. package/dist/session-draft-journal-store.js.map +1 -0
  83. package/dist/snapshot/take-snapshot.d.ts +41 -0
  84. package/dist/snapshot/take-snapshot.d.ts.map +1 -0
  85. package/dist/snapshot/take-snapshot.js +244 -0
  86. package/dist/snapshot/take-snapshot.js.map +1 -0
  87. package/dist/snapshot/types.d.ts +25 -0
  88. package/dist/snapshot/types.d.ts.map +1 -0
  89. package/dist/snapshot/types.js +3 -0
  90. package/dist/snapshot/types.js.map +1 -0
  91. package/dist/snapshot/upload-snapshot.d.ts +33 -0
  92. package/dist/snapshot/upload-snapshot.d.ts.map +1 -0
  93. package/dist/snapshot/upload-snapshot.js +113 -0
  94. package/dist/snapshot/upload-snapshot.js.map +1 -0
  95. package/dist/socket-dbfs-transport.d.ts +32 -0
  96. package/dist/socket-dbfs-transport.d.ts.map +1 -0
  97. package/dist/socket-dbfs-transport.js +126 -0
  98. package/dist/socket-dbfs-transport.js.map +1 -0
  99. package/dist/sync-credential-provider.d.ts +27 -0
  100. package/dist/sync-credential-provider.d.ts.map +1 -0
  101. package/dist/sync-credential-provider.js +22 -0
  102. package/dist/sync-credential-provider.js.map +1 -0
  103. package/dist/sync-engine.d.ts +119 -0
  104. package/dist/sync-engine.d.ts.map +1 -0
  105. package/dist/sync-engine.js +358 -0
  106. package/dist/sync-engine.js.map +1 -0
  107. package/dist/sync-paths.d.ts +61 -0
  108. package/dist/sync-paths.d.ts.map +1 -0
  109. package/dist/sync-paths.js +107 -0
  110. package/dist/sync-paths.js.map +1 -0
  111. package/dist/sync-telemetry.d.ts +12 -0
  112. package/dist/sync-telemetry.d.ts.map +1 -0
  113. package/dist/sync-telemetry.js +33 -0
  114. package/dist/sync-telemetry.js.map +1 -0
  115. package/dist/testing.d.ts +66 -0
  116. package/dist/testing.d.ts.map +1 -0
  117. package/dist/testing.js +180 -0
  118. package/dist/testing.js.map +1 -0
  119. package/dist/workspace-state-store.d.ts +52 -0
  120. package/dist/workspace-state-store.d.ts.map +1 -0
  121. package/dist/workspace-state-store.js +45 -0
  122. package/dist/workspace-state-store.js.map +1 -0
  123. package/package.json +59 -3
package/LICENSE.txt ADDED
@@ -0,0 +1,87 @@
1
+ Superblocks Community Software License
2
+
3
+ This Superblocks Community License Agreement (the “Agreement”) sets forth the terms on which DayZero
4
+ Software, Inc. d/b/a Superblocks (“Superblocks”) makes available certain software made available by Superblocks
5
+ under this Agreement (the “Software”). BY INSTALLING, DOWNLOADING, ACCESSING, USING OR
6
+ DISTRIBUTING ANY OF THE SOFTWARE, YOU AGREE TO THE TERMS AND CONDITIONS OF THIS
7
+ AGREEMENT.IF YOU DO NOT AGREE TO SUCH TERMS AND CONDITIONS, YOU MUST NOT USE THE
8
+ SOFTWARE. IF YOU ARE RECEIVING THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU
9
+ REPRESENT AND WARRANT THAT YOU HAVE THE ACTUAL AUTHORITY TO AGREE TO THE
10
+ TERMS AND CONDITIONS OF THIS AGREEMENT ON BEHALF OF SUCH ENTITY. “Licensee” means you,
11
+ an individual, or the entity on whose behalf you are receiving the Software.
12
+
13
+ 1. LICENSE GRANT AND CONDITIONS.
14
+
15
+ 1.1 License. Subject to the terms and conditions of this Agreement, Superblocks hereby grants to Licensee a
16
+ non-exclusive, royalty-free, worldwide, non-transferable, non-sublicenseable license during the term of this
17
+ Agreement to: (a) use the Software; (b) prepare modifications and derivative works of the Software; (c)
18
+ distribute the Software (including without limitation in source code or object code form); and (d) reproduce
19
+ copies of the Software (the “License”). Licensee is not granted the right to, and Licensee shall not, exercise the
20
+ License for an Excluded Purpose. For purposes of this Agreement, “Excluded Purpose” means making
21
+ available any software-as-a-service, platform-as-a-service, infrastructure-as-a-service or other similar online
22
+ service that competes with Superblocks’ products or services.
23
+
24
+ 1.2 Conditions. In consideration of the License, Licensee’s distribution of the Software is subject to the
25
+ following conditions:
26
+
27
+ a. Licensee must cause any Software modified by Licensee to carry prominent notices stating that Licensee
28
+ modified the Software.
29
+ b. On each Software copy, Licensee shall reproduce and not remove or alter all Superblocks or third party
30
+ copyright or other proprietary notices contained in the Software, and Licensee must provide the notice
31
+ below with each copy.
32
+
33
+ “This software is made available by DayZero Software, Inc. d/b/a Superblocks, under the terms of the
34
+ Superblocks Community License Agreement. © 2022 DayZero Software, Inc.”
35
+
36
+ 1.3 Licensee Modifications. Licensee may add its own copyright notices to modifications made by Licensee
37
+ and may provide additional or different license terms and conditions for use, reproduction, or distribution of
38
+ Licensee’s modifications. While redistributing the Software or modifications thereof, Licensee may choose to
39
+ offer, for a fee or free of charge, support, warranty, indemnity, or other obligations. Licensee, and not
40
+ Superblocks, will be responsible for any such obligations.
41
+
42
+ 1.4 No Sublicensing. The License does not include the right to sublicense the Software, however, each recipient
43
+ to which Licensee provides the Software may exercise the Licenses so long as such recipient agrees to the terms
44
+ and conditions of this Agreement.
45
+
46
+ 2. TERM AND TERMINATION. This Agreement will continue unless and until earlier terminated as set forth
47
+ herein. If Licensee breaches any of its conditions or obligations under this Agreement, this Agreement will
48
+ terminate automatically and the License will terminate automatically and permanently.
49
+
50
+ 3. INTELLECTUAL PROPERTY. As between the parties, Superblocks will retain all right, title, and interest in
51
+ the Software, and all intellectual property rights therein. Superblocks hereby reserves all rights not expressly
52
+ granted to Licensee in this Agreement. Superblocks hereby reserves all rights in its trademarks and service
53
+ marks, and no licenses therein are granted in this Agreement.
54
+
55
+ 4. DISCLAIMER. SUPERBLOCKS HEREBY DISCLAIMS ANY AND ALL WARRANTIES AND
56
+ CONDITIONS, EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY
57
+ DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
58
+ PURPOSE, WITH RESPECT TO THE SOFTWARE.
59
+
60
+ 5. LIMITATION OF LIABILITY. SUPERBLOCKS WILL NOT BE LIABLE FOR ANY DAMAGES OF
61
+ ANY KIND, INCLUDING BUT NOT LIMITED TO, LOST PROFITS OR ANY CONSEQUENTIAL,
62
+ SPECIAL, INCIDENTAL, INDIRECT, OR DIRECT DAMAGES, HOWEVER CAUSED AND ON ANY
63
+ THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. THE FOREGOING SHALL APPLY TO
64
+ THE EXTENT PERMITTED BY APPLICABLE LAW.
65
+
66
+ 6. GENERAL.
67
+
68
+ 6.1  Governing Law. This Agreement will be governed by and interpreted in accordance with the laws of the
69
+ state of California, without reference to its conflict of laws principles. If Licensee is located within the United
70
+ States, all disputes arising out of this Agreement are subject to the exclusive jurisdiction of courts located in San
71
+ Mateo County, California. USA. If Licensee is located outside of the United States, any dispute, controversy or
72
+ claim arising out of or relating to this Agreement will be referred to and finally determined by arbitration in
73
+ accordance with the JAMS International Arbitration Rules. The tribunal will consist of one neutral arbitrator.
74
+ The place of arbitration will be Palo Alto, California. The language to be used in the arbitral proceedings will be
75
+ English. Judgment upon the award rendered by the arbitrator may be entered in any court having jurisdiction
76
+ thereof.
77
+
78
+ 6.2.  Assignment. Licensee may not assign its rights under this Agreement to any third party. Superblocks may
79
+ freely assign its rights under this Agreement to any third party.
80
+
81
+ 6.3.  Other.  This Agreement is the entire agreement between the parties regarding the subject matter hereof.
82
+ No amendment or modification of this Agreement will be valid or binding upon the parties unless made in
83
+ writing and signed by the duly authorized representatives of both parties. In the event that any provision,
84
+ including without limitation any condition, of this Agreement is held to be unenforceable, this Agreement and
85
+ all licenses and rights granted hereunder will immediately terminate. Waiver by Superblocks of a breach of any
86
+ provision of this Agreement or the failure by Superblocks to exercise any right hereunder will not be construed
87
+ as a waiver of any subsequent breach of that right or as a waiver of any other right.
package/README.md CHANGED
@@ -1,3 +1,44 @@
1
- # Temporary Holding Version
1
+ # @superblocksteam/workspace-sync
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ DBFS sync primitives for an app workspace: listing and snapshotting the local
4
+ tree, uploading a snapshot, downloading a tree, draft markers, and the native
5
+ draft journal.
6
+
7
+ This is a leaf package. It depends on `@superblocksteam/shared` and
8
+ `@superblocksteam/util`, never on `vite-plugin-file-sync`, the CLI or the
9
+ server, so it can run outside the dev-server pod.
10
+
11
+ `vite-plugin-file-sync` binds its logger with `setSyncLoggerProvider`. Until a
12
+ host binds one, messages go to the console.
13
+
14
+ ## Native draft journal stores
15
+
16
+ `NativeDraftJournal` persists through a `DraftJournalStore`:
17
+
18
+ - `FileDraftJournalStore` (the default) writes one base64 JSON file to
19
+ `<root>/../.superblocks-native-drafts/<sha256(root)>.json`. This is the
20
+ live-edit layout.
21
+ - `SessionDraftJournalStore` writes a small pointer record to a session state
22
+ directory and keeps file contents as DBFS blobs referenced by content hash.
23
+ A fresh process over the same directory can still reconcile, accept or
24
+ discard a killed session's drafts.
25
+
26
+ ## Sync engine
27
+
28
+ `createWorkspaceSyncEngine` runs a workspace without the live-edit
29
+ `SyncService`, for the AgentCore microVM. DBFS is the commit point and the
30
+ session state directory is a cache, so the engine survives a kill at any step.
31
+
32
+ - `interimFlush()` uploads blobs only and never moves the branch hash.
33
+ `createFlushScheduler` runs it on the live-edit cadence (10s trailing, 30s
34
+ cap).
35
+ - `commit(source)` reconciles the draft journal, snapshots the tree, uploads
36
+ what DBFS lacks, asks the `BranchWriteGuard`, moves the branch hash, then
37
+ writes the state store, retires the journal and reports draft state.
38
+ - `rehydrate()` compares the server hash, the stored hash and the local tree
39
+ on boot and returns `fresh`, `resumed`, `replayed` or `reloaded`. A
40
+ `reloaded` tree keeps the local diff under `<stateDir>/orphaned/`.
41
+
42
+ It talks to the server only through a `DbfsTransport`. `SocketDbfsTransport`
43
+ wraps the existing socket RPCs; `FakeDbfs` from
44
+ `@superblocksteam/workspace-sync/testing` is an in-memory stand-in for tests.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Replaces `file` with `contents` so a reader sees the old or the new bytes,
3
+ * never a torn write: write a temporary sibling, fsync it, rename it over the
4
+ * target, then fsync the directory so the rename survives a crash.
5
+ */
6
+ export declare function writeFileAtomic(file: string, contents: string | Buffer, mode?: number): Promise<void>;
7
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../src/atomic-write.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,SAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CAoBf"}
@@ -0,0 +1,33 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ /**
5
+ * Replaces `file` with `contents` so a reader sees the old or the new bytes,
6
+ * never a torn write: write a temporary sibling, fsync it, rename it over the
7
+ * target, then fsync the directory so the rename survives a crash.
8
+ */
9
+ export async function writeFileAtomic(file, contents, mode = 0o600) {
10
+ const temporary = `${file}.${randomUUID()}.tmp`;
11
+ const handle = await fs.open(temporary, "wx", mode);
12
+ try {
13
+ await handle.writeFile(contents);
14
+ await handle.sync();
15
+ }
16
+ finally {
17
+ await handle.close();
18
+ }
19
+ try {
20
+ await fs.rename(temporary, file);
21
+ const directory = await fs.open(path.dirname(file), "r");
22
+ try {
23
+ await directory.sync();
24
+ }
25
+ finally {
26
+ await directory.close();
27
+ }
28
+ }
29
+ finally {
30
+ await fs.rm(temporary, { force: true });
31
+ }
32
+ }
33
+ //# sourceMappingURL=atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../src/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,QAAyB,EACzB,IAAI,GAAG,KAAK;IAEZ,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACjC,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACzB,CAAC;gBAAS,CAAC;YACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { DbfsTransport } from "./dbfs-transport.js";
2
+ export type BranchWriteRejection = "lock_not_held" | "server_moved";
3
+ /** A commit was refused before the branch hash moved. */
4
+ export declare class BranchWriteRejectedError extends Error {
5
+ readonly reason: BranchWriteRejection;
6
+ constructor(reason: BranchWriteRejection, message: string);
7
+ }
8
+ /**
9
+ * Decides whether this workspace may move the branch hash on top of
10
+ * `baseHash`. Throws {@link BranchWriteRejectedError} to refuse.
11
+ */
12
+ export interface BranchWriteGuard {
13
+ assertCanCommit(baseHash: string | undefined): Promise<void>;
14
+ }
15
+ /**
16
+ * The interim guard: the edge must hold the app branch lock (the host toggles
17
+ * {@link setLockHeld} from the edge's state snapshots), and the server hash
18
+ * must still equal the base. The compare and the set are two calls, so this
19
+ * races a concurrent writer; the branching work (#22956) replaces it with a
20
+ * server compare-and-set behind the same interface.
21
+ */
22
+ export declare class ServerHashGuard implements BranchWriteGuard {
23
+ private readonly transport;
24
+ private held;
25
+ constructor(transport: Pick<DbfsTransport, "getServerHash">, options?: {
26
+ lockHeld?: boolean;
27
+ });
28
+ get lockHeld(): boolean;
29
+ setLockHeld(held: boolean): void;
30
+ assertCanCommit(baseHash: string | undefined): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=branch-write-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-write-guard.d.ts","sourceRoot":"","sources":["../src/branch-write-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,cAAc,CAAC;AAEpE,yDAAyD;AACzD,qBAAa,wBAAyB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,MAAM,EAAE,oBAAoB;IADvC,YACW,MAAM,EAAE,oBAAoB,EACrC,OAAO,EAAE,MAAM,EAIhB;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAIpD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAH5B,OAAO,CAAC,IAAI,CAAU;IAEtB,YACmB,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,EAChE,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO,EAGrC;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE/B;IAEK,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAYjE;CACF"}
@@ -0,0 +1,38 @@
1
+ /** A commit was refused before the branch hash moved. */
2
+ export class BranchWriteRejectedError extends Error {
3
+ reason;
4
+ constructor(reason, message) {
5
+ super(message);
6
+ this.reason = reason;
7
+ this.name = "BranchWriteRejectedError";
8
+ }
9
+ }
10
+ /**
11
+ * The interim guard: the edge must hold the app branch lock (the host toggles
12
+ * {@link setLockHeld} from the edge's state snapshots), and the server hash
13
+ * must still equal the base. The compare and the set are two calls, so this
14
+ * races a concurrent writer; the branching work (#22956) replaces it with a
15
+ * server compare-and-set behind the same interface.
16
+ */
17
+ export class ServerHashGuard {
18
+ transport;
19
+ held;
20
+ constructor(transport, options = {}) {
21
+ this.transport = transport;
22
+ this.held = options.lockHeld ?? false;
23
+ }
24
+ get lockHeld() {
25
+ return this.held;
26
+ }
27
+ setLockHeld(held) {
28
+ this.held = held;
29
+ }
30
+ async assertCanCommit(baseHash) {
31
+ if (!this.held)
32
+ throw new BranchWriteRejectedError("lock_not_held", "The application branch lock is not held");
33
+ const serverHash = await this.transport.getServerHash();
34
+ if (serverHash !== baseHash)
35
+ throw new BranchWriteRejectedError("server_moved", "The application branch moved since this workspace last synced");
36
+ }
37
+ }
38
+ //# sourceMappingURL=branch-write-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-write-guard.js","sourceRoot":"","sources":["../src/branch-write-guard.ts"],"names":[],"mappings":"AAIA,yDAAyD;AACzD,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAEtC,MAAM;IADjB,YACW,MAA4B,EACrC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAUD;;;;;;GAMG;AACH,MAAM,OAAO,eAAe;IAIP,SAAS;IAHpB,IAAI,CAAU;IAEtB,YACmB,SAA+C,EAChE,OAAO,GAA2B,EAAE;yBADnB,SAAS;QAG1B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IACxC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,WAAW,CAAC,IAAa;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAA4B;QAChD,IAAI,CAAC,IAAI,CAAC,IAAI;YACZ,MAAM,IAAI,wBAAwB,CAChC,eAAe,EACf,yCAAyC,CAC1C,CAAC;QACJ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;QACxD,IAAI,UAAU,KAAK,QAAQ;YACzB,MAAM,IAAI,wBAAwB,CAChC,cAAc,EACd,+DAA+D,CAChE,CAAC;IACN,CAAC;CACF"}
@@ -0,0 +1,237 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The port the VM's ingress listens on. The builder runtime's `allowedPorts`
4
+ * must include it (AgentCore allows 8000-12000).
5
+ */
6
+ export declare const WORKSPACE_INGRESS_PORT = 8090;
7
+ /**
8
+ * Every control path on either side lives under this prefix. The edge never
9
+ * forwards a browser request under it to the VM: forwarded requests carry the
10
+ * workspace token, so a forwarded control path would be authorized.
11
+ */
12
+ export declare const WORKSPACE_CONTROL_PREFIX = "/_sb_workspace/";
13
+ /** VM ingress, edge → VM: replace the VM's copy of the edge's state. */
14
+ export declare const WORKSPACE_STATE_PATH = "/_sb_workspace/state";
15
+ /** VM ingress, edge → VM: commit the tree to DBFS now and report the result. */
16
+ export declare const WORKSPACE_COMMIT_PATH = "/_sb_workspace/commit";
17
+ /** Edge, AI service → edge: the VM's current session endpoint. */
18
+ export declare const WORKSPACE_ENDPOINT_PATH = "/_sb_workspace/endpoint";
19
+ /** Edge, VM → edge: read-only package registry proxy (prefix). */
20
+ export declare const WORKSPACE_REGISTRY_PATH = "/_sb_workspace/registry/";
21
+ /**
22
+ * Carries the workspace token on every request between the parties. Not
23
+ * `Authorization`: SigV4 owns that header on the edge → VM hop.
24
+ */
25
+ export declare const WORKSPACE_TOKEN_HEADER = "x-sb-workspace-token";
26
+ /**
27
+ * The browser's Host. The edge → VM hop must send the session endpoint's own
28
+ * Host (it is signed), so the edge moves the original here and the VM ingress
29
+ * restores it before Vite sees the request.
30
+ */
31
+ export declare const WORKSPACE_ORIGINAL_HOST_HEADER = "x-sb-original-host";
32
+ /**
33
+ * The browser's `Authorization`. SigV4 owns `Authorization` on the edge → VM
34
+ * hop, so the edge moves the browser's value here (dropping any inbound copy)
35
+ * and the VM ingress restores it before the workspace host checks it.
36
+ */
37
+ export declare const WORKSPACE_ORIGINAL_AUTHORIZATION_HEADER = "x-sb-original-authorization";
38
+ /** True when `pathname` is a control path that must not be forwarded. */
39
+ export declare function isWorkspaceControlPath(pathname: string): boolean;
40
+ /**
41
+ * The bearer token for one workspace session: the hex HMAC-SHA256 of
42
+ * `sessionKey` keyed by `secret`. Every party that holds the secret derives
43
+ * the same token, and a token derived for one session opens no other.
44
+ */
45
+ export declare function deriveWorkspaceToken(secret: string, sessionKey: string): string;
46
+ /**
47
+ * The token that authorizes endpoint reports (`PUT`
48
+ * {@link WORKSPACE_ENDPOINT_PATH}) for one session. Only parties outside the
49
+ * VM derive it: the VM holds the {@link deriveWorkspaceToken workspace
50
+ * token}, and that token must not be able to retarget the edge.
51
+ */
52
+ export declare function deriveWorkspaceEndpointToken(secret: string, sessionKey: string): string;
53
+ /**
54
+ * True when `url` is an AgentCore session endpoint in `region`: https on the
55
+ * default port, no credentials, and a host under
56
+ * `runtime.bedrock-agentcore.<region>.on.aws`.
57
+ */
58
+ export declare function isAgentCoreSessionEndpoint(url: string, region: string): boolean;
59
+ /**
60
+ * Constant-time string comparison. Both sides are hashed first so inputs of
61
+ * different lengths compare in constant time too.
62
+ */
63
+ export declare function tokensEqual(a: string, b: string): boolean;
64
+ /**
65
+ * Whether `headers` carry exactly `expected` in {@link WORKSPACE_TOKEN_HEADER}.
66
+ * A missing, repeated or empty header is rejected.
67
+ */
68
+ export declare function hasWorkspaceToken(headers: Record<string, string | string[] | undefined>, expected: string): boolean;
69
+ export declare const workspaceSyncCredentialSchema: z.ZodObject<{
70
+ token: z.ZodString;
71
+ /** Epoch milliseconds after which the server rejects the token. */
72
+ expiresAt: z.ZodNumber;
73
+ }, "strip", z.ZodTypeAny, {
74
+ token: string;
75
+ expiresAt: number;
76
+ }, {
77
+ token: string;
78
+ expiresAt: number;
79
+ }>;
80
+ export type WorkspaceSyncCredential = z.infer<typeof workspaceSyncCredentialSchema>;
81
+ /**
82
+ * Everything the VM needs from the edge, sent whole every time
83
+ * (`PUT` {@link WORKSPACE_STATE_PATH}). The edge sends it on every change and
84
+ * on a timer, so a VM that restarted inside the same session is back in sync
85
+ * within one interval without the edge noticing the restart. The VM replaces
86
+ * its copy; it never merges.
87
+ */
88
+ export declare const workspaceStateSchema: z.ZodObject<{
89
+ /** The edge holds the branch lock; without it the VM must not commit. */
90
+ lockHeld: z.ZodBoolean;
91
+ /** A user was recently active in the editor (feeds the VM's busy policy). */
92
+ userActive: z.ZodBoolean;
93
+ /** The edge is shutting down; going quiet after this is not a failure. */
94
+ draining: z.ZodBoolean;
95
+ /**
96
+ * Absent until the edge has minted one. A snapshot without one leaves the
97
+ * VM's last credential in place; the server enforces its expiry.
98
+ */
99
+ credential: z.ZodOptional<z.ZodObject<{
100
+ token: z.ZodString;
101
+ /** Epoch milliseconds after which the server rejects the token. */
102
+ expiresAt: z.ZodNumber;
103
+ }, "strip", z.ZodTypeAny, {
104
+ token: string;
105
+ expiresAt: number;
106
+ }, {
107
+ token: string;
108
+ expiresAt: number;
109
+ }>>;
110
+ }, "strip", z.ZodTypeAny, {
111
+ lockHeld: boolean;
112
+ userActive: boolean;
113
+ draining: boolean;
114
+ credential?: {
115
+ token: string;
116
+ expiresAt: number;
117
+ } | undefined;
118
+ }, {
119
+ lockHeld: boolean;
120
+ userActive: boolean;
121
+ draining: boolean;
122
+ credential?: {
123
+ token: string;
124
+ expiresAt: number;
125
+ } | undefined;
126
+ }>;
127
+ export type WorkspaceState = z.infer<typeof workspaceStateSchema>;
128
+ /**
129
+ * The VM's answer to a state snapshot. `bootId` is random per VM process, for
130
+ * logs and metrics; the edge does not branch on it.
131
+ */
132
+ export declare const workspaceStatusSchema: z.ZodObject<{
133
+ bootId: z.ZodString;
134
+ devServer: z.ZodEnum<["booting", "ready", "failed"]>;
135
+ /** Local changes not yet committed to DBFS. */
136
+ unsynced: z.ZodBoolean;
137
+ dbfsHash: z.ZodOptional<z.ZodString>;
138
+ }, "strip", z.ZodTypeAny, {
139
+ bootId: string;
140
+ devServer: "booting" | "failed" | "ready";
141
+ unsynced: boolean;
142
+ dbfsHash?: string | undefined;
143
+ }, {
144
+ bootId: string;
145
+ devServer: "booting" | "failed" | "ready";
146
+ unsynced: boolean;
147
+ dbfsHash?: string | undefined;
148
+ }>;
149
+ export type WorkspaceStatus = z.infer<typeof workspaceStatusSchema>;
150
+ /**
151
+ * The response body of `POST` {@link WORKSPACE_COMMIT_PATH}, always with
152
+ * status 200 so the edge reads one shape. `not_ready` means the workspace is
153
+ * not open or has no state snapshot yet; the edge reports it like an error.
154
+ */
155
+ export declare const workspaceCommitResultSchema: z.ZodDiscriminatedUnion<"outcome", [z.ZodObject<{
156
+ outcome: z.ZodLiteral<"committed">;
157
+ dbfsHash: z.ZodOptional<z.ZodString>;
158
+ }, "strip", z.ZodTypeAny, {
159
+ outcome: "committed";
160
+ dbfsHash?: string | undefined;
161
+ }, {
162
+ outcome: "committed";
163
+ dbfsHash?: string | undefined;
164
+ }>, z.ZodObject<{
165
+ outcome: z.ZodLiteral<"not_ready">;
166
+ reason: z.ZodString;
167
+ }, "strip", z.ZodTypeAny, {
168
+ outcome: "not_ready";
169
+ reason: string;
170
+ }, {
171
+ outcome: "not_ready";
172
+ reason: string;
173
+ }>, z.ZodObject<{
174
+ outcome: z.ZodLiteral<"error">;
175
+ error: z.ZodString;
176
+ }, "strip", z.ZodTypeAny, {
177
+ outcome: "error";
178
+ error: string;
179
+ }, {
180
+ outcome: "error";
181
+ error: string;
182
+ }>]>;
183
+ export type WorkspaceCommitResult = z.infer<typeof workspaceCommitResultSchema>;
184
+ /**
185
+ * Where the VM's ingress is reachable and how the edge authenticates to it
186
+ * (`PUT` {@link WORKSPACE_ENDPOINT_PATH}). Each `workspace.open` that returns
187
+ * a new URL sends a new one; the edge then pushes its state there.
188
+ *
189
+ * - `sigv4`: an AgentCore session endpoint. The edge signs each request and
190
+ * WebSocket handshake for `bedrock-agentcore` in `region`.
191
+ * - `none`: a local builder runtime reached directly, for development.
192
+ */
193
+ export declare const workspaceEndpointSchema: z.ZodDiscriminatedUnion<"auth", [z.ZodObject<{
194
+ auth: z.ZodLiteral<"sigv4">;
195
+ url: z.ZodEffects<z.ZodString, string, string>;
196
+ region: z.ZodString;
197
+ sessionKey: z.ZodString;
198
+ }, "strip", z.ZodTypeAny, {
199
+ auth: "sigv4";
200
+ url: string;
201
+ region: string;
202
+ sessionKey: string;
203
+ }, {
204
+ auth: "sigv4";
205
+ url: string;
206
+ region: string;
207
+ sessionKey: string;
208
+ }>, z.ZodObject<{
209
+ auth: z.ZodLiteral<"none">;
210
+ url: z.ZodEffects<z.ZodString, string, string>;
211
+ sessionKey: z.ZodString;
212
+ }, "strip", z.ZodTypeAny, {
213
+ auth: "none";
214
+ url: string;
215
+ sessionKey: string;
216
+ }, {
217
+ auth: "none";
218
+ url: string;
219
+ sessionKey: string;
220
+ }>]>;
221
+ export type WorkspaceEndpoint = z.infer<typeof workspaceEndpointSchema>;
222
+ /**
223
+ * The edge's view of the VM, reported in its health response as
224
+ * `workspace.ingress`. The AI service reopens the workspace when it stays
225
+ * `unreachable`.
226
+ *
227
+ * - `waiting`: no endpoint yet.
228
+ * - `reachable`: the last state push succeeded and the VM reports a booting
229
+ * or ready workspace host.
230
+ * - `unreachable`: pushes to the current endpoint are failing, or the VM
231
+ * answers them but reports its workspace host `failed` (it cannot serve
232
+ * until the workspace is reopened).
233
+ * - `closed`: the edge is shutting down.
234
+ */
235
+ export declare const workspaceIngressStateSchema: z.ZodEnum<["waiting", "reachable", "unreachable", "closed"]>;
236
+ export type WorkspaceIngressState = z.infer<typeof workspaceIngressStateSchema>;
237
+ //# sourceMappingURL=control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;GAGG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAE1D,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,uBAAuB,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,gCACrB,CAAC;AAEhC,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhE;AAMD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAeT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,QAAQ,EAAE,MAAM,GACf,OAAO,CAIT;AAMD,eAAO,MAAM,6BAA6B;;IAExC,mEAAmE;;;;;;;;EAEnE,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;IAC/B,yEAAyE;;IAEzE,6EAA6E;;IAE7E,0EAA0E;;IAE1E;;;OAGG;;;QAxBH,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;EA0BnE,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;IAGhC,+CAA+C;;;;;;;;;;;;;EAG/C,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAMpE;;;;GAIG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;IAatC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAWhF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;IAYlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAMxE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,8DAKtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}