@smthrs/kernel 0.0.0-stage → 1.0.0-rc.3

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 (267) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -2
  4. package/dist/cjs/CapabilitySet.d.ts +6 -0
  5. package/dist/cjs/CapabilitySet.d.ts.map +1 -0
  6. package/dist/cjs/CapabilitySet.js +19 -0
  7. package/dist/cjs/CapabilitySet.js.map +7 -0
  8. package/dist/cjs/ChildProcessEnvironment.d.ts +60 -0
  9. package/dist/cjs/ChildProcessEnvironment.d.ts.map +1 -0
  10. package/dist/cjs/ChildProcessEnvironment.js +61 -0
  11. package/dist/cjs/ChildProcessEnvironment.js.map +7 -0
  12. package/dist/cjs/ChildProcessSpawner.d.ts +100 -0
  13. package/dist/cjs/ChildProcessSpawner.d.ts.map +1 -0
  14. package/dist/cjs/ChildProcessSpawner.js +291 -0
  15. package/dist/cjs/ChildProcessSpawner.js.map +7 -0
  16. package/dist/cjs/CommandLine.d.ts +173 -0
  17. package/dist/cjs/CommandLine.d.ts.map +1 -0
  18. package/dist/cjs/CommandLine.js +54 -0
  19. package/dist/cjs/CommandLine.js.map +7 -0
  20. package/dist/cjs/ContainedSpawner.d.ts +135 -0
  21. package/dist/cjs/ContainedSpawner.d.ts.map +1 -0
  22. package/dist/cjs/ContainedSpawner.js +141 -0
  23. package/dist/cjs/ContainedSpawner.js.map +7 -0
  24. package/dist/cjs/FileSystem.d.ts +452 -0
  25. package/dist/cjs/FileSystem.d.ts.map +1 -0
  26. package/dist/cjs/FileSystem.js +890 -0
  27. package/dist/cjs/FileSystem.js.map +7 -0
  28. package/dist/cjs/FileSystemBatch.d.ts +94 -0
  29. package/dist/cjs/FileSystemBatch.d.ts.map +1 -0
  30. package/dist/cjs/FileSystemBatch.js +31 -0
  31. package/dist/cjs/FileSystemBatch.js.map +7 -0
  32. package/dist/cjs/GrantEvent.d.ts +240 -0
  33. package/dist/cjs/GrantEvent.d.ts.map +1 -0
  34. package/dist/cjs/GrantEvent.js +115 -0
  35. package/dist/cjs/GrantEvent.js.map +7 -0
  36. package/dist/cjs/GrantStore.d.ts +270 -0
  37. package/dist/cjs/GrantStore.d.ts.map +1 -0
  38. package/dist/cjs/GrantStore.js +857 -0
  39. package/dist/cjs/GrantStore.js.map +7 -0
  40. package/dist/cjs/HostError.d.ts +36 -0
  41. package/dist/cjs/HostError.d.ts.map +1 -0
  42. package/dist/cjs/HostError.js +17 -0
  43. package/dist/cjs/HostError.js.map +7 -0
  44. package/dist/cjs/HostServices.d.ts +101 -0
  45. package/dist/cjs/HostServices.d.ts.map +1 -0
  46. package/dist/cjs/HostServices.js +66 -0
  47. package/dist/cjs/HostServices.js.map +7 -0
  48. package/dist/cjs/HttpClient.d.ts +177 -0
  49. package/dist/cjs/HttpClient.d.ts.map +1 -0
  50. package/dist/cjs/HttpClient.js +217 -0
  51. package/dist/cjs/HttpClient.js.map +7 -0
  52. package/dist/cjs/Jj.d.ts +67 -0
  53. package/dist/cjs/Jj.d.ts.map +1 -0
  54. package/dist/cjs/Jj.js +118 -0
  55. package/dist/cjs/Jj.js.map +7 -0
  56. package/dist/cjs/JournalGrantStore.d.ts +65 -0
  57. package/dist/cjs/JournalGrantStore.d.ts.map +1 -0
  58. package/dist/cjs/JournalGrantStore.js +354 -0
  59. package/dist/cjs/JournalGrantStore.js.map +7 -0
  60. package/dist/cjs/Path.d.ts +37 -0
  61. package/dist/cjs/Path.d.ts.map +1 -0
  62. package/dist/cjs/Path.js +46 -0
  63. package/dist/cjs/Path.js.map +7 -0
  64. package/dist/cjs/ProcessConfinement.d.ts +55 -0
  65. package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
  66. package/dist/cjs/ProcessConfinement.js +94 -0
  67. package/dist/cjs/ProcessConfinement.js.map +7 -0
  68. package/dist/cjs/ProcessLedger.d.ts +260 -0
  69. package/dist/cjs/ProcessLedger.d.ts.map +1 -0
  70. package/dist/cjs/ProcessLedger.js +190 -0
  71. package/dist/cjs/ProcessLedger.js.map +7 -0
  72. package/dist/cjs/Rooted.d.ts +53 -0
  73. package/dist/cjs/Rooted.d.ts.map +1 -0
  74. package/dist/cjs/Rooted.js +101 -0
  75. package/dist/cjs/Rooted.js.map +7 -0
  76. package/dist/cjs/Unreachable.d.ts +27 -0
  77. package/dist/cjs/Unreachable.d.ts.map +1 -0
  78. package/dist/cjs/Unreachable.js +43 -0
  79. package/dist/cjs/Unreachable.js.map +7 -0
  80. package/dist/cjs/Workspace.d.ts +62 -0
  81. package/dist/cjs/Workspace.d.ts.map +1 -0
  82. package/dist/cjs/Workspace.js +35 -0
  83. package/dist/cjs/Workspace.js.map +7 -0
  84. package/dist/cjs/index.d.ts +161 -0
  85. package/dist/cjs/index.d.ts.map +1 -0
  86. package/dist/cjs/index.js +73 -0
  87. package/dist/cjs/index.js.map +7 -0
  88. package/dist/cjs/internal/Containment.d.ts +24 -0
  89. package/dist/cjs/internal/Containment.d.ts.map +1 -0
  90. package/dist/cjs/internal/Containment.js +30 -0
  91. package/dist/cjs/internal/Containment.js.map +7 -0
  92. package/dist/cjs/internal/Pipeline.d.ts +18 -0
  93. package/dist/cjs/internal/Pipeline.d.ts.map +1 -0
  94. package/dist/cjs/internal/Pipeline.js +90 -0
  95. package/dist/cjs/internal/Pipeline.js.map +7 -0
  96. package/dist/cjs/internal/makeCapability.d.ts +16 -0
  97. package/dist/cjs/internal/makeCapability.d.ts.map +1 -0
  98. package/dist/cjs/internal/makeCapability.js +44 -0
  99. package/dist/cjs/internal/makeCapability.js.map +7 -0
  100. package/dist/cjs/package.json +1 -0
  101. package/dist/cjs/test/FileSystemBatchContract.d.ts +15 -0
  102. package/dist/cjs/test/FileSystemBatchContract.d.ts.map +1 -0
  103. package/dist/cjs/test/FileSystemBatchContract.js +76 -0
  104. package/dist/cjs/test/FileSystemBatchContract.js.map +7 -0
  105. package/dist/cjs/test/HostContract.d.ts +225 -0
  106. package/dist/cjs/test/HostContract.d.ts.map +1 -0
  107. package/dist/cjs/test/HostContract.js +489 -0
  108. package/dist/cjs/test/HostContract.js.map +7 -0
  109. package/dist/cjs/test/TestGrantStore.d.ts +31 -0
  110. package/dist/cjs/test/TestGrantStore.d.ts.map +1 -0
  111. package/dist/cjs/test/TestGrantStore.js +65 -0
  112. package/dist/cjs/test/TestGrantStore.js.map +7 -0
  113. package/dist/esm/CapabilitySet.d.ts +6 -0
  114. package/dist/esm/CapabilitySet.d.ts.map +1 -0
  115. package/dist/esm/CapabilitySet.js +6 -0
  116. package/dist/esm/CapabilitySet.js.map +1 -0
  117. package/dist/esm/ChildProcessEnvironment.d.ts +60 -0
  118. package/dist/esm/ChildProcessEnvironment.d.ts.map +1 -0
  119. package/dist/esm/ChildProcessEnvironment.js +91 -0
  120. package/dist/esm/ChildProcessEnvironment.js.map +1 -0
  121. package/dist/esm/ChildProcessSpawner.d.ts +100 -0
  122. package/dist/esm/ChildProcessSpawner.d.ts.map +1 -0
  123. package/dist/esm/ChildProcessSpawner.js +342 -0
  124. package/dist/esm/ChildProcessSpawner.js.map +1 -0
  125. package/dist/esm/CommandLine.d.ts +173 -0
  126. package/dist/esm/CommandLine.d.ts.map +1 -0
  127. package/dist/esm/CommandLine.js +195 -0
  128. package/dist/esm/CommandLine.js.map +1 -0
  129. package/dist/esm/ContainedSpawner.d.ts +135 -0
  130. package/dist/esm/ContainedSpawner.d.ts.map +1 -0
  131. package/dist/esm/ContainedSpawner.js +180 -0
  132. package/dist/esm/ContainedSpawner.js.map +1 -0
  133. package/dist/esm/FileSystem.d.ts +452 -0
  134. package/dist/esm/FileSystem.d.ts.map +1 -0
  135. package/dist/esm/FileSystem.js +989 -0
  136. package/dist/esm/FileSystem.js.map +1 -0
  137. package/dist/esm/FileSystemBatch.d.ts +94 -0
  138. package/dist/esm/FileSystemBatch.d.ts.map +1 -0
  139. package/dist/esm/FileSystemBatch.js +26 -0
  140. package/dist/esm/FileSystemBatch.js.map +1 -0
  141. package/dist/esm/GrantEvent.d.ts +240 -0
  142. package/dist/esm/GrantEvent.d.ts.map +1 -0
  143. package/dist/esm/GrantEvent.js +155 -0
  144. package/dist/esm/GrantEvent.js.map +1 -0
  145. package/dist/esm/GrantStore.d.ts +270 -0
  146. package/dist/esm/GrantStore.d.ts.map +1 -0
  147. package/dist/esm/GrantStore.js +951 -0
  148. package/dist/esm/GrantStore.js.map +1 -0
  149. package/dist/esm/HostError.d.ts +36 -0
  150. package/dist/esm/HostError.d.ts.map +1 -0
  151. package/dist/esm/HostError.js +20 -0
  152. package/dist/esm/HostError.js.map +1 -0
  153. package/dist/esm/HostServices.d.ts +101 -0
  154. package/dist/esm/HostServices.d.ts.map +1 -0
  155. package/dist/esm/HostServices.js +76 -0
  156. package/dist/esm/HostServices.js.map +1 -0
  157. package/dist/esm/HttpClient.d.ts +177 -0
  158. package/dist/esm/HttpClient.d.ts.map +1 -0
  159. package/dist/esm/HttpClient.js +299 -0
  160. package/dist/esm/HttpClient.js.map +1 -0
  161. package/dist/esm/Jj.d.ts +67 -0
  162. package/dist/esm/Jj.d.ts.map +1 -0
  163. package/dist/esm/Jj.js +111 -0
  164. package/dist/esm/Jj.js.map +1 -0
  165. package/dist/esm/JournalGrantStore.d.ts +65 -0
  166. package/dist/esm/JournalGrantStore.d.ts.map +1 -0
  167. package/dist/esm/JournalGrantStore.js +350 -0
  168. package/dist/esm/JournalGrantStore.js.map +1 -0
  169. package/dist/esm/Path.d.ts +37 -0
  170. package/dist/esm/Path.d.ts.map +1 -0
  171. package/dist/esm/Path.js +34 -0
  172. package/dist/esm/Path.js.map +1 -0
  173. package/dist/esm/ProcessConfinement.d.ts +55 -0
  174. package/dist/esm/ProcessConfinement.d.ts.map +1 -0
  175. package/dist/esm/ProcessConfinement.js +106 -0
  176. package/dist/esm/ProcessConfinement.js.map +1 -0
  177. package/dist/esm/ProcessLedger.d.ts +260 -0
  178. package/dist/esm/ProcessLedger.d.ts.map +1 -0
  179. package/dist/esm/ProcessLedger.js +283 -0
  180. package/dist/esm/ProcessLedger.js.map +1 -0
  181. package/dist/esm/Rooted.d.ts +53 -0
  182. package/dist/esm/Rooted.d.ts.map +1 -0
  183. package/dist/esm/Rooted.js +104 -0
  184. package/dist/esm/Rooted.js.map +1 -0
  185. package/dist/esm/Unreachable.d.ts +27 -0
  186. package/dist/esm/Unreachable.d.ts.map +1 -0
  187. package/dist/esm/Unreachable.js +26 -0
  188. package/dist/esm/Unreachable.js.map +1 -0
  189. package/dist/esm/Workspace.d.ts +62 -0
  190. package/dist/esm/Workspace.d.ts.map +1 -0
  191. package/dist/esm/Workspace.js +51 -0
  192. package/dist/esm/Workspace.js.map +1 -0
  193. package/dist/esm/index.d.ts +161 -0
  194. package/dist/esm/index.d.ts.map +1 -0
  195. package/dist/esm/index.js +151 -0
  196. package/dist/esm/index.js.map +1 -0
  197. package/dist/esm/internal/Containment.d.ts +24 -0
  198. package/dist/esm/internal/Containment.d.ts.map +1 -0
  199. package/dist/esm/internal/Containment.js +27 -0
  200. package/dist/esm/internal/Containment.js.map +1 -0
  201. package/dist/esm/internal/Pipeline.d.ts +18 -0
  202. package/dist/esm/internal/Pipeline.d.ts.map +1 -0
  203. package/dist/esm/internal/Pipeline.js +68 -0
  204. package/dist/esm/internal/Pipeline.js.map +1 -0
  205. package/dist/esm/internal/makeCapability.d.ts +16 -0
  206. package/dist/esm/internal/makeCapability.d.ts.map +1 -0
  207. package/dist/esm/internal/makeCapability.js +22 -0
  208. package/dist/esm/internal/makeCapability.js.map +1 -0
  209. package/dist/esm/test/FileSystemBatchContract.d.ts +15 -0
  210. package/dist/esm/test/FileSystemBatchContract.d.ts.map +1 -0
  211. package/dist/esm/test/FileSystemBatchContract.js +57 -0
  212. package/dist/esm/test/FileSystemBatchContract.js.map +1 -0
  213. package/dist/esm/test/HostContract.d.ts +225 -0
  214. package/dist/esm/test/HostContract.d.ts.map +1 -0
  215. package/dist/esm/test/HostContract.js +460 -0
  216. package/dist/esm/test/HostContract.js.map +1 -0
  217. package/dist/esm/test/TestGrantStore.d.ts +31 -0
  218. package/dist/esm/test/TestGrantStore.d.ts.map +1 -0
  219. package/dist/esm/test/TestGrantStore.js +57 -0
  220. package/dist/esm/test/TestGrantStore.js.map +1 -0
  221. package/docs/README.md +162 -0
  222. package/docs/api.md +1532 -0
  223. package/docs/concepts/decoration-in-place.md +117 -0
  224. package/docs/concepts/filesystem-batches.md +58 -0
  225. package/docs/concepts/filesystem-confinement.md +168 -0
  226. package/docs/concepts/grant-decisions.md +181 -0
  227. package/docs/concepts/process-containment.md +155 -0
  228. package/docs/contract.md +14 -0
  229. package/docs/guides/adapt-a-new-host-platform.md +148 -0
  230. package/docs/guides/answer-permission-requests.md +151 -0
  231. package/docs/guides/authorize-network-and-model-calls.md +118 -0
  232. package/docs/guides/contain-spawned-processes.md +118 -0
  233. package/docs/guides/guard-a-host-bundle.md +109 -0
  234. package/docs/guides/persist-grants-across-restarts.md +135 -0
  235. package/docs/guides/write-a-capability-policy.md +159 -0
  236. package/docs/installation.md +115 -0
  237. package/docs/quickstart.md +182 -0
  238. package/docs/testing.md +108 -0
  239. package/docs/troubleshooting.md +281 -0
  240. package/package.json +344 -3
  241. package/src/CapabilitySet.ts +6 -0
  242. package/src/ChildProcessEnvironment.ts +98 -0
  243. package/src/ChildProcessSpawner.ts +414 -0
  244. package/src/CommandLine.ts +250 -0
  245. package/src/ContainedSpawner.ts +284 -0
  246. package/src/FileSystem.ts +1655 -0
  247. package/src/FileSystemBatch.ts +90 -0
  248. package/src/GrantEvent.ts +174 -0
  249. package/src/GrantStore.ts +1345 -0
  250. package/src/HostError.ts +37 -0
  251. package/src/HostServices.ts +133 -0
  252. package/src/HttpClient.ts +406 -0
  253. package/src/Jj.ts +159 -0
  254. package/src/JournalGrantStore.ts +461 -0
  255. package/src/Path.ts +47 -0
  256. package/src/ProcessConfinement.ts +156 -0
  257. package/src/ProcessLedger.ts +423 -0
  258. package/src/Rooted.ts +128 -0
  259. package/src/Unreachable.ts +30 -0
  260. package/src/Workspace.ts +65 -0
  261. package/src/index.ts +181 -0
  262. package/src/internal/Containment.ts +37 -0
  263. package/src/internal/Pipeline.ts +85 -0
  264. package/src/internal/makeCapability.ts +26 -0
  265. package/src/test/FileSystemBatchContract.ts +59 -0
  266. package/src/test/HostContract.ts +785 -0
  267. package/src/test/TestGrantStore.ts +73 -0
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var HttpClient_exports = {};
30
+ __export(HttpClient_exports, {
31
+ Destination: () => Destination,
32
+ HttpClient: () => import_HttpClient.HttpClient,
33
+ ModelCall: () => ModelCall,
34
+ authorizePreflight: () => authorizePreflight,
35
+ fromHttpClientError: () => fromHttpClientError,
36
+ layer: () => layer,
37
+ layerNoop: () => layerNoop,
38
+ make: () => import_HttpClient2.make,
39
+ makeNoop: () => makeNoop,
40
+ supportsDestinationPinning: () => supportsDestinationPinning,
41
+ toHttpClientError: () => toHttpClientError,
42
+ withDestinationPinning: () => withDestinationPinning,
43
+ withModelCall: () => withModelCall
44
+ });
45
+ module.exports = __toCommonJS(HttpClient_exports);
46
+ var import_Permission = require("@smthrs/capability/Permission");
47
+ var import_effect = require("effect");
48
+ var FetchHttpClient = __toESM(require("effect/unstable/http/FetchHttpClient"), 1);
49
+ var Headers = __toESM(require("effect/unstable/http/Headers"), 1);
50
+ var HttpBody = __toESM(require("effect/unstable/http/HttpBody"), 1);
51
+ var EffectHttpClient = __toESM(require("effect/unstable/http/HttpClient"), 1);
52
+ var HttpClientError = __toESM(require("effect/unstable/http/HttpClientError"), 1);
53
+ var HttpClientRequest = __toESM(require("effect/unstable/http/HttpClientRequest"), 1);
54
+ var UrlParams = __toESM(require("effect/unstable/http/UrlParams"), 1);
55
+ var import_GrantStore = require("./GrantStore.js");
56
+ var import_makeCapability = require("./internal/makeCapability.js");
57
+ var import_HttpClient = require("effect/unstable/http/HttpClient");
58
+ var import_HttpClient2 = require("effect/unstable/http/HttpClient");
59
+ const snapshotRawBody = (value) => {
60
+ if (value instanceof globalThis.Uint8Array) return value.slice();
61
+ if (value instanceof ArrayBuffer) return value.slice(0);
62
+ if (value instanceof URLSearchParams) {
63
+ return new URLSearchParams(value);
64
+ }
65
+ if (value instanceof Blob) return value;
66
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
67
+ return value;
68
+ }
69
+ throw new TypeError("raw HTTP bodies must be immutable or copyable");
70
+ };
71
+ const snapshotBody = (body) => {
72
+ switch (body._tag) {
73
+ case "Empty":
74
+ return HttpBody.empty;
75
+ case "Raw":
76
+ return HttpBody.raw(snapshotRawBody(body.body), {
77
+ contentType: body.contentType,
78
+ contentLength: body.contentLength
79
+ });
80
+ case "Uint8Array":
81
+ return HttpBody.uint8Array(body.body.slice(), body.contentType);
82
+ case "FormData": {
83
+ const formData = new globalThis.FormData();
84
+ for (const [name, value] of body.formData.entries()) formData.append(name, value);
85
+ return HttpBody.formData(formData);
86
+ }
87
+ case "Stream":
88
+ return HttpBody.stream(body.stream, body.contentType, body.contentLength);
89
+ }
90
+ };
91
+ const snapshotRequest = (request) => HttpClientRequest.makeWith(
92
+ request.method,
93
+ request.url,
94
+ UrlParams.make(
95
+ Object.freeze(request.urlParams.params.map(([name, value]) => Object.freeze([name, value])))
96
+ ),
97
+ import_effect.Option.map(request.hash, (value) => value),
98
+ Headers.fromInput(request.headers),
99
+ snapshotBody(request.body)
100
+ );
101
+ const invalidRequest = (request) => new HttpClientError.HttpClientError({
102
+ reason: new HttpClientError.TransportError({
103
+ request,
104
+ description: "HTTP request must be an immutable supported request description"
105
+ })
106
+ });
107
+ const ModelCall = import_effect.Context.Reference(
108
+ "@smthrs/kernel/HttpClient/ModelCall",
109
+ { defaultValue: () => void 0 }
110
+ );
111
+ const withModelCall = (modelId) => (effect) => import_effect.Effect.provideService(effect, ModelCall, modelId);
112
+ const toHttpClientError = (options) => new HttpClientError.HttpClientError({
113
+ reason: new HttpClientError.TransportError({
114
+ request: options.request,
115
+ description: (0, import_Permission.formatError)(options.error),
116
+ cause: options.error
117
+ })
118
+ });
119
+ const fromHttpClientError = (error) => error.reason._tag === "TransportError" && (0, import_Permission.isPermissionError)(error.reason.cause) ? import_effect.Option.some(error.reason.cause) : import_effect.Option.none();
120
+ const makeNoop = () => EffectHttpClient.make(
121
+ (request) => import_effect.Effect.fail(
122
+ new HttpClientError.HttpClientError({
123
+ reason: new HttpClientError.TransportError({
124
+ request,
125
+ cause: new Error("HTTP is unavailable on this host")
126
+ })
127
+ })
128
+ )
129
+ );
130
+ const layerNoop = () => import_effect.Layer.succeed(EffectHttpClient.HttpClient)(makeNoop());
131
+ const capabilityFor = (request, modelId) => {
132
+ const action = modelId === void 0 ? request.method === "GET" || request.method === "HEAD" ? "net:get" : "net:post" : "model:call";
133
+ let url;
134
+ try {
135
+ url = new URL(request.url);
136
+ } catch {
137
+ return (0, import_makeCapability.makeCapability)(action, request.url).pipe(
138
+ import_effect.Effect.flatMap(
139
+ (capability) => import_effect.Effect.fail(
140
+ new import_Permission.PermissionDenied({
141
+ code: "permission_denied",
142
+ capability,
143
+ reason: "HTTP capability checks require an absolute, parseable URL"
144
+ })
145
+ )
146
+ )
147
+ );
148
+ }
149
+ const host = url.host.toLowerCase();
150
+ const resource = url.protocol === "https:" ? host : `${url.protocol}//${host}`;
151
+ return (0, import_makeCapability.makeCapability)(action, modelId === void 0 ? resource : `${resource}/${modelId}`);
152
+ };
153
+ const Admission = import_effect.Context.Reference("@smthrs/kernel/HttpClient/Admission", {
154
+ defaultValue: () => void 0
155
+ });
156
+ const authorizePreflight = (request, effect) => import_effect.Effect.gen(function* () {
157
+ const store = yield* import_GrantStore.GrantStore;
158
+ const capability = yield* import_effect.Effect.withFiber((fiber) => capabilityFor(request, fiber.getRef(ModelCall))).pipe(
159
+ import_effect.Effect.tap((capability2) => store.check(capability2)),
160
+ import_effect.Effect.mapError((error) => toHttpClientError({ request, error }))
161
+ );
162
+ return yield* import_effect.Effect.provideService(effect, Admission, { store, capability, consumed: false });
163
+ });
164
+ const manualRedirects = (context) => import_effect.Context.add(context, FetchHttpClient.RequestInit, {
165
+ ...import_effect.Context.getOrUndefined(context, FetchHttpClient.RequestInit),
166
+ redirect: "manual"
167
+ });
168
+ const layer = import_effect.Layer.effect(
169
+ EffectHttpClient.HttpClient,
170
+ import_effect.Effect.gen(function* () {
171
+ const client = yield* EffectHttpClient.HttpClient;
172
+ const grants = yield* import_GrantStore.GrantStore;
173
+ const snapshotted = EffectHttpClient.mapRequestEffect(
174
+ client,
175
+ (request) => import_effect.Effect.try({
176
+ try: () => snapshotRequest(request),
177
+ catch: () => invalidRequest(request)
178
+ })
179
+ );
180
+ const guarded = EffectHttpClient.transform(
181
+ snapshotted,
182
+ (execute, request) => import_effect.Effect.withFiber(
183
+ (fiber) => capabilityFor(request, fiber.getRef(ModelCall)).pipe(
184
+ import_effect.Effect.flatMap((capability) => {
185
+ const admission = fiber.getRef(Admission);
186
+ if (admission !== void 0 && !admission.consumed && admission.store === grants && admission.capability.action === capability.action && admission.capability.resource === capability.resource) {
187
+ admission.consumed = true;
188
+ return import_effect.Effect.void;
189
+ }
190
+ return grants.check(capability);
191
+ }),
192
+ import_effect.Effect.mapError((error) => toHttpClientError({ request, error })),
193
+ import_effect.Effect.andThen(import_effect.Effect.updateContext(execute, manualRedirects))
194
+ )
195
+ )
196
+ );
197
+ const followed = EffectHttpClient.followRedirects(guarded);
198
+ const result = EffectHttpClient.makeWith(
199
+ (request) => import_effect.Effect.withFiber(
200
+ (fiber) => (
201
+ // Read caller policy before the guard forces manual transport.
202
+ import_effect.Context.getOrUndefined(fiber.context, FetchHttpClient.RequestInit)?.redirect === "manual" ? guarded.postprocess(request) : followed.postprocess(request)
203
+ )
204
+ ),
205
+ guarded.preprocess
206
+ );
207
+ return supportsDestinationPinning(client) ? withDestinationPinning(result) : result;
208
+ })
209
+ );
210
+ const Destination = import_effect.Context.Reference("@smthrs/kernel/HttpClient/Destination", { defaultValue: () => void 0 });
211
+ const pinnedClients = /* @__PURE__ */ new WeakSet();
212
+ const withDestinationPinning = (client) => {
213
+ pinnedClients.add(client);
214
+ return client;
215
+ };
216
+ const supportsDestinationPinning = (client) => pinnedClients.has(client);
217
+ //# sourceMappingURL=HttpClient.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/HttpClient.ts"],
4
+ "sourcesContent": ["/**\n * Permission-aware outgoing HTTP requests.\n *\n * There is no kernel `HttpClient` interface and no kernel `HttpClient` tag.\n * Effect owns both, and its tag fixes the error channel to `HttpClientError`,\n * so this module is only the middleware: a `Layer` over Effect's own tag that\n * reads the raw client out of context and returns a guarded one in its place.\n * Permission failures are projected into `HttpClientError` by\n * {@link toHttpClientError}, which keeps the structured kernel failure on the\n * transport reason's `cause` so {@link fromHttpClientError} can hand it back.\n *\n * **Redirects.** A redirect is a second network destination, so it needs a\n * second grant check. Two halves guarantee that:\n *\n * 1. The client below this layer must **not** follow redirects on its own.\n * That is a precondition on the host: Undici without a redirect\n * interceptor, or Effect's fetch layer with `redirect: \"manual\"`. This\n * layer also forces `RequestInit { redirect: \"manual\" }` over the ambient\n * value for every request it executes, so a plain `FetchHttpClient.layer`,\n * which follows redirects by default, cannot walk to another origin below\n * the guard either. A custom client that ignores `RequestInit` must meet\n * the precondition itself.\n * 2. This layer composes Effect's own `HttpClient.followRedirects` *above*\n * the guard. That combinator re-enters `postprocess` for every hop, and\n * `postprocess` is the guarded one, so hop *n* is checked exactly like hop\n * zero and an authorized origin cannot lend its grant to another.\n * A caller that sets `FetchHttpClient.RequestInit.redirect` to `manual`\n * receives one guarded hop and owns any further redirect requests itself.\n *\n * Governing design:\n * `docs/specs/Concepts/Permission Kernel.md`,\n * `docs/specs/Concepts/Effect Taxonomy.md`, and\n * `docs/specs/Concepts/Host Adapters.md`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport type { Capability } from \"@smthrs/capability/Capability\"\nimport {\n formatError,\n isPermissionError,\n PermissionDenied,\n type PermissionError,\n type PermissionErrorPayload\n} from \"@smthrs/capability/Permission\"\nimport { Context, Effect, Layer, Option } from \"effect\"\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\"\nimport * as Headers from \"effect/unstable/http/Headers\"\nimport * as HttpBody from \"effect/unstable/http/HttpBody\"\nimport * as EffectHttpClient from \"effect/unstable/http/HttpClient\"\nimport * as HttpClientError from \"effect/unstable/http/HttpClientError\"\nimport * as HttpClientRequest from \"effect/unstable/http/HttpClientRequest\"\nimport * as UrlParams from \"effect/unstable/http/UrlParams\"\nimport { GrantStore, type Service as GrantService } from \"./GrantStore.ts\"\nimport { makeCapability } from \"./internal/makeCapability.ts\"\n\nconst snapshotRawBody = (value: unknown): unknown => {\n if (value instanceof globalThis.Uint8Array) return value.slice()\n if (value instanceof ArrayBuffer) return value.slice(0)\n if (value instanceof URLSearchParams) {\n return new URLSearchParams(value)\n }\n if (value instanceof Blob) return value\n if (value === null || typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return value\n }\n throw new TypeError(\"raw HTTP bodies must be immutable or copyable\")\n}\n\nconst snapshotBody = (body: HttpBody.HttpBody): HttpBody.HttpBody => {\n switch (body._tag) {\n case \"Empty\":\n return HttpBody.empty\n case \"Raw\":\n return HttpBody.raw(snapshotRawBody(body.body), {\n contentType: body.contentType,\n contentLength: body.contentLength\n })\n case \"Uint8Array\":\n return HttpBody.uint8Array(body.body.slice(), body.contentType)\n case \"FormData\": {\n const formData = new globalThis.FormData()\n for (const [name, value] of body.formData.entries()) formData.append(name, value)\n return HttpBody.formData(formData)\n }\n case \"Stream\":\n return HttpBody.stream(body.stream, body.contentType, body.contentLength)\n }\n}\n\nconst snapshotRequest = (request: HttpClientRequest.HttpClientRequest): HttpClientRequest.HttpClientRequest =>\n HttpClientRequest.makeWith(\n request.method,\n request.url,\n UrlParams.make(\n Object.freeze(request.urlParams.params.map(([name, value]) => Object.freeze([name, value] as const)))\n ),\n Option.map(request.hash, (value) => value),\n Headers.fromInput(request.headers),\n snapshotBody(request.body)\n )\n\nconst invalidRequest = (request: HttpClientRequest.HttpClientRequest): HttpClientError.HttpClientError =>\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n description: \"HTTP request must be an immutable supported request description\"\n })\n })\n\n/**\n * Effect's own outgoing HTTP client tag, unchanged. Re-exported so the kernel\n * namespace stays one-stop; it is the *same* tag, never a second one.\n *\n * @category services\n * @since 1.0.0-rc.0\n */\nexport { HttpClient } from \"effect/unstable/http/HttpClient\"\n\n/**\n * Constructs a client from a low-level request runner, keeping Effect's own\n * URL construction, tracing, header redaction, and interruption behavior.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport { make } from \"effect/unstable/http/HttpClient\"\n\n/**\n * The model identity an outgoing request is made on behalf of, if any.\n *\n * A model call is not a general `net:*` effect: the same host answers many\n * models, and a grant for one must not be a grant for the rest. Effect's tag\n * has no room for an extra method, so the intent rides on a `Context`\n * reference instead \u2014 set it with {@link withModelCall} and the decorator asks\n * for `model:call` rather than `net:get`/`net:post`.\n *\n * @category references\n * @since 1.0.0-rc.0\n */\nexport const ModelCall: Context.Reference<string | undefined> = Context.Reference<string | undefined>(\n \"@smthrs/kernel/HttpClient/ModelCall\",\n { defaultValue: (): string | undefined => undefined }\n)\n\n/**\n * Runs `effect` with every outgoing request in it checked as a `model:call` on\n * `modelId` instead of as plain network access.\n *\n * @category references\n * @since 1.0.0-rc.0\n */\nexport const withModelCall = (modelId: string) => <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.provideService(effect, ModelCall, modelId)\n\n/**\n * Projects a permission failure into the error channel Effect's `HttpClient`\n * tag fixes.\n *\n * Nothing is lost: the reason is always a `TransportError` \u2014 the request did\n * not leave the host because the capability kernel refused, suspended, or\n * could not decide it \u2014 `description` carries the human rendering from\n * `Permission.formatError`, and `cause` carries the structured failure itself,\n * so {@link fromHttpClientError} hands the attended surface back the original\n * `capability`, `tier`, `requestId`, and `reason`.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const toHttpClientError = (options: {\n readonly request: HttpClientRequest.HttpClientRequest\n readonly error: PermissionError\n}): HttpClientError.HttpClientError =>\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request: options.request,\n description: formatError(options.error),\n cause: options.error\n })\n })\n\n/**\n * Recovers the structured permission failure a {@link toHttpClientError}\n * projection carries, so an attended surface can still reply to the request\n * and an unattended report can still name the capability.\n *\n * Recovery validates data fields and the transport reason tag, not origin or\n * class operations. Establish producer or request identity separately across\n * a trust boundary.\n *\n * @category refinements\n * @since 1.0.0-rc.0\n */\nexport const fromHttpClientError = (\n error: HttpClientError.HttpClientError\n): Option.Option<PermissionErrorPayload> =>\n error.reason._tag === \"TransportError\" && isPermissionError(error.reason.cause)\n ? Option.some(error.reason.cause)\n : Option.none()\n\n/**\n * Constructs an unavailable HTTP client stub.\n *\n * Every request reports the missing host as a `TransportError` naming the\n * request, so an unconfigured capability answers rather than vanishing.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const makeNoop = (): EffectHttpClient.HttpClient =>\n EffectHttpClient.make((request) =>\n Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n cause: new Error(\"HTTP is unavailable on this host\")\n })\n })\n )\n )\n\n/**\n * Provides an unavailable HTTP client stub.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layerNoop = (): Layer.Layer<EffectHttpClient.HttpClient> =>\n Layer.succeed(EffectHttpClient.HttpClient)(makeNoop())\n\n/**\n * Keeps HTTPS resources host-only so existing grants remain valid. Every\n * other scheme is explicit, which prevents an HTTPS grant from authorizing a\n * cleartext or otherwise different transport.\n */\nconst capabilityFor = (\n request: HttpClientRequest.HttpClientRequest,\n modelId: string | undefined\n): Effect.Effect<Capability, PermissionError> => {\n const action = modelId === undefined\n ? request.method === \"GET\" || request.method === \"HEAD\" ? \"net:get\" : \"net:post\"\n : \"model:call\"\n let url: URL\n try {\n url = new URL(request.url)\n } catch {\n return makeCapability(action, request.url).pipe(\n Effect.flatMap((capability) =>\n Effect.fail(\n new PermissionDenied({\n code: \"permission_denied\",\n capability,\n reason: \"HTTP capability checks require an absolute, parseable URL\"\n })\n )\n )\n )\n }\n const host = url.host.toLowerCase()\n const resource = url.protocol === \"https:\" ? host : `${url.protocol}//${host}`\n return makeCapability(action, modelId === undefined ? resource : `${resource}/${modelId}`)\n}\n\ninterface PreflightAdmission {\n readonly store: GrantService\n readonly capability: Capability\n consumed: boolean\n}\n\nconst Admission = Context.Reference<PreflightAdmission | undefined>(\"@smthrs/kernel/HttpClient/Admission\", {\n defaultValue: () => undefined\n})\n\n/**\n * Authorizes a request before a caller performs network preflight work such as\n * DNS. The guarded transport consumes the same admission once, so a one-shot\n * grant is not spent twice. Admissions match both store identity and the exact\n * capability; redirects and retries require their own authorization.\n *\n * @category authorization\n * @since 1.0.0\n */\nexport const authorizePreflight = <A, E, R>(\n request: HttpClientRequest.HttpClientRequest,\n effect: Effect.Effect<A, E, R>\n): Effect.Effect<A, E | HttpClientError.HttpClientError, R | GrantStore> =>\n Effect.gen(function*() {\n const store = yield* GrantStore\n const capability = yield* Effect.withFiber((fiber) => capabilityFor(request, fiber.getRef(ModelCall))).pipe(\n Effect.tap((capability) => store.check(capability)),\n Effect.mapError((error) => toHttpClientError({ request, error }))\n )\n return yield* Effect.provideService(effect, Admission, { store, capability, consumed: false })\n })\n\n/**\n * Forces `redirect: \"manual\"` on the fetch options a fetch-backed client reads\n * at execute time, keeping every other ambient field.\n */\nconst manualRedirects = (context: Context.Context<never>): Context.Context<never> =>\n Context.add(context, FetchHttpClient.RequestInit, {\n ...Context.getOrUndefined(context, FetchHttpClient.RequestInit),\n redirect: \"manual\"\n })\n\n/**\n * Decorates the HTTP client in place with a `net:get`/`net:post`/`model:call`\n * capability check, then follows redirects *through* that check.\n *\n * The layer provides the tag it also requires: compose it over a host client\n * layer with `Layer.provide` and a consumer that never heard of the kernel is\n * guarded too. Because every hop re-enters the guarded `postprocess`, an\n * authorized first URL that redirects to an unauthorized one is denied at the\n * second hop instead of being fetched.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer: Layer.Layer<\n EffectHttpClient.HttpClient,\n never,\n EffectHttpClient.HttpClient | GrantStore\n> = Layer.effect(\n EffectHttpClient.HttpClient,\n Effect.gen(function*() {\n const client = yield* EffectHttpClient.HttpClient\n const grants = yield* GrantStore\n const snapshotted = EffectHttpClient.mapRequestEffect(\n client,\n (request) =>\n Effect.try({\n try: () => snapshotRequest(request),\n catch: () => invalidRequest(request)\n })\n )\n const guarded = EffectHttpClient.transform(\n snapshotted,\n (execute, request) =>\n Effect.withFiber((fiber) =>\n capabilityFor(request, fiber.getRef(ModelCall)).pipe(\n Effect.flatMap((capability) => {\n const admission = fiber.getRef(Admission)\n if (\n admission !== undefined && !admission.consumed && admission.store === grants\n && admission.capability.action === capability.action &&\n admission.capability.resource === capability.resource\n ) {\n admission.consumed = true\n return Effect.void\n }\n return grants.check(capability)\n }),\n Effect.mapError((error: PermissionError) => toHttpClientError({ request, error })),\n Effect.andThen(Effect.updateContext(execute, manualRedirects))\n )\n )\n )\n const followed = EffectHttpClient.followRedirects(guarded)\n const result = EffectHttpClient.makeWith(\n (request) =>\n Effect.withFiber((fiber) =>\n // Read caller policy before the guard forces manual transport.\n Context.getOrUndefined(fiber.context, FetchHttpClient.RequestInit)?.redirect === \"manual\"\n ? guarded.postprocess(request)\n : followed.postprocess(request)\n ),\n guarded.preprocess\n )\n return supportsDestinationPinning(client) ? withDestinationPinning(result) : result\n })\n)\n\n/**\n * Address snapshot authorized for one web request. Host transports must reject\n * a different origin and use only these addresses for every connection attempt.\n * Ordinary model traffic leaves this reference unset.\n * @category references\n * @since 1.0.0\n */\nexport const Destination = Context.Reference<\n {\n readonly origin: string\n readonly addresses: ReadonlyArray<string>\n } | undefined\n>(\"@smthrs/kernel/HttpClient/Destination\", { defaultValue: () => undefined })\n\nconst pinnedClients = new WeakSet<EffectHttpClient.HttpClient>()\n\n/**\n * Marks a trusted transport that enforces Destination on every connection.\n * The assertion belongs to this client instance, not ambient context. A\n * replacement client must establish its own transport guarantee.\n * @category constructors\n * @since 1.0.0\n */\nexport const withDestinationPinning = <A extends EffectHttpClient.HttpClient>(client: A): A => {\n pinnedClients.add(client)\n return client\n}\n\n/**\n * Whether this exact client implements the Destination transport contract.\n * @category predicates\n * @since 1.0.0\n */\nexport const supportsDestinationPinning = (client: EffectHttpClient.HttpClient): boolean => pinnedClients.has(client)\n"],
5
+ "mappings": "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",
6
+ "names": ["import_HttpClient", "capability"]
7
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Permission-aware Jujutsu version-control operations.
3
+ *
4
+ * There is no kernel `Jj` interface and no kernel `Jj` tag. `@smthrs/jj` owns
5
+ * both, and its error channel already names the failures the kernel adds, so
6
+ * this module is only the middleware: a `Layer` over the same tag that reads
7
+ * the raw service out of context and returns a guarded one in its place.
8
+ *
9
+ * Governing design:
10
+ * `docs/specs/Concepts/Permission Kernel.md`,
11
+ * `docs/specs/Concepts/Effect Taxonomy.md`, and
12
+ * `docs/specs/Concepts/Host Adapters.md`.
13
+ *
14
+ * @since 1.0.0-rc.0
15
+ */
16
+ import { Jj } from "@smthrs/jj";
17
+ import { FileSystem as EffectFileSystem, Layer, Path as EffectPath } from "effect";
18
+ import { GrantStore } from "./GrantStore.ts";
19
+ import { Workspace } from "./Workspace.ts";
20
+ /**
21
+ * `@smthrs/jj`'s own Jujutsu tag, unchanged. Re-exported so the kernel
22
+ * namespace stays one-stop; it is the *same* tag, never a second one.
23
+ *
24
+ * @category services
25
+ * @since 1.0.0-rc.0
26
+ */
27
+ export { Jj } from "@smthrs/jj";
28
+ /**
29
+ * Provides an unavailable Jujutsu stub.
30
+ *
31
+ * @category layers
32
+ * @since 1.0.0-rc.0
33
+ */
34
+ export { layerNoop } from "@smthrs/jj";
35
+ /**
36
+ * Constructs a Jujutsu service from an implementation.
37
+ *
38
+ * @category constructors
39
+ * @since 1.0.0-rc.0
40
+ */
41
+ export { make } from "@smthrs/jj";
42
+ /**
43
+ * Constructs an unavailable Jujutsu stub.
44
+ *
45
+ * @category constructors
46
+ * @since 1.0.0-rc.0
47
+ */
48
+ export { makeNoop } from "@smthrs/jj";
49
+ /**
50
+ * Decorates the Jujutsu service in place with operation-specific capability
51
+ * checks.
52
+ *
53
+ * The layer provides the tag it also requires: compose it over a host jj layer
54
+ * with `Layer.provide` and every consumer of `Jj` — including one that never
55
+ * heard of the kernel — resolves the guarded implementation.
56
+ *
57
+ * `workspaceAdd` canonicalizes its destination and `root` canonicalizes its
58
+ * starting directory through the *raw* filesystem before asking for
59
+ * `jj:workspace-add` and `fs:write`, or for `jj:root`, so an existing symlink
60
+ * cannot turn an inside-workspace grant into outside authority or separate the
61
+ * authorized path from the directory jj is run in.
62
+ *
63
+ * @category layers
64
+ * @since 1.0.0-rc.0
65
+ */
66
+ export declare const layer: Layer.Layer<Jj, never, Jj | EffectFileSystem.FileSystem | EffectPath.Path | Workspace | GrantStore>;
67
+ //# sourceMappingURL=Jj.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Jj.d.ts","sourceRoot":"","sources":["../../src/Jj.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,EAAE,EAAmC,MAAM,YAAY,CAAA;AAChE,OAAO,EAAU,UAAU,IAAI,gBAAgB,EAAE,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAA;AAE1F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;;GAMG;AACH,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAA;AAE/B;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEjC;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAC7B,EAAE,EACF,KAAK,EACL,EAAE,GAAG,gBAAgB,CAAC,UAAU,GAAG,UAAU,CAAC,IAAI,GAAG,SAAS,GAAG,UAAU,CAgF5E,CAAA"}
package/dist/cjs/Jj.js ADDED
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var Jj_exports = {};
20
+ __export(Jj_exports, {
21
+ Jj: () => import_jj2.Jj,
22
+ layer: () => layer,
23
+ layerNoop: () => import_jj3.layerNoop,
24
+ make: () => import_jj4.make,
25
+ makeNoop: () => import_jj5.makeNoop
26
+ });
27
+ module.exports = __toCommonJS(Jj_exports);
28
+ var import_Permission = require("@smthrs/capability/Permission");
29
+ var import_jj = require("@smthrs/jj");
30
+ var import_effect = require("effect");
31
+ var import_FileSystem = require("./FileSystem.js");
32
+ var import_GrantStore = require("./GrantStore.js");
33
+ var import_makeCapability = require("./internal/makeCapability.js");
34
+ var import_Workspace = require("./Workspace.js");
35
+ var import_jj2 = require("@smthrs/jj");
36
+ var import_jj3 = require("@smthrs/jj");
37
+ var import_jj4 = require("@smthrs/jj");
38
+ var import_jj5 = require("@smthrs/jj");
39
+ const layer = import_effect.Layer.effect(
40
+ import_jj.Jj,
41
+ import_effect.Effect.gen(function* () {
42
+ const jj = yield* import_jj.Jj;
43
+ const jjRoot = jj.root;
44
+ const jjRevert = jj.revert;
45
+ const jjOpRestore = jj.opRestore;
46
+ const fileSystem = yield* import_effect.FileSystem.FileSystem;
47
+ const path = yield* import_effect.Path.Path;
48
+ const workspace = yield* import_Workspace.Workspace;
49
+ const grants = yield* import_GrantStore.GrantStore;
50
+ const check = (action, resource) => (0, import_makeCapability.makeCapability)(action, resource).pipe(import_effect.Effect.flatMap((capability) => grants.check(capability)));
51
+ return import_jj.Jj.of({
52
+ status: import_effect.Effect.fn("Jj.status")(() => check("jj:status", ".").pipe(import_effect.Effect.andThen(jj.status()))),
53
+ diff: import_effect.Effect.fn("Jj.diff")(
54
+ (from, to) => check("jj:diff", `${from}:${to}`).pipe(import_effect.Effect.andThen(jj.diff(from, to)))
55
+ ),
56
+ snapshot: import_effect.Effect.fn("Jj.snapshot")(
57
+ (message) => check("jj:snapshot", message ?? "").pipe(import_effect.Effect.andThen(jj.snapshot(message)))
58
+ ),
59
+ restore: import_effect.Effect.fn("Jj.restore")(
60
+ (revision) => check("jj:restore", revision).pipe(import_effect.Effect.andThen(jj.restore(revision)))
61
+ ),
62
+ workspaceAdd: import_effect.Effect.fn("Jj.workspaceAdd")(
63
+ (name, destination, revision) => (0, import_FileSystem.canonicalResource)(fileSystem, path, workspace.root, destination).pipe(
64
+ import_effect.Effect.flatMap(
65
+ (resource) => check("jj:workspace-add", resource).pipe(
66
+ import_effect.Effect.andThen(check("fs:write", resource)),
67
+ import_effect.Effect.andThen((0, import_FileSystem.canonicalResource)(fileSystem, path, workspace.root, destination)),
68
+ import_effect.Effect.flatMap(
69
+ (settled) => settled === resource ? jj.workspaceAdd(name, resource, revision) : (0, import_makeCapability.makeCapability)("jj:workspace-add", resource).pipe(
70
+ import_effect.Effect.flatMap(
71
+ (capability) => import_effect.Effect.fail((0, import_Permission.permissionDenied)(
72
+ capability,
73
+ "workspace destination no longer names the resource that was authorized"
74
+ ))
75
+ )
76
+ )
77
+ )
78
+ )
79
+ )
80
+ )
81
+ ),
82
+ workspaceForget: import_effect.Effect.fn("Jj.workspaceForget")(
83
+ (name) => check("jj:workspace-forget", name).pipe(import_effect.Effect.andThen(jj.workspaceForget(name)))
84
+ ),
85
+ // `root`, `revert`, and `opRestore` are optional on the service, so the decorator
86
+ // forwards the ABSENCE too. A backend that cannot revert must keep
87
+ // reading as a backend that cannot revert: replacing it with a guarded
88
+ // method that fails on call would turn "this host has no revert" into
89
+ // "your revert was refused", which is a different answer to a caller
90
+ // deciding what it can offer.
91
+ ...jjRoot === void 0 ? {} : {
92
+ root: import_effect.Effect.fn("Jj.root")(
93
+ (from) => (
94
+ // Canonicalized BEFORE the check, and the canonical path is what jj
95
+ // is then run in. Checking the caller's spelling and inspecting a
96
+ // different directory is the whole symlink-alias problem: an
97
+ // authorized name would decide the answer for a repository the grant
98
+ // never mentioned.
99
+ (0, import_FileSystem.canonicalResource)(fileSystem, path, workspace.root, from).pipe(
100
+ import_effect.Effect.flatMap((resource) => check("jj:root", resource).pipe(import_effect.Effect.andThen(jjRoot(resource))))
101
+ )
102
+ )
103
+ )
104
+ },
105
+ ...jjRevert === void 0 ? {} : {
106
+ revert: import_effect.Effect.fn("Jj.revert")(
107
+ (revision) => check("jj:revert", revision).pipe(import_effect.Effect.andThen(jjRevert(revision)))
108
+ )
109
+ },
110
+ ...jjOpRestore === void 0 ? {} : {
111
+ opRestore: import_effect.Effect.fn("Jj.opRestore")(
112
+ (operationId) => check("jj:op-restore", operationId).pipe(import_effect.Effect.andThen(jjOpRestore(operationId)))
113
+ )
114
+ }
115
+ });
116
+ })
117
+ );
118
+ //# sourceMappingURL=Jj.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/Jj.ts"],
4
+ "sourcesContent": ["/**\n * Permission-aware Jujutsu version-control operations.\n *\n * There is no kernel `Jj` interface and no kernel `Jj` tag. `@smthrs/jj` owns\n * both, and its error channel already names the failures the kernel adds, so\n * this module is only the middleware: a `Layer` over the same tag that reads\n * the raw service out of context and returns a guarded one in its place.\n *\n * Governing design:\n * `docs/specs/Concepts/Permission Kernel.md`,\n * `docs/specs/Concepts/Effect Taxonomy.md`, and\n * `docs/specs/Concepts/Host Adapters.md`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport type { Action } from \"@smthrs/capability/Capability\"\nimport { permissionDenied } from \"@smthrs/capability/Permission\"\nimport { Jj, type OperationId, type Revision } from \"@smthrs/jj\"\nimport { Effect, FileSystem as EffectFileSystem, Layer, Path as EffectPath } from \"effect\"\nimport { canonicalResource } from \"./FileSystem.ts\"\nimport { GrantStore } from \"./GrantStore.ts\"\nimport { makeCapability } from \"./internal/makeCapability.ts\"\nimport { Workspace } from \"./Workspace.ts\"\n\n/**\n * `@smthrs/jj`'s own Jujutsu tag, unchanged. Re-exported so the kernel\n * namespace stays one-stop; it is the *same* tag, never a second one.\n *\n * @category services\n * @since 1.0.0-rc.0\n */\nexport { Jj } from \"@smthrs/jj\"\n\n/**\n * Provides an unavailable Jujutsu stub.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport { layerNoop } from \"@smthrs/jj\"\n\n/**\n * Constructs a Jujutsu service from an implementation.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport { make } from \"@smthrs/jj\"\n\n/**\n * Constructs an unavailable Jujutsu stub.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport { makeNoop } from \"@smthrs/jj\"\n\n/**\n * Decorates the Jujutsu service in place with operation-specific capability\n * checks.\n *\n * The layer provides the tag it also requires: compose it over a host jj layer\n * with `Layer.provide` and every consumer of `Jj` \u2014 including one that never\n * heard of the kernel \u2014 resolves the guarded implementation.\n *\n * `workspaceAdd` canonicalizes its destination and `root` canonicalizes its\n * starting directory through the *raw* filesystem before asking for\n * `jj:workspace-add` and `fs:write`, or for `jj:root`, so an existing symlink\n * cannot turn an inside-workspace grant into outside authority or separate the\n * authorized path from the directory jj is run in.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer: Layer.Layer<\n Jj,\n never,\n Jj | EffectFileSystem.FileSystem | EffectPath.Path | Workspace | GrantStore\n> = Layer.effect(\n Jj,\n Effect.gen(function*() {\n const jj = yield* Jj\n const jjRoot = jj.root\n const jjRevert = jj.revert\n const jjOpRestore = jj.opRestore\n const fileSystem = yield* EffectFileSystem.FileSystem\n const path = yield* EffectPath.Path\n const workspace = yield* Workspace\n const grants = yield* GrantStore\n const check = (action: Action, resource: string) =>\n makeCapability(action, resource).pipe(Effect.flatMap((capability) => grants.check(capability)))\n return Jj.of({\n status: Effect.fn(\"Jj.status\")(() => check(\"jj:status\", \".\").pipe(Effect.andThen(jj.status()))),\n diff: Effect.fn(\"Jj.diff\")((from, to) =>\n check(\"jj:diff\", `${from}:${to}`).pipe(Effect.andThen(jj.diff(from, to)))\n ),\n snapshot: Effect.fn(\"Jj.snapshot\")((message) =>\n check(\"jj:snapshot\", message ?? \"\").pipe(Effect.andThen(jj.snapshot(message)))\n ),\n restore: Effect.fn(\"Jj.restore\")((revision) =>\n check(\"jj:restore\", revision).pipe(Effect.andThen(jj.restore(revision)))\n ),\n workspaceAdd: Effect.fn(\"Jj.workspaceAdd\")((name, destination, revision) =>\n canonicalResource(fileSystem, path, workspace.root, destination).pipe(\n Effect.flatMap((resource) =>\n check(\"jj:workspace-add\", resource).pipe(\n Effect.andThen(check(\"fs:write\", resource)),\n Effect.andThen(canonicalResource(fileSystem, path, workspace.root, destination)),\n Effect.flatMap((settled) =>\n settled === resource\n ? jj.workspaceAdd(name, resource, revision)\n : makeCapability(\"jj:workspace-add\", resource).pipe(\n Effect.flatMap((capability) =>\n Effect.fail(permissionDenied(\n capability,\n \"workspace destination no longer names the resource that was authorized\"\n ))\n )\n )\n )\n )\n )\n )\n ),\n workspaceForget: Effect.fn(\"Jj.workspaceForget\")((name) =>\n check(\"jj:workspace-forget\", name).pipe(Effect.andThen(jj.workspaceForget(name)))\n ),\n // `root`, `revert`, and `opRestore` are optional on the service, so the decorator\n // forwards the ABSENCE too. A backend that cannot revert must keep\n // reading as a backend that cannot revert: replacing it with a guarded\n // method that fails on call would turn \"this host has no revert\" into\n // \"your revert was refused\", which is a different answer to a caller\n // deciding what it can offer.\n ...jjRoot === undefined ? {} : {\n root: Effect.fn(\"Jj.root\")((from: string) =>\n // Canonicalized BEFORE the check, and the canonical path is what jj\n // is then run in. Checking the caller's spelling and inspecting a\n // different directory is the whole symlink-alias problem: an\n // authorized name would decide the answer for a repository the grant\n // never mentioned.\n canonicalResource(fileSystem, path, workspace.root, from).pipe(\n Effect.flatMap((resource) => check(\"jj:root\", resource).pipe(Effect.andThen(jjRoot(resource))))\n )\n )\n },\n ...jjRevert === undefined ? {} : {\n revert: Effect.fn(\"Jj.revert\")((revision: Revision) =>\n check(\"jj:revert\", revision).pipe(Effect.andThen(jjRevert(revision)))\n )\n },\n ...jjOpRestore === undefined ? {} : {\n opRestore: Effect.fn(\"Jj.opRestore\")((operationId: OperationId) =>\n check(\"jj:op-restore\", operationId).pipe(Effect.andThen(jjOpRestore(operationId)))\n )\n }\n })\n })\n)\n"],
5
+ "mappings": "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",
6
+ "names": ["import_jj", "EffectFileSystem", "EffectPath"]
7
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Journal-backed persistence and replay for capability decisions.
3
+ *
4
+ * Governing design:
5
+ * `docs/specs/Concepts/Permission Kernel.md` and
6
+ * `docs/specs/Concepts/Journal Queue.md`.
7
+ *
8
+ * @since 1.0.0-rc.0
9
+ */
10
+ import * as Capability from "@smthrs/capability/Capability";
11
+ import { GrantStoreError, Rule } from "@smthrs/capability/Permission";
12
+ import * as JournalModule from "@smthrs/journal/Journal";
13
+ import * as Effect from "effect/Effect";
14
+ import * as Layer from "effect/Layer";
15
+ import * as GrantStore from "./GrantStore.ts";
16
+ import { Workspace } from "./Workspace.ts";
17
+ /**
18
+ * Configuration for a journal-backed grant store.
19
+ *
20
+ * `policyRunId` is a deliberately dedicated run containing remembered-policy
21
+ * events. The journal has no global grant projection, so callers that want
22
+ * remembered grants to span operational runs must keep this id stable.
23
+ * `planDigest` binds run grants and envelopes to the exact active plan.
24
+ * `sourceId` is also checked during replay; events from other producers cannot
25
+ * activate kernel authority.
26
+ *
27
+ * The journal is authoritative permission storage: SqlJournal must use the
28
+ * `reject` overflow policy. Drop-capable overflow policies are unsupported,
29
+ * because a dropped grant decision cannot safely be treated as persisted.
30
+ *
31
+ * @category models
32
+ * @since 1.0.0-rc.0
33
+ */
34
+ export interface JournalGrantStoreOptions {
35
+ readonly runId: string;
36
+ readonly policyRunId: string;
37
+ readonly sourceId: string;
38
+ readonly planDigest: string;
39
+ readonly attended?: boolean;
40
+ readonly rules?: ReadonlyArray<ReadonlyArray<Rule>>;
41
+ readonly envelope?: {
42
+ readonly patterns: ReadonlyArray<Capability.CapabilityPattern>;
43
+ readonly scope?: "run" | "remembered" | undefined;
44
+ };
45
+ }
46
+ /**
47
+ * Makes a grant store that replays remembered policy from, and writes decisions
48
+ * to, the supplied journal.
49
+ *
50
+ * `emitDurable` commits before `GrantStore` activates a remembered or
51
+ * run-scoped rule (or resolves a denial). Any journal failure is mapped to
52
+ * `journal_failed`, so permission decisions fail closed.
53
+ *
54
+ * @category constructors
55
+ * @since 1.0.0-rc.0
56
+ */
57
+ export declare const make: (options: JournalGrantStoreOptions) => Effect.Effect<GrantStore.Service, GrantStoreError, import("effect/Scope").Scope | Workspace | JournalModule.Journal>;
58
+ /**
59
+ * Provides a journal-backed `GrantStore`.
60
+ *
61
+ * @category layers
62
+ * @since 1.0.0-rc.0
63
+ */
64
+ export declare const layer: (options: JournalGrantStoreOptions) => Layer.Layer<GrantStore.GrantStore, GrantStoreError, Workspace | JournalModule.Journal>;
65
+ //# sourceMappingURL=JournalGrantStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JournalGrantStore.d.ts","sourceRoot":"","sources":["../../src/JournalGrantStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,UAAU,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,KAAK,aAAa,MAAM,yBAAyB,CAAA;AAExD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAIrC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAA;QAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,YAAY,GAAG,SAAS,CAAA;KAClD,CAAA;CACF;AAoPD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,GAAI,SAAS,wBAAwB,yHAmJlD,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,SAAS,wBAAwB,2FAAuD,CAAA"}