@overkill-dev/run 0.0.64 → 0.0.66

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 (275) hide show
  1. package/attachments/attachment-context.js +41 -0
  2. package/attachments/attachment-context.js.map +1 -0
  3. package/attachments/failure-artifact-stream.js +53 -0
  4. package/attachments/failure-artifact-stream.js.map +1 -0
  5. package/attachments/resource-failure-context.js +41 -0
  6. package/attachments/resource-failure-context.js.map +1 -0
  7. package/engine/case-execution.d.ts +1 -0
  8. package/engine/case-execution.d.ts.map +1 -1
  9. package/engine/case-execution.js +17 -29
  10. package/engine/case-execution.js.map +1 -1
  11. package/engine/recorded-assertion-failure.js +30 -0
  12. package/engine/recorded-assertion-failure.js.map +1 -0
  13. package/engine/run-artifact.d.ts +2 -2
  14. package/engine/run-artifact.d.ts.map +1 -1
  15. package/engine/run-result.d.ts +5 -1
  16. package/engine/run-result.d.ts.map +1 -1
  17. package/engine/run-result.js.map +1 -1
  18. package/engine/runtime-attachment.d.ts +82 -0
  19. package/engine/runtime-attachment.d.ts.map +1 -0
  20. package/engine/runtime-attachment.js +7 -0
  21. package/engine/runtime-attachment.js.map +1 -0
  22. package/package-version.js +31 -0
  23. package/package-version.js.map +1 -0
  24. package/package.json +29 -3
  25. package/packages/resources/attachment-context.entry-point.js +2 -0
  26. package/packages/resources/attachment-context.entry-point.js.map +1 -0
  27. package/packages/run/config.entry-point.d.ts +1 -1
  28. package/packages/run/config.entry-point.d.ts.map +1 -1
  29. package/packages/run/run.entry-point.d.ts +1 -1
  30. package/packages/run/run.entry-point.d.ts.map +1 -1
  31. package/packages/simulation/transcript.entry-point.js +2 -0
  32. package/packages/simulation/transcript.entry-point.js.map +1 -1
  33. package/readme.md +41 -7
  34. package/reporters/human-reporter-rendering.js +59 -15
  35. package/reporters/human-reporter-rendering.js.map +1 -1
  36. package/resources/failure-artifacts.js +9 -0
  37. package/resources/failure-artifacts.js.map +1 -0
  38. package/resources/resource-definition-brand.js +1 -1
  39. package/resources/resource-definition-brand.js.map +1 -1
  40. package/resources/resource-definition-types.d.ts.map +1 -1
  41. package/resources/resource-scenario-binding.js +2 -0
  42. package/resources/resource-scenario-binding.js.map +1 -1
  43. package/resources/resource-session.d.ts.map +1 -1
  44. package/resources/runtime-definition.d.ts.map +1 -1
  45. package/resources/runtime-definition.js +1 -1
  46. package/resources/runtime-definition.js.map +1 -1
  47. package/resources/runtime-matrix-definition.d.ts.map +1 -1
  48. package/resources/runtime-matrix-definition.js +2 -2
  49. package/resources/runtime-matrix-definition.js.map +1 -1
  50. package/run/assertion-result-schema.js +69 -0
  51. package/run/assertion-result-schema.js.map +1 -0
  52. package/run/attachment-connection.js +108 -0
  53. package/run/attachment-connection.js.map +1 -0
  54. package/run/attachment-coordinator-context.js +9 -0
  55. package/run/attachment-coordinator-context.js.map +1 -0
  56. package/run/attachment-coordinator.js +81 -0
  57. package/run/attachment-coordinator.js.map +1 -0
  58. package/run/attachment-eligibility.js +21 -0
  59. package/run/attachment-eligibility.js.map +1 -0
  60. package/run/attachment-execution.js +302 -0
  61. package/run/attachment-execution.js.map +1 -0
  62. package/run/attachment-failure.js +63 -0
  63. package/run/attachment-failure.js.map +1 -0
  64. package/run/attachment-frames.js +22 -0
  65. package/run/attachment-frames.js.map +1 -0
  66. package/run/attachment-json.js +118 -0
  67. package/run/attachment-json.js.map +1 -0
  68. package/run/attachment-protocol.js +9 -0
  69. package/run/attachment-protocol.js.map +1 -0
  70. package/run/attachment-record.js +60 -0
  71. package/run/attachment-record.js.map +1 -0
  72. package/run/attachment-reporter.js +40 -0
  73. package/run/attachment-reporter.js.map +1 -0
  74. package/run/attachment-results.js +111 -0
  75. package/run/attachment-results.js.map +1 -0
  76. package/run/attachment-retention.js +153 -0
  77. package/run/attachment-retention.js.map +1 -0
  78. package/run/attachment-run.js +36 -0
  79. package/run/attachment-run.js.map +1 -0
  80. package/run/attachment-server.js +136 -0
  81. package/run/attachment-server.js.map +1 -0
  82. package/run/attachment-storage-session.js +22 -0
  83. package/run/attachment-storage-session.js.map +1 -0
  84. package/run/attachment-storage-writer.js +128 -0
  85. package/run/attachment-storage-writer.js.map +1 -0
  86. package/run/attachment-store.js +287 -0
  87. package/run/attachment-store.js.map +1 -0
  88. package/run/attachment-wire-schema.js +159 -0
  89. package/run/attachment-wire-schema.js.map +1 -0
  90. package/run/attachment-worker-context.js +49 -0
  91. package/run/attachment-worker-context.js.map +1 -0
  92. package/run/attachment-writer.js +119 -0
  93. package/run/attachment-writer.js.map +1 -0
  94. package/run/capability-policy-snapshots.d.ts +3 -2
  95. package/run/capability-policy-snapshots.d.ts.map +1 -1
  96. package/run/capability-policy-snapshots.js.map +1 -1
  97. package/run/capability-policy.js +48 -38
  98. package/run/capability-policy.js.map +1 -1
  99. package/run/child-process-protocol.js +17 -13
  100. package/run/child-process-protocol.js.map +1 -1
  101. package/run/child-process-shutdown.js +54 -0
  102. package/run/child-process-shutdown.js.map +1 -0
  103. package/run/collected-run-plan-schema.js +90 -0
  104. package/run/collected-run-plan-schema.js.map +1 -0
  105. package/run/coverage-config-schema.d.ts +6 -6
  106. package/run/coverage-runtime-source.js +5 -0
  107. package/run/coverage-runtime-source.js.map +1 -1
  108. package/run/coverage-source-selection.js +6 -2
  109. package/run/coverage-source-selection.js.map +1 -1
  110. package/run/current-process-run-orchestrator.js +7 -11
  111. package/run/current-process-run-orchestrator.js.map +1 -1
  112. package/run/diff-schema.js +78 -0
  113. package/run/diff-schema.js.map +1 -0
  114. package/run/failure-artifact-retention.js +76 -0
  115. package/run/failure-artifact-retention.js.map +1 -0
  116. package/run/node-child-process-starters.js +8 -1
  117. package/run/node-child-process-starters.js.map +1 -1
  118. package/run/node-process-policy-observation.js +43 -0
  119. package/run/node-process-policy-observation.js.map +1 -0
  120. package/run/permission-denial-runtime-policy.js +3 -0
  121. package/run/permission-denial-runtime-policy.js.map +1 -1
  122. package/run/reporter-event-schema.js +42 -0
  123. package/run/reporter-event-schema.js.map +1 -0
  124. package/run/resource-disposal-error.js +27 -0
  125. package/run/resource-disposal-error.js.map +1 -0
  126. package/run/resource-failure-preparation.js +86 -0
  127. package/run/resource-failure-preparation.js.map +1 -0
  128. package/run/resource-lifecycle-disposal.js +132 -0
  129. package/run/resource-lifecycle-disposal.js.map +1 -0
  130. package/run/resource-lifecycle-projection.js +6 -2
  131. package/run/resource-lifecycle-projection.js.map +1 -1
  132. package/run/resource-lifecycle-session-acquirer.js +31 -8
  133. package/run/resource-lifecycle-session-acquirer.js.map +1 -1
  134. package/run/resource-lifecycle-startup-budget.js +1 -0
  135. package/run/resource-lifecycle-startup-budget.js.map +1 -1
  136. package/run/resource-lifecycle-state.d.ts +2 -1
  137. package/run/resource-lifecycle-state.d.ts.map +1 -1
  138. package/run/resource-lifecycle-state.js +40 -1
  139. package/run/resource-lifecycle-state.js.map +1 -1
  140. package/run/resource-lifecycle.js +47 -107
  141. package/run/resource-lifecycle.js.map +1 -1
  142. package/run/retry-artifact-retention.js.map +1 -1
  143. package/run/run-artifact-id-schema.js +27 -0
  144. package/run/run-artifact-id-schema.js.map +1 -0
  145. package/run/run-artifact-schema.js +74 -0
  146. package/run/run-artifact-schema.js.map +1 -0
  147. package/run/run-collection-error-result.js +1 -1
  148. package/run/run-collection-error-result.js.map +1 -1
  149. package/run/run-command-schema.js +60 -0
  150. package/run/run-command-schema.js.map +1 -0
  151. package/run/run-config-schema.d.ts +25 -6
  152. package/run/run-config-schema.d.ts.map +1 -1
  153. package/run/run-config-schema.js +11 -0
  154. package/run/run-config-schema.js.map +1 -1
  155. package/run/run-config.d.ts +7 -5
  156. package/run/run-config.d.ts.map +1 -1
  157. package/run/run-config.js +2 -1
  158. package/run/run-config.js.map +1 -1
  159. package/run/run-engine-primitives.d.ts +12 -1
  160. package/run/run-engine-primitives.d.ts.map +1 -1
  161. package/run/run-errors.d.ts +2 -0
  162. package/run/run-errors.d.ts.map +1 -1
  163. package/run/run-errors.js +17 -0
  164. package/run/run-errors.js.map +1 -1
  165. package/run/run-facts.js +1 -0
  166. package/run/run-facts.js.map +1 -1
  167. package/run/run-identity-schema.js +38 -0
  168. package/run/run-identity-schema.js.map +1 -0
  169. package/run/run-isolated-command.js +1 -0
  170. package/run/run-isolated-command.js.map +1 -1
  171. package/run/run-local-command.js +20 -4
  172. package/run/run-local-command.js.map +1 -1
  173. package/run/run-local-coverage.js +16 -3
  174. package/run/run-local-coverage.js.map +1 -1
  175. package/run/run-local-execution.js +2 -1
  176. package/run/run-local-execution.js.map +1 -1
  177. package/run/run-local-resolution.js.map +1 -1
  178. package/run/run-orchestrator.d.ts +2 -2
  179. package/run/run-orchestrator.d.ts.map +1 -1
  180. package/run/run-orchestrator.js +2 -2
  181. package/run/run-orchestrator.js.map +1 -1
  182. package/run/run-record-input.js.map +1 -1
  183. package/run/run-record-outcomes.d.ts +4 -1
  184. package/run/run-record-outcomes.d.ts.map +1 -1
  185. package/run/run-record-versions.js +1 -30
  186. package/run/run-record-versions.js.map +1 -1
  187. package/run/run-record.js.map +1 -1
  188. package/run/run-result-schema.js +65 -0
  189. package/run/run-result-schema.js.map +1 -0
  190. package/run/run-runtime-schema.js +64 -0
  191. package/run/run-runtime-schema.js.map +1 -0
  192. package/run/run-support.js +10 -1
  193. package/run/run-support.js.map +1 -1
  194. package/run/run-types.d.ts +3 -4
  195. package/run/run-types.d.ts.map +1 -1
  196. package/run/run-types.js.map +1 -1
  197. package/run/run-validation.js +9 -0
  198. package/run/run-validation.js.map +1 -1
  199. package/run/runtime-attachment-boundary.js +11 -0
  200. package/run/runtime-attachment-boundary.js.map +1 -0
  201. package/run/serialized-value-schema.js +76 -0
  202. package/run/serialized-value-schema.js.map +1 -0
  203. package/run/simulation-witness.js +38 -0
  204. package/run/simulation-witness.js.map +1 -0
  205. package/run/supervised-child-failure.js +26 -0
  206. package/run/supervised-child-failure.js.map +1 -0
  207. package/run/supervised-child-process.d.ts +3 -0
  208. package/run/supervised-child-process.d.ts.map +1 -1
  209. package/run/supervised-child-process.js +2 -0
  210. package/run/supervised-child-process.js.map +1 -1
  211. package/run/supervised-child-transport.js +125 -0
  212. package/run/supervised-child-transport.js.map +1 -0
  213. package/run/supervised-child.entry-point.js +38 -33
  214. package/run/supervised-child.entry-point.js.map +1 -1
  215. package/run/supervised-child.js +13 -11
  216. package/run/supervised-child.js.map +1 -1
  217. package/run/supervised-protocol-schema.js +42 -0
  218. package/run/supervised-protocol-schema.js.map +1 -0
  219. package/run/supervised-protocol.js.map +1 -1
  220. package/run/supervised-run-collection.js +33 -30
  221. package/run/supervised-run-collection.js.map +1 -1
  222. package/run/supervised-run-runtime.js +36 -12
  223. package/run/supervised-run-runtime.js.map +1 -1
  224. package/run/supervised-run-state.js +43 -22
  225. package/run/supervised-run-state.js.map +1 -1
  226. package/run/supervised-run.js +80 -39
  227. package/run/supervised-run.js.map +1 -1
  228. package/run/worker-pool-command.js +1 -0
  229. package/run/worker-pool-command.js.map +1 -1
  230. package/run/worker-pool-execution.js +12 -5
  231. package/run/worker-pool-execution.js.map +1 -1
  232. package/run/worker-pool-hedged-arbitration.js +7 -2
  233. package/run/worker-pool-hedged-arbitration.js.map +1 -1
  234. package/run/worker-pool-host-process.js +50 -20
  235. package/run/worker-pool-host-process.js.map +1 -1
  236. package/run/worker-pool-host-protocol-schema.js +80 -0
  237. package/run/worker-pool-host-protocol-schema.js.map +1 -0
  238. package/run/worker-pool-host-protocol.js.map +1 -1
  239. package/run/worker-pool-host-task.js +20 -11
  240. package/run/worker-pool-host-task.js.map +1 -1
  241. package/run/worker-pool-host-transport.js +96 -0
  242. package/run/worker-pool-host-transport.js.map +1 -0
  243. package/run/worker-pool-host.entry-point.js +37 -5
  244. package/run/worker-pool-host.entry-point.js.map +1 -1
  245. package/run/worker-pool-protocol.js +3 -0
  246. package/run/worker-pool-protocol.js.map +1 -1
  247. package/run/worker-pool-resource-lifecycle-execution.js +66 -1
  248. package/run/worker-pool-resource-lifecycle-execution.js.map +1 -1
  249. package/run/worker-pool-routing.js +2 -1
  250. package/run/worker-pool-routing.js.map +1 -1
  251. package/run/worker-pool-run.js +8 -1
  252. package/run/worker-pool-run.js.map +1 -1
  253. package/run/worker-pool-runtime.js +3 -7
  254. package/run/worker-pool-runtime.js.map +1 -1
  255. package/run/worker-pool-task-events.js +20 -14
  256. package/run/worker-pool-task-events.js.map +1 -1
  257. package/run/worker-pool-task-schema.js +61 -0
  258. package/run/worker-pool-task-schema.js.map +1 -0
  259. package/run/worker-pool-task-validation.js +1 -0
  260. package/run/worker-pool-task-validation.js.map +1 -1
  261. package/run/worker-pool-worker-resources.js +68 -0
  262. package/run/worker-pool-worker-resources.js.map +1 -1
  263. package/run/worker-pool-worker.js +25 -8
  264. package/run/worker-pool-worker.js.map +1 -1
  265. package/sbom.cdx.json +5 -5
  266. package/stored-value.js +12 -0
  267. package/stored-value.js.map +1 -0
  268. package/transcript/http-transcript-artifact.js +2 -0
  269. package/transcript/http-transcript-artifact.js.map +1 -0
  270. package/transcript/transcript-store.d.ts +1 -1
  271. package/transcript/transcript-store.d.ts.map +1 -1
  272. package/transcript/transcript-store.js +29 -3
  273. package/transcript/transcript-store.js.map +1 -1
  274. package/run/node-process-capability-restrictions.js +0 -92
  275. package/run/node-process-capability-restrictions.js.map +0 -1
@@ -0,0 +1,36 @@
1
+ import { createAttachmentStorageSession } from "./attachment-storage-session.js";
2
+ import { createAttachmentRecord } from "./attachment-record.js";
3
+ import { createAttachmentRunCoordinator } from "./attachment-coordinator.js";
4
+ import { runWithAttachmentExecution } from "./resource-lifecycle-state.js";
5
+ import { runWithAttachmentCoordinator } from "./attachment-coordinator-context.js";
6
+ import { runHasAttachmentScopes } from "./attachment-eligibility.js";
7
+ async function executeAttachmentSession(record, coordinator, run) {
8
+ try {
9
+ const result = await runWithAttachmentCoordinator(coordinator, async function () {
10
+ return runWithAttachmentExecution(coordinator.execution, run);
11
+ });
12
+ return await record.session.complete(await coordinator.finalize(result));
13
+ }
14
+ catch (error) {
15
+ await coordinator.close();
16
+ try {
17
+ await record.checkpoint(coordinator.artifacts());
18
+ }
19
+ finally {
20
+ await record.session.interrupt(error);
21
+ }
22
+ throw error;
23
+ }
24
+ finally {
25
+ await coordinator.close();
26
+ }
27
+ }
28
+ export async function executeWithAttachments(resolved, dependencies, run) {
29
+ if (!runHasAttachmentScopes(resolved)) {
30
+ return await run();
31
+ }
32
+ const record = await createAttachmentRecord(resolved, dependencies);
33
+ const coordinator = createAttachmentRunCoordinator(await createAttachmentStorageSession(resolved, record));
34
+ return await executeAttachmentSession(record, coordinator, run);
35
+ }
36
+ //# sourceMappingURL=attachment-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-run.js","sourceRoot":"","sources":["../../../../source/run/attachment-run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAyB,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,8BAA8B,EAAiC,MAAM,6BAA6B,CAAC;AAC5G,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAIrE,KAAK,UAAU,wBAAwB,CACnC,MAAwB,EACxB,WAAqC,EACrC,GAA6B;IAE7B,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAC7C,WAAW,EACX,KAAK;YACD,OAAO,0BAA0B,CAAC,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAClE,CAAC,CACJ,CAAC;QACF,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACtB,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC;YACD,MAAM,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC;QACrD,CAAC;gBAAS,CAAC;YACP,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,KAAK,CAAC;IAChB,CAAC;YAAS,CAAC;QACP,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CACxC,QAAqB,EACrB,YAAyC,EACzC,GAA6B;IAE7B,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,OAAO,MAAM,GAAG,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,8BAA8B,CAAC,MAAM,8BAA8B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3G,OAAO,MAAM,wBAAwB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;AACpE,CAAC"}
@@ -0,0 +1,136 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { createServer } from 'node:net';
3
+ import { createInterface } from 'node:readline';
4
+ import { createStoredRunValue } from "./supervised-run-state.js";
5
+ import { attachmentMaxFrameBytes, attachmentMaxPendingRequests } from "./attachment-protocol.js";
6
+ import { attachmentRequestSchema } from "./attachment-wire-schema.js";
7
+ import { boundedAttachmentFrames } from "./attachment-frames.js";
8
+ async function attachmentServerChannelsReply(state, line, socket, channel) {
9
+ const { store } = state;
10
+ const value = JSON.parse(line);
11
+ const request = attachmentRequestSchema.parse(value);
12
+ if (request.token !== state.token) {
13
+ throw new Error('Invalid attachment execution token.');
14
+ }
15
+ const result = await store.exchange(channel, request.operation);
16
+ await new Promise(function acknowledgeAttachment(resolve, reject) {
17
+ socket.write(`${JSON.stringify({ request: request.request, result })}\n`, function attachmentSent(error) {
18
+ if (error === undefined || error === null) {
19
+ resolve();
20
+ }
21
+ else {
22
+ reject(error);
23
+ }
24
+ });
25
+ });
26
+ }
27
+ async function attachmentServerChannelsRequest(state, request) {
28
+ const { line, socket, channel, previous } = request;
29
+ await previous;
30
+ try {
31
+ await attachmentServerChannelsReply(state, line, socket, channel);
32
+ }
33
+ catch {
34
+ socket.destroy();
35
+ }
36
+ finally {
37
+ request.queued.write(request.queued.read() - 1);
38
+ }
39
+ }
40
+ async function attachmentServerChannelsInterrupt(state, channel, previous) {
41
+ const { abandoned, store } = state;
42
+ await previous;
43
+ abandoned.push(...await store.finish(channel));
44
+ }
45
+ function observeAttachmentChannelFailures(socket, frames, lines) {
46
+ frames.on('error', function () {
47
+ socket.destroy();
48
+ });
49
+ lines.on('error', function () {
50
+ socket.destroy();
51
+ });
52
+ socket.on('error', function () {
53
+ socket.destroy();
54
+ });
55
+ }
56
+ function attachmentServerChannelsAccept(state, socket) {
57
+ const { sockets } = state;
58
+ sockets.add(socket);
59
+ const channel = randomUUID();
60
+ const frames = boundedAttachmentFrames(attachmentMaxFrameBytes);
61
+ const lines = createInterface({ input: socket.pipe(frames), crlfDelay: Number.POSITIVE_INFINITY });
62
+ let queue = Promise.resolve();
63
+ const queued = createStoredRunValue(0);
64
+ observeAttachmentChannelFailures(socket, frames, lines);
65
+ lines.on('line', function receiveAttachmentLine(line) {
66
+ if (queued.read() >= attachmentMaxPendingRequests) {
67
+ socket.destroy();
68
+ return;
69
+ }
70
+ queued.write(queued.read() + 1);
71
+ state.operations.delete(queue);
72
+ queue = attachmentServerChannelsRequest(state, { line, socket, channel, previous: queue, queued });
73
+ state.operations.add(queue);
74
+ });
75
+ socket.on('close', function attachmentChannelClosed() {
76
+ sockets.delete(socket);
77
+ lines.close();
78
+ state.operations.delete(queue);
79
+ const interrupted = attachmentServerChannelsInterrupt(state, channel, queue);
80
+ state.operations.add(interrupted);
81
+ });
82
+ }
83
+ async function attachmentServerChannelsFinish(state, server) {
84
+ const { store } = state;
85
+ await Promise.all(state.operations.values());
86
+ const owners = [...state.abandoned.values(), ...await store.finish(null)];
87
+ for (const socket of state.sockets.values()) {
88
+ socket.destroy();
89
+ }
90
+ await new Promise(function closeAttachmentServer(resolve, reject) {
91
+ server.close(function attachmentServerClosed(error) {
92
+ if (error === undefined) {
93
+ resolve();
94
+ }
95
+ else {
96
+ reject(error);
97
+ }
98
+ });
99
+ });
100
+ await Promise.all(state.operations.values());
101
+ return owners;
102
+ }
103
+ function createAttachmentServerChannels(store, token) {
104
+ const sockets = new Set();
105
+ const operations = new Set();
106
+ const abandoned = [];
107
+ const state = { store, token, sockets, operations, abandoned };
108
+ return {
109
+ accept: attachmentServerChannelsAccept.bind(null, state),
110
+ finish: attachmentServerChannelsFinish.bind(null, state)
111
+ };
112
+ }
113
+ export async function createAttachmentServer(store, limits) {
114
+ const token = randomUUID();
115
+ const channels = createAttachmentServerChannels(store, token);
116
+ const server = createServer(function (socket) {
117
+ channels.accept(socket);
118
+ });
119
+ await new Promise(function listenForAttachments(resolve, reject) {
120
+ server.once('error', reject);
121
+ server.listen(0, '127.0.0.1', resolve);
122
+ });
123
+ const address = server.address();
124
+ if (address === null || typeof address === 'string') {
125
+ throw new Error('Attachment server did not obtain an execution address.');
126
+ }
127
+ let finishing = null;
128
+ return {
129
+ endpoint: { branch: null, limits, port: address.port, token },
130
+ async finish() {
131
+ finishing = finishing ?? channels.finish(server);
132
+ return await finishing;
133
+ }
134
+ };
135
+ }
136
+ //# sourceMappingURL=attachment-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-server.js","sourceRoot":"","sources":["../../../../source/run/attachment-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import path from 'node:path';
2
+ import { createAttachmentStore } from "./attachment-store.js";
3
+ import { createAttachmentServer } from "./attachment-server.js";
4
+ export async function createAttachmentStorageSession(resolved, record) {
5
+ const limits = resolved.facts.execution.attachments;
6
+ if (limits === null) {
7
+ throw new TypeError('Runtime attachments require integration limits.');
8
+ }
9
+ const store = createAttachmentStore({
10
+ witnessDirectory: path.resolve(resolved.facts.environment.projectRoot, resolved.config.runtimeStateDir, 'witnesses', record.session.id),
11
+ captureTime: record.captureTime,
12
+ checkpoint: record.checkpoint,
13
+ directory: path.resolve(resolved.facts.environment.projectRoot, resolved.config.runtimeStateDir, 'runs', record.session.id, 'artifacts'),
14
+ limits,
15
+ projectRoot: resolved.facts.environment.projectRoot,
16
+ work: resolved.facts.cases.map(function workIdentity(entry) {
17
+ return entry.workId;
18
+ })
19
+ });
20
+ return { resolved, server: await createAttachmentServer(store, limits), store };
21
+ }
22
+ //# sourceMappingURL=attachment-storage-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-storage-session.js","sourceRoot":"","sources":["../../../../source/run/attachment-storage-session.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,qBAAqB,EAAwB,MAAM,uBAAuB,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAyB,MAAM,wBAAwB,CAAC;AASvF,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAChD,QAAqB,EACrB,MAAwB;IAExB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IACpD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,KAAK,GAAG,qBAAqB,CAAC;QAChC,gBAAgB,EAAE,IAAI,CAAC,OAAO,CAC1B,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EACtC,QAAQ,CAAC,MAAM,CAAC,eAAe,EAC/B,WAAW,EACX,MAAM,CAAC,OAAO,CAAC,EAAE,CACpB;QACD,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,IAAI,CAAC,OAAO,CACnB,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EACtC,QAAQ,CAAC,MAAM,CAAC,eAAe,EAC/B,MAAM,EACN,MAAM,CAAC,OAAO,CAAC,EAAE,EACjB,WAAW,CACd;QACD,MAAM;QACN,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW;QACnD,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,YAAY,CAAC,KAAK;YACtD,OAAO,KAAK,CAAC,MAAM,CAAC;QACxB,CAAC,CAAC;KACL,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;AACpF,CAAC"}
@@ -0,0 +1,128 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+ import { attachmentScopeKey } from "./attachment-protocol.js";
4
+ import { createStoredRunValue } from "./supervised-run-state.js";
5
+ export function createAttachmentScopeBudget() {
6
+ const bytes = createStoredRunValue(0);
7
+ const count = createStoredRunValue(0);
8
+ function reserve(limits) {
9
+ if (count.read() >= limits.maxScopeAttachments) {
10
+ throw new Error('Attachment count limit exceeded.');
11
+ }
12
+ count.write(count.read() + 1);
13
+ }
14
+ function available(limits) {
15
+ return limits.maxScopeBytes - bytes.read();
16
+ }
17
+ function retained(retainedBytes) {
18
+ bytes.write(bytes.read() + retainedBytes);
19
+ }
20
+ return {
21
+ reserve,
22
+ available,
23
+ retained,
24
+ release(releasedBytes) {
25
+ bytes.write(Math.max(0, bytes.read() - releasedBytes));
26
+ count.write(Math.max(0, count.read() - 1));
27
+ }
28
+ };
29
+ }
30
+ function storedAttachmentArtifact(state) {
31
+ const { initial, retention } = state;
32
+ return { ...state.initial, payload: { ...initial.payload, content: retention.content() } };
33
+ }
34
+ async function storedAttachmentClose(state, reason) {
35
+ const { closed, retention } = state;
36
+ if (closed.read()) {
37
+ return;
38
+ }
39
+ closed.write(true);
40
+ await retention.finish(reason === 'complete' ? { kind: 'complete' } : { kind: 'incomplete', reason });
41
+ }
42
+ async function storedAttachmentInterrupt(state, reason) {
43
+ const { closed, retention, failed } = state;
44
+ if (closed.read()) {
45
+ return null;
46
+ }
47
+ closed.write(true);
48
+ await retention.finish({ kind: 'incomplete', reason });
49
+ return failed.read() ? null : state.owner;
50
+ }
51
+ function storedAttachmentAssertOpen(state) {
52
+ const { closed, failed } = state;
53
+ if (closed.read() || failed.read()) {
54
+ throw new Error('Attachment writer is closed.');
55
+ }
56
+ }
57
+ function storedAttachmentOmit(state) {
58
+ const { retention } = state;
59
+ storedAttachmentAssertOpen(state);
60
+ retention.omit();
61
+ }
62
+ async function storedAttachmentRetain(state, bytes, limits) {
63
+ const { retention, budget, failed } = state;
64
+ try {
65
+ return await retention.retain(bytes, budget.available(limits));
66
+ }
67
+ catch (error) {
68
+ failed.write(true);
69
+ await storedAttachmentClose(state, 'write-error');
70
+ throw error;
71
+ }
72
+ }
73
+ function retainChargedBytes(state, retained) {
74
+ state.budget.retained(retained);
75
+ state.charged.write(state.charged.read() + retained);
76
+ }
77
+ async function storedAttachmentWrite(state, data, limits) {
78
+ const { initial, failed, retention } = state;
79
+ storedAttachmentAssertOpen(state);
80
+ const bytes = Buffer.from(data, 'base64');
81
+ const retained = await storedAttachmentRetain(state, bytes, limits);
82
+ retainChargedBytes(state, retained);
83
+ if (retained < bytes.length && initial.payload.content.kind === 'file') {
84
+ failed.write(true);
85
+ await retention.finish({ kind: 'incomplete', reason: 'byte-limit' });
86
+ return { kind: 'error', message: 'Binary attachment byte limit exceeded.', reason: 'byte-limit' };
87
+ }
88
+ return { kind: 'written' };
89
+ }
90
+ export function createStoredAttachment(channel, operation, content) {
91
+ const { initial, retention, budget } = content;
92
+ const branch = operation.branch;
93
+ const owner = operation.owner;
94
+ const closed = createStoredRunValue(false);
95
+ const failed = createStoredRunValue(false);
96
+ const state = {
97
+ channel,
98
+ operation,
99
+ initial,
100
+ retention,
101
+ budget,
102
+ branch,
103
+ owner,
104
+ closed,
105
+ failed,
106
+ charged: createStoredRunValue(0)
107
+ };
108
+ return {
109
+ release() {
110
+ budget.release(state.charged.read());
111
+ },
112
+ channel: state.channel,
113
+ branch: state.branch,
114
+ owner: state.owner,
115
+ artifact: storedAttachmentArtifact.bind(null, state),
116
+ close: storedAttachmentClose.bind(null, state),
117
+ interrupt: storedAttachmentInterrupt.bind(null, state),
118
+ omit: storedAttachmentOmit.bind(null, state),
119
+ write: storedAttachmentWrite.bind(null, state)
120
+ };
121
+ }
122
+ export function retainedAttachmentPath(options, operation, writer) {
123
+ const folder = createHash('sha256').update(attachmentScopeKey(operation.owner)).digest('hex');
124
+ return operation.kind === 'prepare' && operation.subtype === 'witness'
125
+ ? path.join(options.witnessDirectory, folder, operation.owner.kind === 'case' ? `attempt-${operation.owner.attempt.index}` : 'run', `${writer}.witness.json`)
126
+ : path.join(options.directory, folder, `${writer}.attachment.bin`);
127
+ }
128
+ //# sourceMappingURL=attachment-storage-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-storage-writer.js","sourceRoot":"","sources":["../../../../source/run/attachment-storage-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,287 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { workIdentityKey } from "../engine/identity.js";
4
+ import { createFailureArtifactRetention } from "./failure-artifact-retention.js";
5
+ import { retainedAttachmentPath, createAttachmentScopeBudget, createStoredAttachment } from "./attachment-storage-writer.js";
6
+ import { createStoredRunValue } from "./supervised-run-state.js";
7
+ import { attachmentScopeKey, attachmentMetadataBytes } from "./attachment-protocol.js";
8
+ import { createAttachmentRetention } from "./attachment-retention.js";
9
+ function attachmentId(owner, sequence) {
10
+ if (owner.kind === 'run') {
11
+ return { attempt: null, runtimes: [], scope: { kind: 'run' }, sequence, subtype: 'attachment', workload: null };
12
+ }
13
+ return {
14
+ attempt: owner.attempt,
15
+ runtimes: owner.work.runtimes,
16
+ scope: { activeCases: [owner.work.case], case: owner.work.case, confidence: 'active-case', kind: 'case' },
17
+ sequence,
18
+ subtype: 'attachment',
19
+ workload: owner.work.workload
20
+ };
21
+ }
22
+ const firstPrintableCodePoint = 32;
23
+ const deleteCodePoint = 127;
24
+ function isControlCharacter(character) {
25
+ const code = character.codePointAt(0) ?? 0;
26
+ return code < firstPrintableCodePoint || code === deleteCodePoint;
27
+ }
28
+ function validateMetadata(operation) {
29
+ for (const value of [operation.metadata.name, operation.metadata.mediaType]) {
30
+ if (value.length === 0 || Buffer.byteLength(value) > attachmentMetadataBytes ||
31
+ Array.from(value).some(isControlCharacter)) {
32
+ throw new TypeError('Attachment names and media types require 1 to 256 bytes without control characters.');
33
+ }
34
+ }
35
+ }
36
+ function runAttachmentStoreArtifacts(state) {
37
+ const { writers } = state;
38
+ return Array.from(writers.values(), function currentArtifact(writer) {
39
+ return writer.artifact();
40
+ });
41
+ }
42
+ function runAttachmentStoreRegisterBranch(state, branch, retain) {
43
+ const { branches } = state;
44
+ branches.set(branch, retain);
45
+ }
46
+ function retainedArtifact(writer) {
47
+ const artifact = writer.artifact();
48
+ return artifact.payload.capture === 'opt-in' ? artifact : {
49
+ ...artifact,
50
+ payload: { ...artifact.payload, retention: { ...artifact.payload.retention, state: 'retained' } }
51
+ };
52
+ }
53
+ function runAttachmentStoreBranchArtifacts(state, branch) {
54
+ const { writers } = state;
55
+ return Array
56
+ .from(writers.values())
57
+ .filter(function inBranch(writer) {
58
+ return writer.branch === branch && state.failureRetention.retains(writer);
59
+ })
60
+ .map(retainedArtifact);
61
+ }
62
+ function runAttachmentStoreRetainsBranch(state, branch) {
63
+ return branch === null || state.branches.get(branch)?.() === true;
64
+ }
65
+ function runAttachmentStoreRetains(state, writer) {
66
+ const artifact = writer.artifact();
67
+ return runAttachmentStoreRetainsBranch(state, writer.branch) &&
68
+ (artifact.payload.capture === 'opt-in' || state.failureRetention.retains(writer));
69
+ }
70
+ function runAttachmentStoreSelectedArtifacts(state) {
71
+ const { writers } = state;
72
+ return Array
73
+ .from(writers.values())
74
+ .filter(function (writer) {
75
+ return runAttachmentStoreRetains(state, writer);
76
+ })
77
+ .map(retainedArtifact);
78
+ }
79
+ function runAttachmentStoreValidateOwner(state, operation) {
80
+ const { branches, planned } = state;
81
+ validateMetadata(operation);
82
+ if (operation.branch !== null && !branches.has(operation.branch)) {
83
+ throw new TypeError('Unknown attachment execution branch.');
84
+ }
85
+ if (operation.owner.kind === 'case' && !planned.has(workIdentityKey(operation.owner.work))) {
86
+ throw new TypeError('Attachment owner is outside the selected work.');
87
+ }
88
+ }
89
+ function runAttachmentStoreScopeBudget(state, channel, operation) {
90
+ const { budgets, options } = state;
91
+ const key = operation.owner.kind === 'run'
92
+ ? 'run'
93
+ : `${operation.branch ?? channel}:${attachmentScopeKey(operation.owner)}`;
94
+ const budget = budgets.get(key) ?? createAttachmentScopeBudget();
95
+ budgets.set(key, budget);
96
+ budget.reserve(options.limits);
97
+ return budget;
98
+ }
99
+ function runAttachmentStoreInitialArtifact(state, operation, writer, retention) {
100
+ return {
101
+ id: {
102
+ ...attachmentId(operation.owner, writer),
103
+ subtype: operation.kind === 'prepare' ? operation.subtype : 'attachment'
104
+ },
105
+ source: operation.kind === 'prepare' ? operation.source : 'instrumented',
106
+ payload: {
107
+ ...operation.metadata,
108
+ ...operation.kind === 'prepare'
109
+ ? {
110
+ capture: 'automatic',
111
+ retention: { condition: operation.condition, state: 'prepared' }
112
+ }
113
+ : { capture: 'opt-in' },
114
+ capturedAtMicroseconds: state.options.captureTime(),
115
+ content: retention.content(),
116
+ kind: 'runtime-attachment',
117
+ producer: operation.producer
118
+ }
119
+ };
120
+ }
121
+ async function createRetainedAttachment(state, creation) {
122
+ const { channel, operation, writer, filePath, limit, budget } = creation;
123
+ const retention = await createAttachmentRetention(operation.contentKind, state.options.projectRoot, filePath, limit);
124
+ try {
125
+ return createStoredAttachment(channel, operation, {
126
+ initial: runAttachmentStoreInitialArtifact(state, operation, writer, retention),
127
+ retention,
128
+ budget
129
+ });
130
+ }
131
+ catch (error) {
132
+ await retention.finish({ kind: 'incomplete', reason: 'write-error' });
133
+ await rm(filePath, { force: true });
134
+ throw error;
135
+ }
136
+ }
137
+ async function runAttachmentStoreCreateWriter(state, channel, operation) {
138
+ const { sequence, options, writers } = state;
139
+ const budget = runAttachmentStoreScopeBudget(state, channel, operation);
140
+ const writer = sequence.read();
141
+ sequence.write(sequence.read() + 1);
142
+ const filePath = retainedAttachmentPath(options, operation, writer);
143
+ const limit = operation.contentKind === 'binary' || operation.kind === 'prepare' && operation.subtype === 'witness'
144
+ ? options.limits.maxArtifactBytes
145
+ : options.limits.maxInlineBytes;
146
+ writers.set(writer, await createRetainedAttachment(state, { channel, operation, writer, filePath, limit, budget }));
147
+ return writer;
148
+ }
149
+ async function runAttachmentStoreStart(state, channel, operation) {
150
+ const { options } = state;
151
+ runAttachmentStoreValidateOwner(state, operation);
152
+ const writer = await runAttachmentStoreCreateWriter(state, channel, operation);
153
+ if (operation.contentKind === 'binary') {
154
+ await options.checkpoint(runAttachmentStoreArtifacts(state));
155
+ }
156
+ return { kind: 'opened', writer };
157
+ }
158
+ async function checkpointCapturedWrite(state, writer, data) {
159
+ const response = await writer.write(data, state.options.limits);
160
+ if (writer.artifact().payload.capture === 'automatic') {
161
+ await state.options.checkpoint(runAttachmentStoreArtifacts(state));
162
+ }
163
+ return response;
164
+ }
165
+ async function processAttachmentWriterOperation(state, writer, operation) {
166
+ if (operation.kind === 'close') {
167
+ await writer.close(operation.reason);
168
+ await state.options.checkpoint(runAttachmentStoreArtifacts(state));
169
+ return { kind: 'closed', artifact: writer.artifact() };
170
+ }
171
+ if (operation.kind === 'omit') {
172
+ writer.omit();
173
+ return { kind: 'written' };
174
+ }
175
+ return await checkpointCapturedWrite(state, writer, operation.data);
176
+ }
177
+ function registerResourceEvidence(state, channel, operation) {
178
+ if (operation.kind === 'resource-consumer') {
179
+ if (!state.planned.has(workIdentityKey(operation.work))) {
180
+ throw new TypeError('Resource consumer is outside selected work.');
181
+ }
182
+ state.failureRetention.consume(channel, operation.boundary, operation.work);
183
+ }
184
+ else {
185
+ state.failureRetention.markResourceFailure(channel, operation.boundary);
186
+ }
187
+ return { kind: 'written' };
188
+ }
189
+ function isOpenOperation(operation) {
190
+ return operation.kind === 'open' || operation.kind === 'prepare';
191
+ }
192
+ async function runAttachmentStoreProcessOperation(state, channel, operation) {
193
+ if (operation.kind === 'resource-consumer' || operation.kind === 'resource-failure') {
194
+ return registerResourceEvidence(state, channel, operation);
195
+ }
196
+ if (isOpenOperation(operation)) {
197
+ return await runAttachmentStoreStart(state, channel, operation);
198
+ }
199
+ const writer = state.writers.get(operation.writer);
200
+ if (writer?.channel !== channel) {
201
+ throw new TypeError('Unknown attachment writer.');
202
+ }
203
+ return await processAttachmentWriterOperation(state, writer, operation);
204
+ }
205
+ async function runAttachmentStoreExchange(state, channel, operation) {
206
+ try {
207
+ return await runAttachmentStoreProcessOperation(state, channel, operation);
208
+ }
209
+ catch (error) {
210
+ return {
211
+ kind: 'error',
212
+ message: error instanceof Error ? error.message : 'Attachment operation failed.',
213
+ reason: 'operation-error'
214
+ };
215
+ }
216
+ }
217
+ async function finishStoredAttachment(state, channel, writer) {
218
+ const owner = await writer.interrupt(channel === null && !state.failureRetention.interrupted() ? 'unclosed' : 'interrupted');
219
+ return writer.artifact().payload.capture === 'opt-in' && runAttachmentStoreRetains(state, writer) ? owner : null;
220
+ }
221
+ async function runAttachmentStoreFinish(state, channel) {
222
+ const { writers } = state;
223
+ const owners = [];
224
+ const selected = Array.from(writers.values()).filter(function inChannel(writer) {
225
+ return channel === null || writer.channel === channel;
226
+ });
227
+ for (const writer of selected) {
228
+ const owner = await finishStoredAttachment(state, channel, writer);
229
+ if (owner !== null) {
230
+ owners.push(owner);
231
+ }
232
+ }
233
+ return owners;
234
+ }
235
+ async function runAttachmentStorePrune(state, retainedArtifacts) {
236
+ const { options, writers } = state;
237
+ const retained = new Set(retainedArtifacts.map(function artifactSequence(artifact) {
238
+ return artifact.id.sequence;
239
+ }));
240
+ const discarded = runAttachmentStoreArtifacts(state).filter(function discardedArtifact(artifact) {
241
+ return !retained.has(artifact.id.sequence);
242
+ });
243
+ for (const artifact of discarded) {
244
+ if (artifact.payload.content.kind === 'file') {
245
+ await rm(path.resolve(options.projectRoot, artifact.payload.content.path), { force: true });
246
+ }
247
+ writers.get(artifact.id.sequence)?.release();
248
+ writers.delete(artifact.id.sequence);
249
+ }
250
+ }
251
+ export function createAttachmentStore(options) {
252
+ const writers = new Map();
253
+ const branches = new Map();
254
+ const budgets = new Map();
255
+ const planned = new Set(options.work.map(workIdentityKey));
256
+ const sequence = createStoredRunValue(0);
257
+ const state = {
258
+ options,
259
+ writers,
260
+ branches,
261
+ budgets,
262
+ planned,
263
+ sequence,
264
+ failureRetention: createFailureArtifactRetention()
265
+ };
266
+ return {
267
+ settleAttempt: state.failureRetention.settleAttempt,
268
+ settleResult: state.failureRetention.settleResult,
269
+ artifacts: runAttachmentStoreArtifacts.bind(null, state),
270
+ retainsBranch: runAttachmentStoreRetainsBranch.bind(null, state),
271
+ registerBranch: runAttachmentStoreRegisterBranch.bind(null, state),
272
+ conflictArtifacts(branch) {
273
+ return Array
274
+ .from(writers.values())
275
+ .filter(function conflictBranch(writer) {
276
+ return writer.branch === branch;
277
+ })
278
+ .map(retainedArtifact);
279
+ },
280
+ branchArtifacts: runAttachmentStoreBranchArtifacts.bind(null, state),
281
+ selectedArtifacts: runAttachmentStoreSelectedArtifacts.bind(null, state),
282
+ exchange: runAttachmentStoreExchange.bind(null, state),
283
+ finish: runAttachmentStoreFinish.bind(null, state),
284
+ prune: runAttachmentStorePrune.bind(null, state)
285
+ };
286
+ }
287
+ //# sourceMappingURL=attachment-store.js.map