@milaboratories/pl-client 3.11.5 → 3.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/core/PromiseTracker.cjs.map +1 -1
  2. package/dist/core/PromiseTracker.d.ts.map +1 -1
  3. package/dist/core/PromiseTracker.js.map +1 -1
  4. package/dist/core/StatefulPromise.cjs +2 -0
  5. package/dist/core/StatefulPromise.cjs.map +1 -1
  6. package/dist/core/StatefulPromise.js +2 -0
  7. package/dist/core/StatefulPromise.js.map +1 -1
  8. package/dist/core/abstract_stream.d.ts +1 -1
  9. package/dist/core/advisory_locks.cjs.map +1 -1
  10. package/dist/core/advisory_locks.js.map +1 -1
  11. package/dist/core/auth.cjs.map +1 -1
  12. package/dist/core/auth.d.ts.map +1 -1
  13. package/dist/core/auth.js.map +1 -1
  14. package/dist/core/cache.d.ts.map +1 -1
  15. package/dist/core/capabilities.cjs.map +1 -1
  16. package/dist/core/capabilities.d.ts +2 -3
  17. package/dist/core/capabilities.d.ts.map +1 -1
  18. package/dist/core/capabilities.js.map +1 -1
  19. package/dist/core/client.cjs +23 -6
  20. package/dist/core/client.cjs.map +1 -1
  21. package/dist/core/client.d.ts +14 -4
  22. package/dist/core/client.d.ts.map +1 -1
  23. package/dist/core/client.js +22 -5
  24. package/dist/core/client.js.map +1 -1
  25. package/dist/core/config.cjs.map +1 -1
  26. package/dist/core/config.d.ts.map +1 -1
  27. package/dist/core/config.js.map +1 -1
  28. package/dist/core/default_client.cjs +5 -5
  29. package/dist/core/default_client.cjs.map +1 -1
  30. package/dist/core/default_client.d.ts.map +1 -1
  31. package/dist/core/default_client.js.map +1 -1
  32. package/dist/core/driver.cjs.map +1 -1
  33. package/dist/core/driver.d.ts.map +1 -1
  34. package/dist/core/driver.js.map +1 -1
  35. package/dist/core/error_resource.cjs.map +1 -1
  36. package/dist/core/error_resource.js.map +1 -1
  37. package/dist/core/errors.cjs +11 -11
  38. package/dist/core/errors.cjs.map +1 -1
  39. package/dist/core/errors.d.ts.map +1 -1
  40. package/dist/core/errors.js +11 -10
  41. package/dist/core/errors.js.map +1 -1
  42. package/dist/core/final.cjs +6 -2
  43. package/dist/core/final.cjs.map +1 -1
  44. package/dist/core/final.d.ts.map +1 -1
  45. package/dist/core/final.js +4 -1
  46. package/dist/core/final.js.map +1 -1
  47. package/dist/core/ll_client.cjs +60 -16
  48. package/dist/core/ll_client.cjs.map +1 -1
  49. package/dist/core/ll_client.d.ts +23 -7
  50. package/dist/core/ll_client.d.ts.map +1 -1
  51. package/dist/core/ll_client.js +62 -17
  52. package/dist/core/ll_client.js.map +1 -1
  53. package/dist/core/ll_transaction.cjs +3 -1
  54. package/dist/core/ll_transaction.cjs.map +1 -1
  55. package/dist/core/ll_transaction.d.ts +1 -1
  56. package/dist/core/ll_transaction.d.ts.map +1 -1
  57. package/dist/core/ll_transaction.js +2 -1
  58. package/dist/core/ll_transaction.js.map +1 -1
  59. package/dist/core/stat.cjs.map +1 -1
  60. package/dist/core/stat.js.map +1 -1
  61. package/dist/core/transaction.cjs +91 -4
  62. package/dist/core/transaction.cjs.map +1 -1
  63. package/dist/core/transaction.d.ts +52 -2
  64. package/dist/core/transaction.d.ts.map +1 -1
  65. package/dist/core/transaction.js +90 -5
  66. package/dist/core/transaction.js.map +1 -1
  67. package/dist/core/tree_filter.cjs +73 -18
  68. package/dist/core/tree_filter.cjs.map +1 -1
  69. package/dist/core/tree_filter.d.ts +1 -1
  70. package/dist/core/tree_filter.d.ts.map +1 -1
  71. package/dist/core/tree_filter.js +72 -19
  72. package/dist/core/tree_filter.js.map +1 -1
  73. package/dist/core/type_conversion.cjs +19 -20
  74. package/dist/core/type_conversion.cjs.map +1 -1
  75. package/dist/core/type_conversion.js +19 -19
  76. package/dist/core/type_conversion.js.map +1 -1
  77. package/dist/core/types.cjs +2 -3
  78. package/dist/core/types.cjs.map +1 -1
  79. package/dist/core/types.d.ts.map +1 -1
  80. package/dist/core/types.js +2 -2
  81. package/dist/core/types.js.map +1 -1
  82. package/dist/core/unauth_client.cjs +7 -6
  83. package/dist/core/unauth_client.cjs.map +1 -1
  84. package/dist/core/unauth_client.d.ts +9 -0
  85. package/dist/core/unauth_client.d.ts.map +1 -1
  86. package/dist/core/unauth_client.js +7 -5
  87. package/dist/core/unauth_client.js.map +1 -1
  88. package/dist/core/user_resources.cjs +57 -1
  89. package/dist/core/user_resources.cjs.map +1 -1
  90. package/dist/core/user_resources.d.ts +55 -1
  91. package/dist/core/user_resources.d.ts.map +1 -1
  92. package/dist/core/user_resources.js +57 -0
  93. package/dist/core/user_resources.js.map +1 -1
  94. package/dist/core/websocket_stream.cjs +17 -20
  95. package/dist/core/websocket_stream.cjs.map +1 -1
  96. package/dist/core/websocket_stream.js +16 -19
  97. package/dist/core/websocket_stream.js.map +1 -1
  98. package/dist/core/wire.d.ts.map +1 -1
  99. package/dist/helpers/pl.cjs +25 -0
  100. package/dist/helpers/pl.cjs.map +1 -1
  101. package/dist/helpers/pl.d.ts +1 -1
  102. package/dist/helpers/pl.d.ts.map +1 -1
  103. package/dist/helpers/pl.js +1 -1
  104. package/dist/helpers/pl.js.map +1 -1
  105. package/dist/helpers/poll.cjs +5 -1
  106. package/dist/helpers/poll.cjs.map +1 -1
  107. package/dist/helpers/poll.d.ts.map +1 -1
  108. package/dist/helpers/poll.js +4 -0
  109. package/dist/helpers/poll.js.map +1 -1
  110. package/dist/helpers/retry_strategy.cjs +1 -0
  111. package/dist/helpers/retry_strategy.cjs.map +1 -1
  112. package/dist/helpers/retry_strategy.js +1 -1
  113. package/dist/helpers/retry_strategy.js.map +1 -1
  114. package/dist/helpers/tx_helpers.cjs +0 -1
  115. package/dist/helpers/tx_helpers.cjs.map +1 -1
  116. package/dist/helpers/tx_helpers.d.ts.map +1 -1
  117. package/dist/helpers/tx_helpers.js.map +1 -1
  118. package/dist/index.cjs +3 -1
  119. package/dist/index.d.ts +3 -3
  120. package/dist/index.js +2 -2
  121. package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.cjs +0 -1
  122. package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.cjs.map +1 -1
  123. package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.d.ts.map +1 -1
  124. package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.js.map +1 -1
  125. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +537 -83
  126. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
  127. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs +11 -4
  128. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs.map +1 -1
  129. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts +12 -6
  130. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts.map +1 -1
  131. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js +11 -3
  132. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js.map +1 -1
  133. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +112 -7
  134. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -1
  135. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +336 -83
  136. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
  137. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs +23 -7
  138. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs.map +1 -1
  139. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts +10 -3
  140. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts.map +1 -1
  141. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js +18 -7
  142. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js.map +1 -1
  143. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs +1 -2
  144. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs.map +1 -1
  145. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.d.ts.map +1 -1
  146. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js +1 -1
  147. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js.map +1 -1
  148. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.cjs +2 -2
  149. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.cjs.map +1 -1
  150. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.d.ts +1 -1
  151. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.d.ts.map +1 -1
  152. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.js +2 -2
  153. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.js.map +1 -1
  154. package/dist/proto-grpc/google/protobuf/any.cjs +1 -2
  155. package/dist/proto-grpc/google/protobuf/any.cjs.map +1 -1
  156. package/dist/proto-grpc/google/protobuf/any.d.ts.map +1 -1
  157. package/dist/proto-grpc/google/protobuf/any.js +1 -1
  158. package/dist/proto-grpc/google/protobuf/any.js.map +1 -1
  159. package/dist/proto-grpc/google/protobuf/duration.cjs +0 -1
  160. package/dist/proto-grpc/google/protobuf/duration.cjs.map +1 -1
  161. package/dist/proto-grpc/google/protobuf/duration.d.ts.map +1 -1
  162. package/dist/proto-grpc/google/protobuf/duration.js.map +1 -1
  163. package/dist/proto-grpc/google/protobuf/timestamp.cjs +0 -1
  164. package/dist/proto-grpc/google/protobuf/timestamp.cjs.map +1 -1
  165. package/dist/proto-grpc/google/protobuf/timestamp.d.ts.map +1 -1
  166. package/dist/proto-grpc/google/protobuf/timestamp.js.map +1 -1
  167. package/dist/proto-grpc/google/rpc/code.d.ts.map +1 -1
  168. package/dist/proto-rest/index.cjs +1 -1
  169. package/dist/proto-rest/index.cjs.map +1 -1
  170. package/dist/proto-rest/index.d.ts +1 -1
  171. package/dist/proto-rest/index.d.ts.map +1 -1
  172. package/dist/proto-rest/index.js.map +1 -1
  173. package/dist/proto-rest/plapi.d.ts +30 -9
  174. package/dist/proto-rest/plapi.d.ts.map +1 -1
  175. package/dist/test/tcp-proxy.cjs +2 -2
  176. package/dist/test/tcp-proxy.cjs.map +1 -1
  177. package/dist/test/tcp-proxy.d.ts +1 -1
  178. package/dist/test/tcp-proxy.js.map +1 -1
  179. package/dist/test/test_config.cjs +8 -2
  180. package/dist/test/test_config.cjs.map +1 -1
  181. package/dist/test/test_config.d.ts +1 -1
  182. package/dist/test/test_config.d.ts.map +1 -1
  183. package/dist/test/test_config.js +1 -1
  184. package/dist/test/test_config.js.map +1 -1
  185. package/dist/util/pl.cjs.map +1 -1
  186. package/dist/util/pl.js.map +1 -1
  187. package/dist/util/util.cjs.map +1 -1
  188. package/dist/util/util.js.map +1 -1
  189. package/package.json +4 -4
  190. package/src/core/capabilities.ts +10 -3
  191. package/src/core/client.ts +30 -3
  192. package/src/core/errors.ts +2 -0
  193. package/src/core/final.ts +4 -0
  194. package/src/core/ll_client.test.ts +15 -2
  195. package/src/core/ll_client.ts +66 -11
  196. package/src/core/transaction.ts +103 -3
  197. package/src/core/unauth_client.ts +17 -2
  198. package/src/core/user_resources.ts +85 -0
  199. package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.ts +16 -3
  200. package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +335 -12
  201. package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.ts +21 -7
  202. package/src/proto-rest/plapi.ts +29 -8
  203. package/dist/proto-grpc/google/rpc/code.cjs +0 -224
  204. package/dist/proto-grpc/google/rpc/code.cjs.map +0 -1
  205. package/dist/proto-grpc/google/rpc/code.js +0 -224
  206. package/dist/proto-grpc/google/rpc/code.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PromiseTracker.cjs","names":["StatefulPromise"],"sources":["../../src/core/PromiseTracker.ts"],"sourcesContent":["import { StatefulPromise } from \"./StatefulPromise\";\n\n/**\n * Tracks pending promises to ensure they are all awaited before proceeding.\n * Useful for coordinating async operations, preventing premature completion,\n * and avoiding unhandled promise rejections.\n */\nexport class PromiseTracker {\n private promises: Set<Promise<unknown>> = new Set();\n private _draining = false;\n\n get draining(): boolean {\n return this._draining;\n }\n\n get size(): number {\n return this.promises.size;\n }\n\n track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n const _promise =\n typeof promiseOrCallback === \"function\" ? promiseOrCallback() : promiseOrCallback;\n\n const promise = StatefulPromise.fromDeferredReject(_promise, (p) => {\n this.promises.delete(p);\n });\n this.promises.add(promise);\n return promise;\n }\n\n async awaitAll() {\n const toAwait = Array.from(this.promises);\n this._draining = true;\n return await Promise.all(toAwait).finally(() => {\n this._draining = false;\n });\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,iBAAb,MAA4B;CAC1B,2BAA0C,IAAI,KAAK;CACnD,YAAoB;CAEpB,IAAI,WAAoB;AACtB,SAAO,KAAK;;CAGd,IAAI,OAAe;AACjB,SAAO,KAAK,SAAS;;CAGvB,MAAS,mBAAgE;EACvE,MAAM,WACJ,OAAO,sBAAsB,aAAa,mBAAmB,GAAG;EAElE,MAAM,UAAUA,wBAAAA,gBAAgB,mBAAmB,WAAW,MAAM;AAClE,QAAK,SAAS,OAAO,EAAE;IACvB;AACF,OAAK,SAAS,IAAI,QAAQ;AAC1B,SAAO;;CAGT,MAAM,WAAW;EACf,MAAM,UAAU,MAAM,KAAK,KAAK,SAAS;AACzC,OAAK,YAAY;AACjB,SAAO,MAAM,QAAQ,IAAI,QAAQ,CAAC,cAAc;AAC9C,QAAK,YAAY;IACjB"}
1
+ {"version":3,"file":"PromiseTracker.cjs","names":["StatefulPromise"],"sources":["../../src/core/PromiseTracker.ts"],"sourcesContent":["import { StatefulPromise } from \"./StatefulPromise\";\n\n/**\n * Tracks pending promises to ensure they are all awaited before proceeding.\n * Useful for coordinating async operations, preventing premature completion,\n * and avoiding unhandled promise rejections.\n */\nexport class PromiseTracker {\n private promises: Set<Promise<unknown>> = new Set();\n private _draining = false;\n\n get draining(): boolean {\n return this._draining;\n }\n\n get size(): number {\n return this.promises.size;\n }\n\n track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n const _promise =\n typeof promiseOrCallback === \"function\" ? promiseOrCallback() : promiseOrCallback;\n\n const promise = StatefulPromise.fromDeferredReject(_promise, (p) => {\n this.promises.delete(p);\n });\n this.promises.add(promise);\n return promise;\n }\n\n async awaitAll() {\n const toAwait = Array.from(this.promises);\n this._draining = true;\n return await Promise.all(toAwait).finally(() => {\n this._draining = false;\n });\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,iBAAb,MAA4B;CAC1B,2BAA0C,IAAI,IAAI;CAClD,YAAoB;CAEpB,IAAI,WAAoB;EACtB,OAAO,KAAK;CACd;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,SAAS;CACvB;CAEA,MAAS,mBAAgE;EACvE,MAAM,WACJ,OAAO,sBAAsB,aAAa,kBAAkB,IAAI;EAElE,MAAM,UAAUA,wBAAAA,gBAAgB,mBAAmB,WAAW,MAAM;GAClE,KAAK,SAAS,OAAO,CAAC;EACxB,CAAC;EACD,KAAK,SAAS,IAAI,OAAO;EACzB,OAAO;CACT;CAEA,MAAM,WAAW;EACf,MAAM,UAAU,MAAM,KAAK,KAAK,QAAQ;EACxC,KAAK,YAAY;EACjB,OAAO,MAAM,QAAQ,IAAI,OAAO,CAAC,CAAC,cAAc;GAC9C,KAAK,YAAY;EACnB,CAAC;CACH;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"PromiseTracker.d.ts","names":[],"sources":["../../src/core/PromiseTracker.ts"],"mappings":";;AAOA;;;;cAAa,cAAA;EAAA,QACH,QAAA;EAAA,QACA,SAAA;EAAA,IAEJ,QAAA,CAAA;EAAA,IAIA,IAAA,CAAA;EAIJ,KAAA,GAAA,CAAS,iBAAA,EAAmB,OAAA,CAAQ,CAAA,WAAY,OAAA,CAAQ,CAAA,KAAM,OAAA,CAAQ,CAAA;EAWhE,QAAA,CAAA,GAAQ,OAAA;AAAA"}
1
+ {"version":3,"file":"PromiseTracker.d.ts","names":[],"sources":["../../src/core/PromiseTracker.ts"],"mappings":";;AAOA;;;;cAAa,cAAA;EAAA,QACH,QAAA;EAAA,QACA,SAAA;EAAA,IAEJ,QAAA;EAAA,IAIA,IAAA;EAIJ,KAAA,IAAS,iBAAA,EAAmB,OAAA,CAAQ,CAAA,WAAY,OAAA,CAAQ,CAAA,KAAM,OAAA,CAAQ,CAAA;EAWhE,QAAA,IAAQ,OAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"PromiseTracker.js","names":[],"sources":["../../src/core/PromiseTracker.ts"],"sourcesContent":["import { StatefulPromise } from \"./StatefulPromise\";\n\n/**\n * Tracks pending promises to ensure they are all awaited before proceeding.\n * Useful for coordinating async operations, preventing premature completion,\n * and avoiding unhandled promise rejections.\n */\nexport class PromiseTracker {\n private promises: Set<Promise<unknown>> = new Set();\n private _draining = false;\n\n get draining(): boolean {\n return this._draining;\n }\n\n get size(): number {\n return this.promises.size;\n }\n\n track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n const _promise =\n typeof promiseOrCallback === \"function\" ? promiseOrCallback() : promiseOrCallback;\n\n const promise = StatefulPromise.fromDeferredReject(_promise, (p) => {\n this.promises.delete(p);\n });\n this.promises.add(promise);\n return promise;\n }\n\n async awaitAll() {\n const toAwait = Array.from(this.promises);\n this._draining = true;\n return await Promise.all(toAwait).finally(() => {\n this._draining = false;\n });\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,iBAAb,MAA4B;CAC1B,2BAA0C,IAAI,KAAK;CACnD,YAAoB;CAEpB,IAAI,WAAoB;AACtB,SAAO,KAAK;;CAGd,IAAI,OAAe;AACjB,SAAO,KAAK,SAAS;;CAGvB,MAAS,mBAAgE;EACvE,MAAM,WACJ,OAAO,sBAAsB,aAAa,mBAAmB,GAAG;EAElE,MAAM,UAAU,gBAAgB,mBAAmB,WAAW,MAAM;AAClE,QAAK,SAAS,OAAO,EAAE;IACvB;AACF,OAAK,SAAS,IAAI,QAAQ;AAC1B,SAAO;;CAGT,MAAM,WAAW;EACf,MAAM,UAAU,MAAM,KAAK,KAAK,SAAS;AACzC,OAAK,YAAY;AACjB,SAAO,MAAM,QAAQ,IAAI,QAAQ,CAAC,cAAc;AAC9C,QAAK,YAAY;IACjB"}
1
+ {"version":3,"file":"PromiseTracker.js","names":[],"sources":["../../src/core/PromiseTracker.ts"],"sourcesContent":["import { StatefulPromise } from \"./StatefulPromise\";\n\n/**\n * Tracks pending promises to ensure they are all awaited before proceeding.\n * Useful for coordinating async operations, preventing premature completion,\n * and avoiding unhandled promise rejections.\n */\nexport class PromiseTracker {\n private promises: Set<Promise<unknown>> = new Set();\n private _draining = false;\n\n get draining(): boolean {\n return this._draining;\n }\n\n get size(): number {\n return this.promises.size;\n }\n\n track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n const _promise =\n typeof promiseOrCallback === \"function\" ? promiseOrCallback() : promiseOrCallback;\n\n const promise = StatefulPromise.fromDeferredReject(_promise, (p) => {\n this.promises.delete(p);\n });\n this.promises.add(promise);\n return promise;\n }\n\n async awaitAll() {\n const toAwait = Array.from(this.promises);\n this._draining = true;\n return await Promise.all(toAwait).finally(() => {\n this._draining = false;\n });\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,iBAAb,MAA4B;CAC1B,2BAA0C,IAAI,IAAI;CAClD,YAAoB;CAEpB,IAAI,WAAoB;EACtB,OAAO,KAAK;CACd;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,SAAS;CACvB;CAEA,MAAS,mBAAgE;EACvE,MAAM,WACJ,OAAO,sBAAsB,aAAa,kBAAkB,IAAI;EAElE,MAAM,UAAU,gBAAgB,mBAAmB,WAAW,MAAM;GAClE,KAAK,SAAS,OAAO,CAAC;EACxB,CAAC;EACD,KAAK,SAAS,IAAI,OAAO;EACzB,OAAO;CACT;CAEA,MAAM,WAAW;EACf,MAAM,UAAU,MAAM,KAAK,KAAK,QAAQ;EACxC,KAAK,YAAY;EACjB,OAAO,MAAM,QAAQ,IAAI,OAAO,CAAC,CAAC,cAAc;GAC9C,KAAK,YAAY;EACnB,CAAC;CACH;AACF"}
@@ -4,6 +4,8 @@
4
4
  * optional deferred rejection handling to prevent unhandled promise rejections.
5
5
  */
6
6
  var StatefulPromise = class StatefulPromise {
7
+ promise;
8
+ options;
7
9
  _state;
8
10
  _id;
9
11
  static idCounter = 0n;
@@ -1 +1 @@
1
- {"version":3,"file":"StatefulPromise.cjs","names":[],"sources":["../../src/core/StatefulPromise.ts"],"sourcesContent":["type PromiseState = \"pending\" | \"fulfilled\" | \"rejected\";\n\ntype StatefulPromiseOptions<T> = {\n /**\n * If true, rejections that happen inside the promise are *recorded* but\n * not rethrown from the constructor chain. They will only surface when you\n * call unwrap()/then()/await.\n */\n deferReject?: true;\n /**\n * Callback invoked when the promise is accessed (via then/catch/finally/await).\n * Useful for cleanup or tracking when a promise result is consumed.\n */\n onUnwrap?: (promise: StatefulPromise<T>) => void;\n};\n\n/**\n * A Promise wrapper that tracks its state (pending/fulfilled/rejected) and provides\n * optional deferred rejection handling to prevent unhandled promise rejections.\n */\nexport class StatefulPromise<T> implements Promise<T> {\n private _state: PromiseState;\n private _id: bigint;\n\n private static idCounter = 0n;\n\n public static debug = false;\n\n static from<T>(promise: Promise<T>, options: StatefulPromiseOptions<T> = {}): StatefulPromise<T> {\n return new StatefulPromise(promise, options);\n }\n\n static fromDeferredReject<T>(\n promise: Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(promise, { deferReject: true, onUnwrap });\n }\n\n static fromDeferredRejectCallback<T>(\n asyncFn: () => Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(asyncFn(), { deferReject: true, onUnwrap });\n }\n\n private constructor(\n private readonly promise: Promise<T>,\n private readonly options: StatefulPromiseOptions<T> = {},\n ) {\n this._state = \"pending\";\n this._id = StatefulPromise.idCounter++;\n\n this.promise\n .then((value) => {\n this._state = \"fulfilled\";\n return value;\n })\n .catch((err) => {\n this._state = \"rejected\";\n if (!options.deferReject) {\n throw err;\n }\n });\n }\n\n readonly [Symbol.toStringTag] = \"Promise\";\n\n get id(): bigint {\n return this._id;\n }\n\n get state(): PromiseState {\n return this._state;\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: (reason: unknown) => TResult | PromiseLike<TResult>,\n ): Promise<T | TResult> {\n return this.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this.unwrap().finally(onfinally);\n }\n\n async unwrap(): Promise<T> {\n if (this.options.onUnwrap) {\n this.options.onUnwrap(this);\n }\n\n return this.promise;\n }\n}\n"],"mappings":";;;;;AAoBA,IAAa,kBAAb,MAAa,gBAAyC;CACpD;CACA;CAEA,OAAe,YAAY;CAE3B,OAAc,QAAQ;CAEtB,OAAO,KAAQ,SAAqB,UAAqC,EAAE,EAAsB;AAC/F,SAAO,IAAI,gBAAgB,SAAS,QAAQ;;CAG9C,OAAO,mBACL,SACA,UACoB;AACpB,SAAO,IAAI,gBAAgB,SAAS;GAAE,aAAa;GAAM;GAAU,CAAC;;CAGtE,OAAO,2BACL,SACA,UACoB;AACpB,SAAO,IAAI,gBAAgB,SAAS,EAAE;GAAE,aAAa;GAAM;GAAU,CAAC;;CAGxE,YACE,SACA,UAAsD,EAAE,EACxD;AAFiB,OAAA,UAAA;AACA,OAAA,UAAA;AAEjB,OAAK,SAAS;AACd,OAAK,MAAM,gBAAgB;AAE3B,OAAK,QACF,MAAM,UAAU;AACf,QAAK,SAAS;AACd,UAAO;IACP,CACD,OAAO,QAAQ;AACd,QAAK,SAAS;AACd,OAAI,CAAC,QAAQ,YACX,OAAM;IAER;;CAGN,CAAU,OAAO,eAAe;CAEhC,IAAI,KAAa;AACf,SAAO,KAAK;;CAGd,IAAI,QAAsB;AACxB,SAAO,KAAK;;CAGd,KACE,aACA,YAC8B;AAC9B,SAAO,KAAK,QAAQ,CAAC,KAAK,aAAa,WAAW;;CAGpD,MACE,YACsB;AACtB,SAAO,KAAK,QAAQ,CAAC,MAAM,WAAW;;CAGxC,QAAQ,WAAoC;AAC1C,SAAO,KAAK,QAAQ,CAAC,QAAQ,UAAU;;CAGzC,MAAM,SAAqB;AACzB,MAAI,KAAK,QAAQ,SACf,MAAK,QAAQ,SAAS,KAAK;AAG7B,SAAO,KAAK"}
1
+ {"version":3,"file":"StatefulPromise.cjs","names":[],"sources":["../../src/core/StatefulPromise.ts"],"sourcesContent":["type PromiseState = \"pending\" | \"fulfilled\" | \"rejected\";\n\ntype StatefulPromiseOptions<T> = {\n /**\n * If true, rejections that happen inside the promise are *recorded* but\n * not rethrown from the constructor chain. They will only surface when you\n * call unwrap()/then()/await.\n */\n deferReject?: true;\n /**\n * Callback invoked when the promise is accessed (via then/catch/finally/await).\n * Useful for cleanup or tracking when a promise result is consumed.\n */\n onUnwrap?: (promise: StatefulPromise<T>) => void;\n};\n\n/**\n * A Promise wrapper that tracks its state (pending/fulfilled/rejected) and provides\n * optional deferred rejection handling to prevent unhandled promise rejections.\n */\nexport class StatefulPromise<T> implements Promise<T> {\n private _state: PromiseState;\n private _id: bigint;\n\n private static idCounter = 0n;\n\n public static debug = false;\n\n static from<T>(promise: Promise<T>, options: StatefulPromiseOptions<T> = {}): StatefulPromise<T> {\n return new StatefulPromise(promise, options);\n }\n\n static fromDeferredReject<T>(\n promise: Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(promise, { deferReject: true, onUnwrap });\n }\n\n static fromDeferredRejectCallback<T>(\n asyncFn: () => Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(asyncFn(), { deferReject: true, onUnwrap });\n }\n\n private constructor(\n private readonly promise: Promise<T>,\n private readonly options: StatefulPromiseOptions<T> = {},\n ) {\n this._state = \"pending\";\n this._id = StatefulPromise.idCounter++;\n\n this.promise\n .then((value) => {\n this._state = \"fulfilled\";\n return value;\n })\n .catch((err) => {\n this._state = \"rejected\";\n if (!options.deferReject) {\n throw err;\n }\n });\n }\n\n readonly [Symbol.toStringTag] = \"Promise\";\n\n get id(): bigint {\n return this._id;\n }\n\n get state(): PromiseState {\n return this._state;\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: (reason: unknown) => TResult | PromiseLike<TResult>,\n ): Promise<T | TResult> {\n return this.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this.unwrap().finally(onfinally);\n }\n\n async unwrap(): Promise<T> {\n if (this.options.onUnwrap) {\n this.options.onUnwrap(this);\n }\n\n return this.promise;\n }\n}\n"],"mappings":";;;;;AAoBA,IAAa,kBAAb,MAAa,gBAAyC;CA2BjC;CACA;CA3BnB;CACA;CAEA,OAAe,YAAY;CAE3B,OAAc,QAAQ;CAEtB,OAAO,KAAQ,SAAqB,UAAqC,CAAC,GAAuB;EAC/F,OAAO,IAAI,gBAAgB,SAAS,OAAO;CAC7C;CAEA,OAAO,mBACL,SACA,UACoB;EACpB,OAAO,IAAI,gBAAgB,SAAS;GAAE,aAAa;GAAM;EAAS,CAAC;CACrE;CAEA,OAAO,2BACL,SACA,UACoB;EACpB,OAAO,IAAI,gBAAgB,QAAQ,GAAG;GAAE,aAAa;GAAM;EAAS,CAAC;CACvE;CAEA,YACE,SACA,UAAsD,CAAC,GACvD;EAFiB,KAAA,UAAA;EACA,KAAA,UAAA;EAEjB,KAAK,SAAS;EACd,KAAK,MAAM,gBAAgB;EAE3B,KAAK,QACF,MAAM,UAAU;GACf,KAAK,SAAS;GACd,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,KAAK,SAAS;GACd,IAAI,CAAC,QAAQ,aACX,MAAM;EAEV,CAAC;CACL;CAEA,CAAU,OAAO,eAAe;CAEhC,IAAI,KAAa;EACf,OAAO,KAAK;CACd;CAEA,IAAI,QAAsB;EACxB,OAAO,KAAK;CACd;CAEA,KACE,aACA,YAC8B;EAC9B,OAAO,KAAK,OAAO,CAAC,CAAC,KAAK,aAAa,UAAU;CACnD;CAEA,MACE,YACsB;EACtB,OAAO,KAAK,OAAO,CAAC,CAAC,MAAM,UAAU;CACvC;CAEA,QAAQ,WAAoC;EAC1C,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ,SAAS;CACxC;CAEA,MAAM,SAAqB;EACzB,IAAI,KAAK,QAAQ,UACf,KAAK,QAAQ,SAAS,IAAI;EAG5B,OAAO,KAAK;CACd;AACF"}
@@ -4,6 +4,8 @@
4
4
  * optional deferred rejection handling to prevent unhandled promise rejections.
5
5
  */
6
6
  var StatefulPromise = class StatefulPromise {
7
+ promise;
8
+ options;
7
9
  _state;
8
10
  _id;
9
11
  static idCounter = 0n;
@@ -1 +1 @@
1
- {"version":3,"file":"StatefulPromise.js","names":[],"sources":["../../src/core/StatefulPromise.ts"],"sourcesContent":["type PromiseState = \"pending\" | \"fulfilled\" | \"rejected\";\n\ntype StatefulPromiseOptions<T> = {\n /**\n * If true, rejections that happen inside the promise are *recorded* but\n * not rethrown from the constructor chain. They will only surface when you\n * call unwrap()/then()/await.\n */\n deferReject?: true;\n /**\n * Callback invoked when the promise is accessed (via then/catch/finally/await).\n * Useful for cleanup or tracking when a promise result is consumed.\n */\n onUnwrap?: (promise: StatefulPromise<T>) => void;\n};\n\n/**\n * A Promise wrapper that tracks its state (pending/fulfilled/rejected) and provides\n * optional deferred rejection handling to prevent unhandled promise rejections.\n */\nexport class StatefulPromise<T> implements Promise<T> {\n private _state: PromiseState;\n private _id: bigint;\n\n private static idCounter = 0n;\n\n public static debug = false;\n\n static from<T>(promise: Promise<T>, options: StatefulPromiseOptions<T> = {}): StatefulPromise<T> {\n return new StatefulPromise(promise, options);\n }\n\n static fromDeferredReject<T>(\n promise: Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(promise, { deferReject: true, onUnwrap });\n }\n\n static fromDeferredRejectCallback<T>(\n asyncFn: () => Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(asyncFn(), { deferReject: true, onUnwrap });\n }\n\n private constructor(\n private readonly promise: Promise<T>,\n private readonly options: StatefulPromiseOptions<T> = {},\n ) {\n this._state = \"pending\";\n this._id = StatefulPromise.idCounter++;\n\n this.promise\n .then((value) => {\n this._state = \"fulfilled\";\n return value;\n })\n .catch((err) => {\n this._state = \"rejected\";\n if (!options.deferReject) {\n throw err;\n }\n });\n }\n\n readonly [Symbol.toStringTag] = \"Promise\";\n\n get id(): bigint {\n return this._id;\n }\n\n get state(): PromiseState {\n return this._state;\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: (reason: unknown) => TResult | PromiseLike<TResult>,\n ): Promise<T | TResult> {\n return this.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this.unwrap().finally(onfinally);\n }\n\n async unwrap(): Promise<T> {\n if (this.options.onUnwrap) {\n this.options.onUnwrap(this);\n }\n\n return this.promise;\n }\n}\n"],"mappings":";;;;;AAoBA,IAAa,kBAAb,MAAa,gBAAyC;CACpD;CACA;CAEA,OAAe,YAAY;CAE3B,OAAc,QAAQ;CAEtB,OAAO,KAAQ,SAAqB,UAAqC,EAAE,EAAsB;AAC/F,SAAO,IAAI,gBAAgB,SAAS,QAAQ;;CAG9C,OAAO,mBACL,SACA,UACoB;AACpB,SAAO,IAAI,gBAAgB,SAAS;GAAE,aAAa;GAAM;GAAU,CAAC;;CAGtE,OAAO,2BACL,SACA,UACoB;AACpB,SAAO,IAAI,gBAAgB,SAAS,EAAE;GAAE,aAAa;GAAM;GAAU,CAAC;;CAGxE,YACE,SACA,UAAsD,EAAE,EACxD;AAFiB,OAAA,UAAA;AACA,OAAA,UAAA;AAEjB,OAAK,SAAS;AACd,OAAK,MAAM,gBAAgB;AAE3B,OAAK,QACF,MAAM,UAAU;AACf,QAAK,SAAS;AACd,UAAO;IACP,CACD,OAAO,QAAQ;AACd,QAAK,SAAS;AACd,OAAI,CAAC,QAAQ,YACX,OAAM;IAER;;CAGN,CAAU,OAAO,eAAe;CAEhC,IAAI,KAAa;AACf,SAAO,KAAK;;CAGd,IAAI,QAAsB;AACxB,SAAO,KAAK;;CAGd,KACE,aACA,YAC8B;AAC9B,SAAO,KAAK,QAAQ,CAAC,KAAK,aAAa,WAAW;;CAGpD,MACE,YACsB;AACtB,SAAO,KAAK,QAAQ,CAAC,MAAM,WAAW;;CAGxC,QAAQ,WAAoC;AAC1C,SAAO,KAAK,QAAQ,CAAC,QAAQ,UAAU;;CAGzC,MAAM,SAAqB;AACzB,MAAI,KAAK,QAAQ,SACf,MAAK,QAAQ,SAAS,KAAK;AAG7B,SAAO,KAAK"}
1
+ {"version":3,"file":"StatefulPromise.js","names":[],"sources":["../../src/core/StatefulPromise.ts"],"sourcesContent":["type PromiseState = \"pending\" | \"fulfilled\" | \"rejected\";\n\ntype StatefulPromiseOptions<T> = {\n /**\n * If true, rejections that happen inside the promise are *recorded* but\n * not rethrown from the constructor chain. They will only surface when you\n * call unwrap()/then()/await.\n */\n deferReject?: true;\n /**\n * Callback invoked when the promise is accessed (via then/catch/finally/await).\n * Useful for cleanup or tracking when a promise result is consumed.\n */\n onUnwrap?: (promise: StatefulPromise<T>) => void;\n};\n\n/**\n * A Promise wrapper that tracks its state (pending/fulfilled/rejected) and provides\n * optional deferred rejection handling to prevent unhandled promise rejections.\n */\nexport class StatefulPromise<T> implements Promise<T> {\n private _state: PromiseState;\n private _id: bigint;\n\n private static idCounter = 0n;\n\n public static debug = false;\n\n static from<T>(promise: Promise<T>, options: StatefulPromiseOptions<T> = {}): StatefulPromise<T> {\n return new StatefulPromise(promise, options);\n }\n\n static fromDeferredReject<T>(\n promise: Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(promise, { deferReject: true, onUnwrap });\n }\n\n static fromDeferredRejectCallback<T>(\n asyncFn: () => Promise<T>,\n onUnwrap?: (promise: StatefulPromise<T>) => void,\n ): StatefulPromise<T> {\n return new StatefulPromise(asyncFn(), { deferReject: true, onUnwrap });\n }\n\n private constructor(\n private readonly promise: Promise<T>,\n private readonly options: StatefulPromiseOptions<T> = {},\n ) {\n this._state = \"pending\";\n this._id = StatefulPromise.idCounter++;\n\n this.promise\n .then((value) => {\n this._state = \"fulfilled\";\n return value;\n })\n .catch((err) => {\n this._state = \"rejected\";\n if (!options.deferReject) {\n throw err;\n }\n });\n }\n\n readonly [Symbol.toStringTag] = \"Promise\";\n\n get id(): bigint {\n return this._id;\n }\n\n get state(): PromiseState {\n return this._state;\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: (reason: unknown) => TResult | PromiseLike<TResult>,\n ): Promise<T | TResult> {\n return this.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this.unwrap().finally(onfinally);\n }\n\n async unwrap(): Promise<T> {\n if (this.options.onUnwrap) {\n this.options.onUnwrap(this);\n }\n\n return this.promise;\n }\n}\n"],"mappings":";;;;;AAoBA,IAAa,kBAAb,MAAa,gBAAyC;CA2BjC;CACA;CA3BnB;CACA;CAEA,OAAe,YAAY;CAE3B,OAAc,QAAQ;CAEtB,OAAO,KAAQ,SAAqB,UAAqC,CAAC,GAAuB;EAC/F,OAAO,IAAI,gBAAgB,SAAS,OAAO;CAC7C;CAEA,OAAO,mBACL,SACA,UACoB;EACpB,OAAO,IAAI,gBAAgB,SAAS;GAAE,aAAa;GAAM;EAAS,CAAC;CACrE;CAEA,OAAO,2BACL,SACA,UACoB;EACpB,OAAO,IAAI,gBAAgB,QAAQ,GAAG;GAAE,aAAa;GAAM;EAAS,CAAC;CACvE;CAEA,YACE,SACA,UAAsD,CAAC,GACvD;EAFiB,KAAA,UAAA;EACA,KAAA,UAAA;EAEjB,KAAK,SAAS;EACd,KAAK,MAAM,gBAAgB;EAE3B,KAAK,QACF,MAAM,UAAU;GACf,KAAK,SAAS;GACd,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,KAAK,SAAS;GACd,IAAI,CAAC,QAAQ,aACX,MAAM;EAEV,CAAC;CACL;CAEA,CAAU,OAAO,eAAe;CAEhC,IAAI,KAAa;EACf,OAAO,KAAK;CACd;CAEA,IAAI,QAAsB;EACxB,OAAO,KAAK;CACd;CAEA,KACE,aACA,YAC8B;EAC9B,OAAO,KAAK,OAAO,CAAC,CAAC,KAAK,aAAa,UAAU;CACnD;CAEA,MACE,YACsB;EACtB,OAAO,KAAK,OAAO,CAAC,CAAC,MAAM,UAAU;CACvC;CAEA,QAAQ,WAAoC;EAC1C,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ,SAAS;CACxC;CAEA,MAAM,SAAqB;EACzB,IAAI,KAAK,QAAQ,UACf,KAAK,QAAQ,SAAS,IAAI;EAG5B,OAAO,KAAK;CACd;AACF"}
@@ -17,5 +17,5 @@ interface BiDiStream<I extends object, O extends object> {
17
17
  responses: AsyncIterable<O>;
18
18
  }
19
19
  //#endregion
20
- export { BiDiStream };
20
+ export { BiDiStream, RequestsStream };
21
21
  //# sourceMappingURL=abstract_stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"advisory_locks.cjs","names":[],"sources":["../../src/core/advisory_locks.ts"],"sourcesContent":["class AwaitLock {\n private acquired = false;\n private resolvers: (() => void)[] = [];\n\n acquireAsync(): Promise<void> {\n if (!this.acquired) {\n this.acquired = true;\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n this.resolvers.push(resolve);\n });\n }\n\n /**\n * Releases the lock. Returns true if the lock becomes fully idle (no waiters, not acquired).\n */\n release(): boolean {\n if (!this.acquired) {\n throw new Error(\"Cannot release an unacquired lock\");\n }\n\n if (this.resolvers.length) {\n this.resolvers.shift()?.();\n return false;\n } else {\n this.acquired = false;\n return true;\n }\n }\n}\n\nconst m = new Map<string, AwaitLock>();\n\n/**\n * Acquire a process-local async lock for the given id and return a release function.\n * Ensures only one concurrent operation per id within this process.\n */\nexport async function advisoryLock(id: string) {\n if (!m.has(id)) {\n m.set(id, new AwaitLock());\n }\n\n const lock = m.get(id)!;\n await lock.acquireAsync();\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const nowIdle = lock.release();\n if (nowIdle) m.delete(id);\n };\n}\n\n/**\n * Run the callback under the lock for the given id; releases automatically.\n */\nexport async function advisoryLockCallback<T>(id: string, cb: () => Promise<T>): Promise<T> {\n const release = await advisoryLock(id);\n try {\n return await cb();\n } finally {\n release();\n }\n}\n"],"mappings":";AAAA,IAAM,YAAN,MAAgB;CACd,WAAmB;CACnB,YAAoC,EAAE;CAEtC,eAA8B;AAC5B,MAAI,CAAC,KAAK,UAAU;AAClB,QAAK,WAAW;AAChB,UAAO,QAAQ,SAAS;;AAG1B,SAAO,IAAI,SAAS,YAAY;AAC9B,QAAK,UAAU,KAAK,QAAQ;IAC5B;;;;;CAMJ,UAAmB;AACjB,MAAI,CAAC,KAAK,SACR,OAAM,IAAI,MAAM,oCAAoC;AAGtD,MAAI,KAAK,UAAU,QAAQ;AACzB,QAAK,UAAU,OAAO,IAAI;AAC1B,UAAO;SACF;AACL,QAAK,WAAW;AAChB,UAAO;;;;AAKb,MAAM,oBAAI,IAAI,KAAwB;;;;;AAMtC,eAAsB,aAAa,IAAY;AAC7C,KAAI,CAAC,EAAE,IAAI,GAAG,CACZ,GAAE,IAAI,IAAI,IAAI,WAAW,CAAC;CAG5B,MAAM,OAAO,EAAE,IAAI,GAAG;AACtB,OAAM,KAAK,cAAc;CAEzB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AAEX,MADgB,KAAK,SAAS,CACjB,GAAE,OAAO,GAAG"}
1
+ {"version":3,"file":"advisory_locks.cjs","names":[],"sources":["../../src/core/advisory_locks.ts"],"sourcesContent":["class AwaitLock {\n private acquired = false;\n private resolvers: (() => void)[] = [];\n\n acquireAsync(): Promise<void> {\n if (!this.acquired) {\n this.acquired = true;\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n this.resolvers.push(resolve);\n });\n }\n\n /**\n * Releases the lock. Returns true if the lock becomes fully idle (no waiters, not acquired).\n */\n release(): boolean {\n if (!this.acquired) {\n throw new Error(\"Cannot release an unacquired lock\");\n }\n\n if (this.resolvers.length) {\n this.resolvers.shift()?.();\n return false;\n } else {\n this.acquired = false;\n return true;\n }\n }\n}\n\nconst m = new Map<string, AwaitLock>();\n\n/**\n * Acquire a process-local async lock for the given id and return a release function.\n * Ensures only one concurrent operation per id within this process.\n */\nexport async function advisoryLock(id: string) {\n if (!m.has(id)) {\n m.set(id, new AwaitLock());\n }\n\n const lock = m.get(id)!;\n await lock.acquireAsync();\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const nowIdle = lock.release();\n if (nowIdle) m.delete(id);\n };\n}\n\n/**\n * Run the callback under the lock for the given id; releases automatically.\n */\nexport async function advisoryLockCallback<T>(id: string, cb: () => Promise<T>): Promise<T> {\n const release = await advisoryLock(id);\n try {\n return await cb();\n } finally {\n release();\n }\n}\n"],"mappings":";AAAA,IAAM,YAAN,MAAgB;CACd,WAAmB;CACnB,YAAoC,CAAC;CAErC,eAA8B;EAC5B,IAAI,CAAC,KAAK,UAAU;GAClB,KAAK,WAAW;GAChB,OAAO,QAAQ,QAAQ;EACzB;EAEA,OAAO,IAAI,SAAS,YAAY;GAC9B,KAAK,UAAU,KAAK,OAAO;EAC7B,CAAC;CACH;;;;CAKA,UAAmB;EACjB,IAAI,CAAC,KAAK,UACR,MAAM,IAAI,MAAM,mCAAmC;EAGrD,IAAI,KAAK,UAAU,QAAQ;GACzB,KAAK,UAAU,MAAM,CAAC,GAAG;GACzB,OAAO;EACT,OAAO;GACL,KAAK,WAAW;GAChB,OAAO;EACT;CACF;AACF;AAEA,MAAM,oBAAI,IAAI,IAAuB;;;;;AAMrC,eAAsB,aAAa,IAAY;CAC7C,IAAI,CAAC,EAAE,IAAI,EAAE,GACX,EAAE,IAAI,IAAI,IAAI,UAAU,CAAC;CAG3B,MAAM,OAAO,EAAE,IAAI,EAAE;CACrB,MAAM,KAAK,aAAa;CAExB,IAAI,WAAW;CACf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EAEX,IADgB,KAAK,QACX,GAAG,EAAE,OAAO,EAAE;CAC1B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"advisory_locks.js","names":[],"sources":["../../src/core/advisory_locks.ts"],"sourcesContent":["class AwaitLock {\n private acquired = false;\n private resolvers: (() => void)[] = [];\n\n acquireAsync(): Promise<void> {\n if (!this.acquired) {\n this.acquired = true;\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n this.resolvers.push(resolve);\n });\n }\n\n /**\n * Releases the lock. Returns true if the lock becomes fully idle (no waiters, not acquired).\n */\n release(): boolean {\n if (!this.acquired) {\n throw new Error(\"Cannot release an unacquired lock\");\n }\n\n if (this.resolvers.length) {\n this.resolvers.shift()?.();\n return false;\n } else {\n this.acquired = false;\n return true;\n }\n }\n}\n\nconst m = new Map<string, AwaitLock>();\n\n/**\n * Acquire a process-local async lock for the given id and return a release function.\n * Ensures only one concurrent operation per id within this process.\n */\nexport async function advisoryLock(id: string) {\n if (!m.has(id)) {\n m.set(id, new AwaitLock());\n }\n\n const lock = m.get(id)!;\n await lock.acquireAsync();\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const nowIdle = lock.release();\n if (nowIdle) m.delete(id);\n };\n}\n\n/**\n * Run the callback under the lock for the given id; releases automatically.\n */\nexport async function advisoryLockCallback<T>(id: string, cb: () => Promise<T>): Promise<T> {\n const release = await advisoryLock(id);\n try {\n return await cb();\n } finally {\n release();\n }\n}\n"],"mappings":";AAAA,IAAM,YAAN,MAAgB;CACd,WAAmB;CACnB,YAAoC,EAAE;CAEtC,eAA8B;AAC5B,MAAI,CAAC,KAAK,UAAU;AAClB,QAAK,WAAW;AAChB,UAAO,QAAQ,SAAS;;AAG1B,SAAO,IAAI,SAAS,YAAY;AAC9B,QAAK,UAAU,KAAK,QAAQ;IAC5B;;;;;CAMJ,UAAmB;AACjB,MAAI,CAAC,KAAK,SACR,OAAM,IAAI,MAAM,oCAAoC;AAGtD,MAAI,KAAK,UAAU,QAAQ;AACzB,QAAK,UAAU,OAAO,IAAI;AAC1B,UAAO;SACF;AACL,QAAK,WAAW;AAChB,UAAO;;;;AAKb,MAAM,oBAAI,IAAI,KAAwB;;;;;AAMtC,eAAsB,aAAa,IAAY;AAC7C,KAAI,CAAC,EAAE,IAAI,GAAG,CACZ,GAAE,IAAI,IAAI,IAAI,WAAW,CAAC;CAG5B,MAAM,OAAO,EAAE,IAAI,GAAG;AACtB,OAAM,KAAK,cAAc;CAEzB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AAEX,MADgB,KAAK,SAAS,CACjB,GAAE,OAAO,GAAG"}
1
+ {"version":3,"file":"advisory_locks.js","names":[],"sources":["../../src/core/advisory_locks.ts"],"sourcesContent":["class AwaitLock {\n private acquired = false;\n private resolvers: (() => void)[] = [];\n\n acquireAsync(): Promise<void> {\n if (!this.acquired) {\n this.acquired = true;\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n this.resolvers.push(resolve);\n });\n }\n\n /**\n * Releases the lock. Returns true if the lock becomes fully idle (no waiters, not acquired).\n */\n release(): boolean {\n if (!this.acquired) {\n throw new Error(\"Cannot release an unacquired lock\");\n }\n\n if (this.resolvers.length) {\n this.resolvers.shift()?.();\n return false;\n } else {\n this.acquired = false;\n return true;\n }\n }\n}\n\nconst m = new Map<string, AwaitLock>();\n\n/**\n * Acquire a process-local async lock for the given id and return a release function.\n * Ensures only one concurrent operation per id within this process.\n */\nexport async function advisoryLock(id: string) {\n if (!m.has(id)) {\n m.set(id, new AwaitLock());\n }\n\n const lock = m.get(id)!;\n await lock.acquireAsync();\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const nowIdle = lock.release();\n if (nowIdle) m.delete(id);\n };\n}\n\n/**\n * Run the callback under the lock for the given id; releases automatically.\n */\nexport async function advisoryLockCallback<T>(id: string, cb: () => Promise<T>): Promise<T> {\n const release = await advisoryLock(id);\n try {\n return await cb();\n } finally {\n release();\n }\n}\n"],"mappings":";AAAA,IAAM,YAAN,MAAgB;CACd,WAAmB;CACnB,YAAoC,CAAC;CAErC,eAA8B;EAC5B,IAAI,CAAC,KAAK,UAAU;GAClB,KAAK,WAAW;GAChB,OAAO,QAAQ,QAAQ;EACzB;EAEA,OAAO,IAAI,SAAS,YAAY;GAC9B,KAAK,UAAU,KAAK,OAAO;EAC7B,CAAC;CACH;;;;CAKA,UAAmB;EACjB,IAAI,CAAC,KAAK,UACR,MAAM,IAAI,MAAM,mCAAmC;EAGrD,IAAI,KAAK,UAAU,QAAQ;GACzB,KAAK,UAAU,MAAM,CAAC,GAAG;GACzB,OAAO;EACT,OAAO;GACL,KAAK,WAAW;GAChB,OAAO;EACT;CACF;AACF;AAEA,MAAM,oBAAI,IAAI,IAAuB;;;;;AAMrC,eAAsB,aAAa,IAAY;CAC7C,IAAI,CAAC,EAAE,IAAI,EAAE,GACX,EAAE,IAAI,IAAI,IAAI,UAAU,CAAC;CAG3B,MAAM,OAAO,EAAE,IAAI,EAAE;CACrB,MAAM,KAAK,aAAa;CAExB,IAAI,WAAW;CACf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EAEX,IADgB,KAAK,QACX,GAAG,EAAE,OAAO,EAAE;CAC1B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.cjs","names":["parsePlJwt"],"sources":["../../src/core/auth.ts"],"sourcesContent":["import type { AuthInformation } from \"./config\";\nimport { parsePlJwt } from \"../util/pl\";\n\n/** Returns a timestamp when current authorization information should be refreshed.\n * Compare the value with Date.now(). */\nexport function inferAuthRefreshTime(\n info: AuthInformation,\n maxRefreshSeconds: number,\n): number | undefined {\n if (info.jwtToken === undefined) return undefined;\n\n const { exp, iat } = parsePlJwt(info.jwtToken);\n\n return (\n Math.min(\n // in the middle between issue and expiration time points\n (iat + exp) / 2,\n iat + maxRefreshSeconds,\n ) * 1000\n );\n}\n\nexport function expirationFromAuthInformation(authInfo: AuthInformation): number | undefined {\n if (authInfo.jwtToken === undefined) return undefined;\n const parsed = parsePlJwt(authInfo.jwtToken);\n return parsed.exp * 1000;\n}\n"],"mappings":";;;;AAKA,SAAgB,qBACd,MACA,mBACoB;AACpB,KAAI,KAAK,aAAa,KAAA,EAAW,QAAO,KAAA;CAExC,MAAM,EAAE,KAAK,QAAQA,WAAAA,WAAW,KAAK,SAAS;AAE9C,QACE,KAAK,KAEF,MAAM,OAAO,GACd,MAAM,kBACP,GAAG;;AAIR,SAAgB,8BAA8B,UAA+C;AAC3F,KAAI,SAAS,aAAa,KAAA,EAAW,QAAO,KAAA;AAE5C,QADeA,WAAAA,WAAW,SAAS,SAAS,CAC9B,MAAM"}
1
+ {"version":3,"file":"auth.cjs","names":["parsePlJwt"],"sources":["../../src/core/auth.ts"],"sourcesContent":["import type { AuthInformation } from \"./config\";\nimport { parsePlJwt } from \"../util/pl\";\n\n/** Returns a timestamp when current authorization information should be refreshed.\n * Compare the value with Date.now(). */\nexport function inferAuthRefreshTime(\n info: AuthInformation,\n maxRefreshSeconds: number,\n): number | undefined {\n if (info.jwtToken === undefined) return undefined;\n\n const { exp, iat } = parsePlJwt(info.jwtToken);\n\n return (\n Math.min(\n // in the middle between issue and expiration time points\n (iat + exp) / 2,\n iat + maxRefreshSeconds,\n ) * 1000\n );\n}\n\nexport function expirationFromAuthInformation(authInfo: AuthInformation): number | undefined {\n if (authInfo.jwtToken === undefined) return undefined;\n const parsed = parsePlJwt(authInfo.jwtToken);\n return parsed.exp * 1000;\n}\n"],"mappings":";;;;AAKA,SAAgB,qBACd,MACA,mBACoB;CACpB,IAAI,KAAK,aAAa,KAAA,GAAW,OAAO,KAAA;CAExC,MAAM,EAAE,KAAK,QAAQA,WAAAA,WAAW,KAAK,QAAQ;CAE7C,OACE,KAAK,KAEF,MAAM,OAAO,GACd,MAAM,iBACR,IAAI;AAER;AAEA,SAAgB,8BAA8B,UAA+C;CAC3F,IAAI,SAAS,aAAa,KAAA,GAAW,OAAO,KAAA;CAE5C,OADeA,WAAAA,WAAW,SAAS,QACvB,CAAC,CAAC,MAAM;AACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/core/auth.ts"],"mappings":";;;;;iBAKgB,oBAAA,CACd,IAAA,EAAM,eAAA,EACN,iBAAA;AAAA,iBAec,6BAAA,CAA8B,QAAA,EAAU,eAAA"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/core/auth.ts"],"mappings":";;;;;iBAKgB,oBAAA,CACd,IAAA,EAAM,eAAe,EACrB,iBAAA;AAAA,iBAec,6BAAA,CAA8B,QAAyB,EAAf,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","names":[],"sources":["../../src/core/auth.ts"],"sourcesContent":["import type { AuthInformation } from \"./config\";\nimport { parsePlJwt } from \"../util/pl\";\n\n/** Returns a timestamp when current authorization information should be refreshed.\n * Compare the value with Date.now(). */\nexport function inferAuthRefreshTime(\n info: AuthInformation,\n maxRefreshSeconds: number,\n): number | undefined {\n if (info.jwtToken === undefined) return undefined;\n\n const { exp, iat } = parsePlJwt(info.jwtToken);\n\n return (\n Math.min(\n // in the middle between issue and expiration time points\n (iat + exp) / 2,\n iat + maxRefreshSeconds,\n ) * 1000\n );\n}\n\nexport function expirationFromAuthInformation(authInfo: AuthInformation): number | undefined {\n if (authInfo.jwtToken === undefined) return undefined;\n const parsed = parsePlJwt(authInfo.jwtToken);\n return parsed.exp * 1000;\n}\n"],"mappings":";;;;AAKA,SAAgB,qBACd,MACA,mBACoB;AACpB,KAAI,KAAK,aAAa,KAAA,EAAW,QAAO,KAAA;CAExC,MAAM,EAAE,KAAK,QAAQ,WAAW,KAAK,SAAS;AAE9C,QACE,KAAK,KAEF,MAAM,OAAO,GACd,MAAM,kBACP,GAAG;;AAIR,SAAgB,8BAA8B,UAA+C;AAC3F,KAAI,SAAS,aAAa,KAAA,EAAW,QAAO,KAAA;AAE5C,QADe,WAAW,SAAS,SAAS,CAC9B,MAAM"}
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../src/core/auth.ts"],"sourcesContent":["import type { AuthInformation } from \"./config\";\nimport { parsePlJwt } from \"../util/pl\";\n\n/** Returns a timestamp when current authorization information should be refreshed.\n * Compare the value with Date.now(). */\nexport function inferAuthRefreshTime(\n info: AuthInformation,\n maxRefreshSeconds: number,\n): number | undefined {\n if (info.jwtToken === undefined) return undefined;\n\n const { exp, iat } = parsePlJwt(info.jwtToken);\n\n return (\n Math.min(\n // in the middle between issue and expiration time points\n (iat + exp) / 2,\n iat + maxRefreshSeconds,\n ) * 1000\n );\n}\n\nexport function expirationFromAuthInformation(authInfo: AuthInformation): number | undefined {\n if (authInfo.jwtToken === undefined) return undefined;\n const parsed = parsePlJwt(authInfo.jwtToken);\n return parsed.exp * 1000;\n}\n"],"mappings":";;;;AAKA,SAAgB,qBACd,MACA,mBACoB;CACpB,IAAI,KAAK,aAAa,KAAA,GAAW,OAAO,KAAA;CAExC,MAAM,EAAE,KAAK,QAAQ,WAAW,KAAK,QAAQ;CAE7C,OACE,KAAK,KAEF,MAAM,OAAO,GACd,MAAM,iBACR,IAAI;AAER;AAEA,SAAgB,8BAA8B,UAA+C;CAC3F,IAAI,SAAS,aAAa,KAAA,GAAW,OAAO,KAAA;CAE5C,OADe,WAAW,SAAS,QACvB,CAAC,CAAC,MAAM;AACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","names":[],"sources":["../../src/core/cache.ts"],"mappings":";;;KAEY,uBAAA;;AAAZ;EAGE,oBAAA;EACA,IAAA,EAAM,YAAA;EAAA,SACG,SAAA,EAAW,iBAAA;AAAA"}
1
+ {"version":3,"file":"cache.d.ts","names":[],"sources":["../../src/core/cache.ts"],"mappings":";;;KAEY,uBAAA;;AAAZ;EAGE,oBAAA;EACA,IAAA,EAAM,YAAA;EAAA,SACG,SAAA,EAAW,iBAAiB;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.cjs","names":[],"sources":["../../src/core/capabilities.ts"],"sourcesContent":["/**\n * Backend capability tokens advertised by pl in\n * `MaintenanceAPI.Ping.Response.capabilities`.\n * Capabilities affect behaviour of inner ML mechanisms and allow\n * to detect incompatibilities between blocks and backend via\n * via `TemplateDataV3.requiredCapabilities`.\n *\n * Mirror of `pl/platform/api/plapiserver/server_capabilities.go` — keep\n * tokens in sync with the backend's advertised list. Format is\n * `<feature>:<version>`; bump the version when wire semantics change.\n *\n * Shared across:\n * - `@milaboratories/pl-client` — client-side capability checks\n * - `@platforma-sdk/tengo-builder` — populates `requiredCapabilities` at compile time\n * - `@platforma-sdk/block-tools` — copies it onto the published manifest\n * - `@milaboratories/pl-middle-layer` — checks it at install time\n */\nexport type BackendCapability = \"auth:v2\" | \"treeFilter:v2\" | \"wasm:v1\";\n\n/** True iff `capabilities` advertises the requested token. */\nexport function hasCapability(\n capabilities: readonly string[] | undefined,\n capability: BackendCapability,\n): boolean {\n return capabilities?.includes(capability) ?? false;\n}\n"],"mappings":";;AAoBA,SAAgB,cACd,cACA,YACS;AACT,QAAO,cAAc,SAAS,WAAW,IAAI"}
1
+ {"version":3,"file":"capabilities.cjs","names":[],"sources":["../../src/core/capabilities.ts"],"sourcesContent":["/**\n * Backend capability tokens advertised by pl in\n * `MaintenanceAPI.Ping.Response.capabilities`.\n * Capabilities affect behaviour of inner ML mechanisms and allow\n * to detect incompatibilities between blocks and backend via\n * via `TemplateDataV3.requiredCapabilities`.\n *\n * Keep tokens in sync with the backend's advertised list. Format is\n * `<feature>:<version>`; bump the version when wire semantics change.\n *\n * Shared across:\n * - `@milaboratories/pl-client` — client-side capability checks\n * - `@platforma-sdk/tengo-builder` — populates `requiredCapabilities` at compile time\n * - `@platforma-sdk/block-tools` — copies it onto the published manifest\n * - `@milaboratories/pl-middle-layer` — checks it at install time\n */\nexport type BackendCapability =\n | \"auth:v2\"\n | \"treeFilter:v2\"\n | \"wasm:v1\"\n // Project-sharing capability tokens.\n | \"crossTreeRefs:v1\" // cross-color field attach (accept a foreign-colored shared envelope)\n | \"userListing:v1\" // list users for the recipient picker\n | \"publicGrants:v1\" // public (everyone) grants allowed for any role\n | \"txListGrants:v1\"; // list grants inside a transaction (batched recipient reads)\n\n/** True iff `capabilities` advertises the requested token. */\nexport function hasCapability(\n capabilities: readonly string[] | undefined,\n capability: BackendCapability,\n): boolean {\n return capabilities?.includes(capability) ?? false;\n}\n"],"mappings":";;AA2BA,SAAgB,cACd,cACA,YACS;CACT,OAAO,cAAc,SAAS,UAAU,KAAK;AAC/C"}
@@ -6,8 +6,7 @@
6
6
  * to detect incompatibilities between blocks and backend via
7
7
  * via `TemplateDataV3.requiredCapabilities`.
8
8
  *
9
- * Mirror of `pl/platform/api/plapiserver/server_capabilities.go` — keep
10
- * tokens in sync with the backend's advertised list. Format is
9
+ * Keep tokens in sync with the backend's advertised list. Format is
11
10
  * `<feature>:<version>`; bump the version when wire semantics change.
12
11
  *
13
12
  * Shared across:
@@ -16,7 +15,7 @@
16
15
  * - `@platforma-sdk/block-tools` — copies it onto the published manifest
17
16
  * - `@milaboratories/pl-middle-layer` — checks it at install time
18
17
  */
19
- type BackendCapability = "auth:v2" | "treeFilter:v2" | "wasm:v1";
18
+ type BackendCapability = "auth:v2" | "treeFilter:v2" | "wasm:v1" | "crossTreeRefs:v1" | "userListing:v1" | "publicGrants:v1" | "txListGrants:v1";
20
19
  /** True iff `capabilities` advertises the requested token. */
21
20
  declare function hasCapability(capabilities: readonly string[] | undefined, capability: BackendCapability): boolean;
22
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","names":[],"sources":["../../src/core/capabilities.ts"],"mappings":";;AAiBA;;;;;AAGA;;;;;;;;;;;KAHY,iBAAA;;iBAGI,aAAA,CACd,YAAA,iCACA,UAAA,EAAY,iBAAA"}
1
+ {"version":3,"file":"capabilities.d.ts","names":[],"sources":["../../src/core/capabilities.ts"],"mappings":";;AAgBA;;;;AAA6B;AAW7B;;;;;;;;AAE+B;;KAbnB,iBAAA;;iBAWI,aAAA,CACd,YAAA,iCACA,UAAA,EAAY,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","names":[],"sources":["../../src/core/capabilities.ts"],"sourcesContent":["/**\n * Backend capability tokens advertised by pl in\n * `MaintenanceAPI.Ping.Response.capabilities`.\n * Capabilities affect behaviour of inner ML mechanisms and allow\n * to detect incompatibilities between blocks and backend via\n * via `TemplateDataV3.requiredCapabilities`.\n *\n * Mirror of `pl/platform/api/plapiserver/server_capabilities.go` — keep\n * tokens in sync with the backend's advertised list. Format is\n * `<feature>:<version>`; bump the version when wire semantics change.\n *\n * Shared across:\n * - `@milaboratories/pl-client` — client-side capability checks\n * - `@platforma-sdk/tengo-builder` — populates `requiredCapabilities` at compile time\n * - `@platforma-sdk/block-tools` — copies it onto the published manifest\n * - `@milaboratories/pl-middle-layer` — checks it at install time\n */\nexport type BackendCapability = \"auth:v2\" | \"treeFilter:v2\" | \"wasm:v1\";\n\n/** True iff `capabilities` advertises the requested token. */\nexport function hasCapability(\n capabilities: readonly string[] | undefined,\n capability: BackendCapability,\n): boolean {\n return capabilities?.includes(capability) ?? false;\n}\n"],"mappings":";;AAoBA,SAAgB,cACd,cACA,YACS;AACT,QAAO,cAAc,SAAS,WAAW,IAAI"}
1
+ {"version":3,"file":"capabilities.js","names":[],"sources":["../../src/core/capabilities.ts"],"sourcesContent":["/**\n * Backend capability tokens advertised by pl in\n * `MaintenanceAPI.Ping.Response.capabilities`.\n * Capabilities affect behaviour of inner ML mechanisms and allow\n * to detect incompatibilities between blocks and backend via\n * via `TemplateDataV3.requiredCapabilities`.\n *\n * Keep tokens in sync with the backend's advertised list. Format is\n * `<feature>:<version>`; bump the version when wire semantics change.\n *\n * Shared across:\n * - `@milaboratories/pl-client` — client-side capability checks\n * - `@platforma-sdk/tengo-builder` — populates `requiredCapabilities` at compile time\n * - `@platforma-sdk/block-tools` — copies it onto the published manifest\n * - `@milaboratories/pl-middle-layer` — checks it at install time\n */\nexport type BackendCapability =\n | \"auth:v2\"\n | \"treeFilter:v2\"\n | \"wasm:v1\"\n // Project-sharing capability tokens.\n | \"crossTreeRefs:v1\" // cross-color field attach (accept a foreign-colored shared envelope)\n | \"userListing:v1\" // list users for the recipient picker\n | \"publicGrants:v1\" // public (everyone) grants allowed for any role\n | \"txListGrants:v1\"; // list grants inside a transaction (batched recipient reads)\n\n/** True iff `capabilities` advertises the requested token. */\nexport function hasCapability(\n capabilities: readonly string[] | undefined,\n capability: BackendCapability,\n): boolean {\n return capabilities?.includes(capability) ?? false;\n}\n"],"mappings":";;AA2BA,SAAgB,cACd,cACA,YACS;CACT,OAAO,cAAc,SAAS,UAAU,KAAK;AAC/C"}
@@ -1,6 +1,6 @@
1
1
  const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_types = require("./types.cjs");
3
- const require_api = require("../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs");
3
+ require("../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs");
4
4
  const require_stat = require("./stat.cjs");
5
5
  const require_transaction = require("./transaction.cjs");
6
6
  const require_pl = require("../helpers/pl.cjs");
@@ -11,7 +11,7 @@ const require_advisory_locks = require("./advisory_locks.cjs");
11
11
  const require_user_resources = require("./user_resources.cjs");
12
12
  let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
13
13
  let node_timers_promises = require("node:timers/promises");
14
- node_timers_promises = require_runtime.__toESM(node_timers_promises);
14
+ node_timers_promises = require_runtime.__toESM(node_timers_promises, 1);
15
15
  let lru_cache = require("lru-cache");
16
16
  //#region src/core/client.ts
17
17
  const defaultTxOps = { sync: false };
@@ -37,6 +37,10 @@ var PlClient = class PlClient {
37
37
  /** Stores client root (this abstraction is intended for future implementation of the security model) */
38
38
  _clientRoot = "";
39
39
  _userResources;
40
+ /** Cached effective role of the authenticated session, fetched once during
41
+ * init via the GetSessionInfo RPC. `null` for an anonymous (no-auth)
42
+ * connection — mirrors {@link authUser}. Read through {@link currentUserRole}. */
43
+ _currentUserRole = null;
40
44
  _txCommittedStat = require_stat.initialTxStat();
41
45
  _txConflictStat = require_stat.initialTxStat();
42
46
  _txErrorStat = require_stat.initialTxStat();
@@ -138,10 +142,22 @@ var PlClient = class PlClient {
138
142
  this.checkInitialized();
139
143
  return this._ll.hasCapability(capability);
140
144
  }
145
+ /** Effective role of the authenticated session, resolved once during init via
146
+ * the GetSessionInfo RPC and cached. `null` for an anonymous (no-auth)
147
+ * connection, or when the backend predates GetSessionInfo. Mirrors
148
+ * {@link authUser}'s null contract. */
149
+ get currentUserRole() {
150
+ this.checkInitialized();
151
+ return this._currentUserRole;
152
+ }
153
+ /** Login of the authenticated user, or `null` for an anonymous connection. */
154
+ get authUser() {
155
+ this.checkInitialized();
156
+ return this.userResources.authUser;
157
+ }
141
158
  /**
142
- * True if the backend honors per-file `permissions` on workdir fill rules
143
- * (PR #1830 in milaboratory/pl). See `LLPlClient.supportsWritableWorkdirFiles`
144
- * for the full definition.
159
+ * True if the backend honors per-file `permissions` on workdir fill rules.
160
+ * See {@link LLPlClient.supportsWritableWorkdirFiles} for the full definition.
145
161
  */
146
162
  get supportsWritableWorkdirFiles() {
147
163
  this.checkInitialized();
@@ -159,11 +175,12 @@ var PlClient = class PlClient {
159
175
  if (this.initialized) throw new Error("Already initialized");
160
176
  this._ll = await this.buildLLPlClient(false);
161
177
  const wireProtocol = this._ll.wireProtocol;
162
- if (this._ll.serverInfo.compression === require_api.MaintenanceAPI_Ping_Response_Compression.GZIP) {
178
+ if (this._ll.serverInfo.compression === 1) {
163
179
  await this._ll.close();
164
180
  this._ll = await this.buildLLPlClient(true, wireProtocol);
165
181
  }
166
182
  const userRoot = await this.userResources.getUserRoot({ createIfNotExists: true });
183
+ if (this.userResources.authUser !== null && this._ll.hasCapability("publicGrants:v1")) this._currentUserRole = (await this._ll.getSessionInfo()).role;
167
184
  if (this.conf.alternativeRoot === void 0) this._clientRoot = userRoot;
168
185
  else this._clientRoot = await this._withTx("initialization", true, userRoot, async (tx) => {
169
186
  const aFId = {
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","names":["initialTxStat","plAddressToConfig","LLPlClient","DefaultFinalResourceDataPredicate","LRUCache","addStat","isNullSignedResourceId","ensureSignedResourceIdNotNull","UserResources","MaintenanceAPI_Ping_Response_Compression","ClientRoot","advisoryLock","PlTransaction","parseSignedResourceId","TxCommitConflict","tp"],"sources":["../../src/core/client.ts"],"sourcesContent":["import type { AuthOps, PlClientConfig, PlConnectionStatusListener, wireProtocol } from \"./config\";\nimport type { PlCallOps } from \"./ll_client\";\nimport { LLPlClient } from \"./ll_client\";\nimport { PlTransaction, TxCommitConflict } from \"./transaction\";\nimport type { OptionalSignedResourceId, SignedResourceId } from \"./types\";\nimport {\n ensureSignedResourceIdNotNull,\n isNullSignedResourceId,\n NullSignedResourceId,\n parseSignedResourceId,\n} from \"./types\";\nimport type { ColorProof } from \"./types\";\nimport { ClientRoot } from \"../helpers/pl\";\nimport type { MiLogger, RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { assertNever, createRetryState, nextRetryStateOrError } from \"@milaboratories/ts-helpers\";\nimport type { PlDriver, PlDriverDefinition } from \"./driver\";\nimport type {\n MaintenanceAPI_Ping_Response,\n MaintenanceAPI_License_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { MaintenanceAPI_Ping_Response_Compression } from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport * as tp from \"node:timers/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { LRUCache } from \"lru-cache\";\nimport type { ResourceDataCacheRecord } from \"./cache\";\nimport type { FinalResourceDataPredicate } from \"./final\";\nimport { DefaultFinalResourceDataPredicate } from \"./final\";\nimport type { AllTxStat, TxStat } from \"./stat\";\nimport { addStat, initialTxStat } from \"./stat\";\nimport type { WireConnection } from \"./wire\";\nimport { advisoryLock } from \"./advisory_locks\";\nimport { plAddressToConfig } from \"./config\";\nimport { UserResources } from \"./user_resources\";\nimport type { BackendCapability } from \"./capabilities\";\n\nexport type TxOps = PlCallOps & {\n sync?: boolean;\n retryOptions?: RetryOptions;\n name?: string;\n lockId?: string;\n};\n\nconst defaultTxOps = {\n sync: false,\n};\n\nfunction alternativeRootFieldName(alternativeRoot: string): string {\n return `alternative_root_${alternativeRoot}`;\n}\n\n/** Client to access core PL API. */\nexport class PlClient {\n private readonly drivers = new Map<string, PlDriver>();\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n private readonly txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n private readonly forceSync: boolean;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n private readonly defaultRetryOptions: RetryOptions;\n\n private readonly buildLLPlClient: (\n shouldUseGzip: boolean,\n wireProtocol?: wireProtocol,\n ) => Promise<LLPlClient>;\n private _ll?: LLPlClient;\n\n private get ll(): LLPlClient {\n if (this._ll === undefined) {\n throw new Error(\"LLPlClient not initialized\");\n }\n return this._ll;\n }\n\n /** Stores client root (this abstraction is intended for future implementation of the security model) */\n private _clientRoot: OptionalSignedResourceId = NullSignedResourceId;\n\n private _userResources?: UserResources;\n\n private _txCommittedStat: TxStat = initialTxStat();\n private _txConflictStat: TxStat = initialTxStat();\n private _txErrorStat: TxStat = initialTxStat();\n\n //\n // Caching\n //\n\n /** This function determines whether resource data can be cached */\n public readonly finalPredicate: FinalResourceDataPredicate;\n\n /** Resource data cache, to minimize redundant data rereading from remote db */\n private readonly resourceDataCache: LRUCache<SignedResourceId, ResourceDataCacheRecord>;\n\n private constructor(\n configOrAddress: PlClientConfig | string,\n auth: AuthOps,\n ops: {\n statusListener?: PlConnectionStatusListener;\n finalPredicate?: FinalResourceDataPredicate;\n logger?: MiLogger;\n } = {},\n ) {\n const conf =\n typeof configOrAddress === \"string\" ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n this.buildLLPlClient = async (\n shouldUseGzip: boolean,\n wireProtocol?: wireProtocol,\n ): Promise<LLPlClient> => {\n if (wireProtocol) conf.wireProtocol = wireProtocol;\n return await LLPlClient.build(conf, { auth, ...ops, shouldUseGzip });\n };\n\n this.txDelay = conf.txDelay;\n this.forceSync = conf.forceSync;\n this.finalPredicate = ops.finalPredicate ?? DefaultFinalResourceDataPredicate;\n this.resourceDataCache = new LRUCache({\n maxSize: conf.maxCacheBytes,\n sizeCalculation: (v) => (v.basicData.data?.length ?? 0) + 64,\n });\n switch (conf.retryBackoffAlgorithm) {\n case \"exponential\":\n this.defaultRetryOptions = {\n type: \"exponentialBackoff\",\n initialDelay: conf.retryInitialDelay,\n maxAttempts: conf.retryMaxAttempts,\n backoffMultiplier: conf.retryExponentialBackoffMultiplier,\n jitter: conf.retryJitter,\n };\n break;\n case \"linear\":\n this.defaultRetryOptions = {\n type: \"linearBackoff\",\n initialDelay: conf.retryInitialDelay,\n maxAttempts: conf.retryMaxAttempts,\n backoffStep: conf.retryLinearBackoffStep,\n jitter: conf.retryJitter,\n };\n break;\n default:\n assertNever(conf.retryBackoffAlgorithm);\n }\n }\n\n public get txCommittedStat(): TxStat {\n return { ...this._txCommittedStat };\n }\n\n public get txConflictStat(): TxStat {\n return { ...this._txConflictStat };\n }\n\n public get txErrorStat(): TxStat {\n return { ...this._txErrorStat };\n }\n\n public get txTotalStat(): TxStat {\n return addStat(addStat(this._txCommittedStat, this._txConflictStat), this._txErrorStat);\n }\n\n public get allTxStat(): AllTxStat {\n return {\n committed: this.txCommittedStat,\n conflict: this.txConflictStat,\n error: this.txErrorStat,\n };\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async license(): Promise<MaintenanceAPI_License_Response> {\n return await this.ll.license();\n }\n\n /**\n * Returns the user root SignedResourceId via ListUserResources.\n * @param opts.login - target user login; omit for the authenticated user.\n * @returns SignedResourceId of the user root, or undefined if the server returned no userRoot entry.\n * @throws if the backend does not implement ListUserResources (callers should catch with isUnimplementedError).\n */\n public async getUserRoot(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n public async getUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n public async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n return this.userResources.getUserRoot(opts);\n }\n\n public get conf(): PlClientConfig {\n return this.ll.conf;\n }\n\n public get httpDispatcher(): Dispatcher {\n return this.ll.httpDispatcher;\n }\n\n public get connectionOpts(): WireConnection {\n return this.ll.wireConnection;\n }\n\n private get initialized() {\n return !isNullSignedResourceId(this._clientRoot);\n }\n\n private checkInitialized() {\n if (!this.initialized) throw new Error(\"Client not initialized\");\n }\n\n public get clientRoot(): SignedResourceId {\n this.checkInitialized();\n return ensureSignedResourceIdNotNull(this._clientRoot);\n }\n\n public get serverInfo(): MaintenanceAPI_Ping_Response {\n this.checkInitialized();\n return this._ll!.serverInfo;\n }\n\n public hasCapability(capability: BackendCapability): boolean {\n this.checkInitialized();\n return this._ll!.hasCapability(capability);\n }\n\n /**\n * True if the backend honors per-file `permissions` on workdir fill rules\n * (PR #1830 in milaboratory/pl). See `LLPlClient.supportsWritableWorkdirFiles`\n * for the full definition.\n */\n public get supportsWritableWorkdirFiles(): boolean {\n this.checkInitialized();\n return this._ll!.supportsWritableWorkdirFiles;\n }\n\n /** User resources index for discovering data libraries and other shared resources. */\n public get userResources(): UserResources {\n if (!this._ll) throw new Error(\"Client not initialized\");\n\n if (!this._userResources) {\n this._userResources = new UserResources(this._ll, this._withTx.bind(this), this._ll.authUser);\n }\n\n return this._userResources;\n }\n\n /** Discovers or creates the user's root resource via UserResources,\n * then handles alternativeRoot if configured. */\n private async init() {\n if (this.initialized) throw new Error(\"Already initialized\");\n\n // Initial client is created without gzip to perform server ping and detect optimal wire protocol.\n // LLPlClient.build() internally calls detectOptimalWireProtocol() which starts with default 'grpc',\n // then retries with 'rest' if ping fails, alternating until a working protocol is found.\n // We save the detected wireProtocol here because if the server supports gzip compression,\n // we'll need to reinitialize the client with gzip enabled - passing the already-detected\n // wireProtocol avoids redundant protocol detection on reinit.\n this._ll = await this.buildLLPlClient(false);\n const wireProtocol = this._ll.wireProtocol;\n\n // LLPlClient.build() guarantees a successful ping; read the cached response instead of pinging again.\n const info = this._ll.serverInfo;\n if (info.compression === MaintenanceAPI_Ping_Response_Compression.GZIP) {\n await this._ll.close();\n this._ll = await this.buildLLPlClient(true, wireProtocol);\n }\n\n const userRoot = await this.userResources.getUserRoot({ createIfNotExists: true });\n\n if (this.conf.alternativeRoot === undefined) {\n this._clientRoot = userRoot;\n } else {\n this._clientRoot = await this._withTx(\"initialization\", true, userRoot, async (tx) => {\n const aFId = {\n resourceId: userRoot,\n fieldName: alternativeRootFieldName(this.conf.alternativeRoot!),\n };\n\n const altRoot = tx.createEphemeral(ClientRoot);\n tx.lock(altRoot);\n tx.createField(aFId, \"Dynamic\");\n tx.setField(aFId, altRoot);\n await tx.commit();\n\n return await altRoot.globalId;\n });\n }\n }\n\n /** Returns true if field existed */\n public async deleteAlternativeRoot(alternativeRootName: string): Promise<boolean> {\n this.checkInitialized();\n if (this.ll.conf.alternativeRoot !== undefined)\n throw new Error(\"Initialized with alternative root.\");\n return await this.withWriteTx(\"delete-alternative-root\", async (tx) => {\n const fId = {\n resourceId: tx.clientRoot,\n fieldName: alternativeRootFieldName(alternativeRootName),\n };\n const exists = tx.fieldExists(fId);\n tx.removeField(fId);\n await tx.commit();\n return await exists;\n });\n }\n\n private async _withTx<T>(\n name: string,\n writable: boolean,\n clientRoot: OptionalSignedResourceId,\n body: (tx: PlTransaction) => Promise<T>,\n ops?: TxOps,\n ): Promise<T> {\n // for exponential / linear backoff\n let retryState = createRetryState(ops?.retryOptions ?? this.defaultRetryOptions);\n\n while (true) {\n const release = ops?.lockId ? await advisoryLock(ops.lockId) : () => {};\n\n try {\n // opening low-level tx\n const llTx = this.ll.createTx(writable, ops);\n // wrapping it into high-level tx (this also asynchronously sends initialization message)\n const tx = new PlTransaction(\n llTx,\n name,\n writable,\n clientRoot,\n this.finalPredicate,\n this.resourceDataCache,\n );\n\n // Auto-set default color proof from the client root's signature.\n // Skip when backend doesn't implement the `set_default_color` TX request.\n if (this.ll.supportsResourceSignatures && !isNullSignedResourceId(clientRoot) && writable) {\n const parsed = parseSignedResourceId(clientRoot);\n if (parsed.signature) {\n tx.setDefaultColor(parsed.signature as ColorProof);\n }\n }\n\n let ok = false;\n let result: T | undefined = undefined;\n let txId;\n\n try {\n // executing transaction body\n result = await body(tx);\n // collecting stat\n this._txCommittedStat = addStat(this._txCommittedStat, tx.stat);\n ok = true;\n } catch (e: unknown) {\n // the only recoverable\n if (e instanceof TxCommitConflict) {\n // ignoring\n // collecting stat\n this._txConflictStat = addStat(this._txConflictStat, tx.stat);\n } else {\n // collecting stat\n this._txErrorStat = addStat(this._txErrorStat, tx.stat);\n throw e;\n }\n } finally {\n // close underlying grpc stream, if not yet done\n\n // even though we can skip two lines below for read-only transactions,\n // we don't do it to simplify reasoning about what is going on in\n // concurrent code, especially in significant latency situations\n await tx.complete();\n await tx.await();\n\n txId = await tx.getGlobalTxId();\n }\n\n if (ok) {\n // syncing on transaction if requested\n if (ops?.sync === undefined ? this.forceSync : ops?.sync) await this.ll.txSync(txId);\n\n // introducing artificial delay, if requested\n if (writable && this.txDelay > 0)\n await tp.setTimeout(this.txDelay, undefined, { signal: ops?.abortSignal });\n\n return result!;\n }\n } finally {\n release();\n }\n\n // we only get here after TxCommitConflict error,\n // all other errors terminate this loop instantly\n\n await tp.setTimeout(retryState.nextDelay, undefined, { signal: ops?.abortSignal });\n retryState = nextRetryStateOrError(retryState);\n }\n }\n\n private async withTx<T>(\n name: string,\n writable: boolean,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n this.checkInitialized();\n return await this._withTx(name, writable, this.clientRoot, body, { ...ops, ...defaultTxOps });\n }\n\n public async withWriteTx<T>(\n name: string,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n return await this.withTx(name, true, body, { ...ops, ...defaultTxOps });\n }\n\n public async withReadTx<T>(\n name: string,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n return await this.withTx(name, false, body, { ...ops, ...defaultTxOps });\n }\n\n public getDriver<Drv extends PlDriver>(definition: PlDriverDefinition<Drv>): Drv {\n const attached = this.drivers.get(definition.name);\n if (attached !== undefined) return attached as Drv;\n const driver = definition.init(this, this.ll, this.httpDispatcher);\n this.drivers.set(definition.name, driver);\n return driver;\n }\n\n /** Closes underlying transport */\n public async close() {\n await this.ll.close();\n }\n\n public static async init(\n configOrAddress: PlClientConfig | string,\n auth: AuthOps,\n ops: {\n statusListener?: PlConnectionStatusListener;\n logger?: MiLogger;\n } = {},\n ) {\n const pl = new PlClient(configOrAddress, auth, ops);\n await pl.init();\n return pl;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs","names":["initialTxStat","plAddressToConfig","LLPlClient","DefaultFinalResourceDataPredicate","LRUCache","addStat","isNullSignedResourceId","ensureSignedResourceIdNotNull","UserResources","ClientRoot","advisoryLock","PlTransaction","parseSignedResourceId","TxCommitConflict","tp"],"sources":["../../src/core/client.ts"],"sourcesContent":["import type { AuthOps, PlClientConfig, PlConnectionStatusListener, wireProtocol } from \"./config\";\nimport type { PlCallOps } from \"./ll_client\";\nimport { LLPlClient } from \"./ll_client\";\nimport { PlTransaction, TxCommitConflict } from \"./transaction\";\nimport type { Role } from \"./transaction\";\nimport type { OptionalSignedResourceId, SignedResourceId } from \"./types\";\nimport {\n ensureSignedResourceIdNotNull,\n isNullSignedResourceId,\n NullSignedResourceId,\n parseSignedResourceId,\n} from \"./types\";\nimport type { ColorProof } from \"./types\";\nimport { ClientRoot } from \"../helpers/pl\";\nimport type { MiLogger, RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { assertNever, createRetryState, nextRetryStateOrError } from \"@milaboratories/ts-helpers\";\nimport type { PlDriver, PlDriverDefinition } from \"./driver\";\nimport type {\n MaintenanceAPI_Ping_Response,\n MaintenanceAPI_License_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { MaintenanceAPI_Ping_Response_Compression } from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport * as tp from \"node:timers/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { LRUCache } from \"lru-cache\";\nimport type { ResourceDataCacheRecord } from \"./cache\";\nimport type { FinalResourceDataPredicate } from \"./final\";\nimport { DefaultFinalResourceDataPredicate } from \"./final\";\nimport type { AllTxStat, TxStat } from \"./stat\";\nimport { addStat, initialTxStat } from \"./stat\";\nimport type { WireConnection } from \"./wire\";\nimport { advisoryLock } from \"./advisory_locks\";\nimport { plAddressToConfig } from \"./config\";\nimport { UserResources } from \"./user_resources\";\nimport type { BackendCapability } from \"./capabilities\";\n\nexport type TxOps = PlCallOps & {\n sync?: boolean;\n retryOptions?: RetryOptions;\n name?: string;\n lockId?: string;\n};\n\nconst defaultTxOps = {\n sync: false,\n};\n\nfunction alternativeRootFieldName(alternativeRoot: string): string {\n return `alternative_root_${alternativeRoot}`;\n}\n\n/** Client to access core PL API. */\nexport class PlClient {\n private readonly drivers = new Map<string, PlDriver>();\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n private readonly txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n private readonly forceSync: boolean;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n private readonly defaultRetryOptions: RetryOptions;\n\n private readonly buildLLPlClient: (\n shouldUseGzip: boolean,\n wireProtocol?: wireProtocol,\n ) => Promise<LLPlClient>;\n private _ll?: LLPlClient;\n\n private get ll(): LLPlClient {\n if (this._ll === undefined) {\n throw new Error(\"LLPlClient not initialized\");\n }\n return this._ll;\n }\n\n /** Stores client root (this abstraction is intended for future implementation of the security model) */\n private _clientRoot: OptionalSignedResourceId = NullSignedResourceId;\n\n private _userResources?: UserResources;\n\n /** Cached effective role of the authenticated session, fetched once during\n * init via the GetSessionInfo RPC. `null` for an anonymous (no-auth)\n * connection — mirrors {@link authUser}. Read through {@link currentUserRole}. */\n private _currentUserRole: Role | null = null;\n\n private _txCommittedStat: TxStat = initialTxStat();\n private _txConflictStat: TxStat = initialTxStat();\n private _txErrorStat: TxStat = initialTxStat();\n\n //\n // Caching\n //\n\n /** This function determines whether resource data can be cached */\n public readonly finalPredicate: FinalResourceDataPredicate;\n\n /** Resource data cache, to minimize redundant data rereading from remote db */\n private readonly resourceDataCache: LRUCache<SignedResourceId, ResourceDataCacheRecord>;\n\n private constructor(\n configOrAddress: PlClientConfig | string,\n auth: AuthOps,\n ops: {\n statusListener?: PlConnectionStatusListener;\n finalPredicate?: FinalResourceDataPredicate;\n logger?: MiLogger;\n } = {},\n ) {\n const conf =\n typeof configOrAddress === \"string\" ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n this.buildLLPlClient = async (\n shouldUseGzip: boolean,\n wireProtocol?: wireProtocol,\n ): Promise<LLPlClient> => {\n if (wireProtocol) conf.wireProtocol = wireProtocol;\n return await LLPlClient.build(conf, { auth, ...ops, shouldUseGzip });\n };\n\n this.txDelay = conf.txDelay;\n this.forceSync = conf.forceSync;\n this.finalPredicate = ops.finalPredicate ?? DefaultFinalResourceDataPredicate;\n this.resourceDataCache = new LRUCache({\n maxSize: conf.maxCacheBytes,\n sizeCalculation: (v) => (v.basicData.data?.length ?? 0) + 64,\n });\n switch (conf.retryBackoffAlgorithm) {\n case \"exponential\":\n this.defaultRetryOptions = {\n type: \"exponentialBackoff\",\n initialDelay: conf.retryInitialDelay,\n maxAttempts: conf.retryMaxAttempts,\n backoffMultiplier: conf.retryExponentialBackoffMultiplier,\n jitter: conf.retryJitter,\n };\n break;\n case \"linear\":\n this.defaultRetryOptions = {\n type: \"linearBackoff\",\n initialDelay: conf.retryInitialDelay,\n maxAttempts: conf.retryMaxAttempts,\n backoffStep: conf.retryLinearBackoffStep,\n jitter: conf.retryJitter,\n };\n break;\n default:\n assertNever(conf.retryBackoffAlgorithm);\n }\n }\n\n public get txCommittedStat(): TxStat {\n return { ...this._txCommittedStat };\n }\n\n public get txConflictStat(): TxStat {\n return { ...this._txConflictStat };\n }\n\n public get txErrorStat(): TxStat {\n return { ...this._txErrorStat };\n }\n\n public get txTotalStat(): TxStat {\n return addStat(addStat(this._txCommittedStat, this._txConflictStat), this._txErrorStat);\n }\n\n public get allTxStat(): AllTxStat {\n return {\n committed: this.txCommittedStat,\n conflict: this.txConflictStat,\n error: this.txErrorStat,\n };\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async license(): Promise<MaintenanceAPI_License_Response> {\n return await this.ll.license();\n }\n\n /**\n * Returns the user root SignedResourceId via ListUserResources.\n * @param opts.login - target user login; omit for the authenticated user.\n * @returns SignedResourceId of the user root, or undefined if the server returned no userRoot entry.\n * @throws if the backend does not implement ListUserResources (callers should catch with isUnimplementedError).\n */\n public async getUserRoot(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n public async getUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n public async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n return this.userResources.getUserRoot(opts);\n }\n\n public get conf(): PlClientConfig {\n return this.ll.conf;\n }\n\n public get httpDispatcher(): Dispatcher {\n return this.ll.httpDispatcher;\n }\n\n public get connectionOpts(): WireConnection {\n return this.ll.wireConnection;\n }\n\n private get initialized() {\n return !isNullSignedResourceId(this._clientRoot);\n }\n\n private checkInitialized() {\n if (!this.initialized) throw new Error(\"Client not initialized\");\n }\n\n public get clientRoot(): SignedResourceId {\n this.checkInitialized();\n return ensureSignedResourceIdNotNull(this._clientRoot);\n }\n\n public get serverInfo(): MaintenanceAPI_Ping_Response {\n this.checkInitialized();\n return this._ll!.serverInfo;\n }\n\n public hasCapability(capability: BackendCapability): boolean {\n this.checkInitialized();\n return this._ll!.hasCapability(capability);\n }\n\n /** Effective role of the authenticated session, resolved once during init via\n * the GetSessionInfo RPC and cached. `null` for an anonymous (no-auth)\n * connection, or when the backend predates GetSessionInfo. Mirrors\n * {@link authUser}'s null contract. */\n public get currentUserRole(): Role | null {\n this.checkInitialized();\n return this._currentUserRole;\n }\n\n /** Login of the authenticated user, or `null` for an anonymous connection. */\n public get authUser(): string | null {\n this.checkInitialized();\n return this.userResources.authUser;\n }\n\n /**\n * True if the backend honors per-file `permissions` on workdir fill rules.\n * See {@link LLPlClient.supportsWritableWorkdirFiles} for the full definition.\n */\n public get supportsWritableWorkdirFiles(): boolean {\n this.checkInitialized();\n return this._ll!.supportsWritableWorkdirFiles;\n }\n\n /** User resources index for discovering data libraries and other shared resources. */\n public get userResources(): UserResources {\n if (!this._ll) throw new Error(\"Client not initialized\");\n\n if (!this._userResources) {\n this._userResources = new UserResources(this._ll, this._withTx.bind(this), this._ll.authUser);\n }\n\n return this._userResources;\n }\n\n /** Discovers or creates the user's root resource via UserResources,\n * then handles alternativeRoot if configured. */\n private async init() {\n if (this.initialized) throw new Error(\"Already initialized\");\n\n // Initial client is created without gzip to perform server ping and detect optimal wire protocol.\n // LLPlClient.build() internally calls detectOptimalWireProtocol() which starts with default 'grpc',\n // then retries with 'rest' if ping fails, alternating until a working protocol is found.\n // We save the detected wireProtocol here because if the server supports gzip compression,\n // we'll need to reinitialize the client with gzip enabled - passing the already-detected\n // wireProtocol avoids redundant protocol detection on reinit.\n this._ll = await this.buildLLPlClient(false);\n const wireProtocol = this._ll.wireProtocol;\n\n // LLPlClient.build() guarantees a successful ping; read the cached response instead of pinging again.\n const info = this._ll.serverInfo;\n if (info.compression === MaintenanceAPI_Ping_Response_Compression.GZIP) {\n await this._ll.close();\n this._ll = await this.buildLLPlClient(true, wireProtocol);\n }\n\n const userRoot = await this.userResources.getUserRoot({ createIfNotExists: true });\n\n // Resolve the caller's role once; only the publicGrants-gated share-with-everybody check uses it,\n // so skip it for anonymous connections or when publicGrants:v1 is absent. Use _ll.hasCapability,\n // not this.hasCapability: we are mid-init, so this.checkInitialized() would throw.\n if (this.userResources.authUser !== null && this._ll.hasCapability(\"publicGrants:v1\")) {\n this._currentUserRole = (await this._ll.getSessionInfo()).role;\n }\n\n if (this.conf.alternativeRoot === undefined) {\n this._clientRoot = userRoot;\n } else {\n this._clientRoot = await this._withTx(\"initialization\", true, userRoot, async (tx) => {\n const aFId = {\n resourceId: userRoot,\n fieldName: alternativeRootFieldName(this.conf.alternativeRoot!),\n };\n\n const altRoot = tx.createEphemeral(ClientRoot);\n tx.lock(altRoot);\n tx.createField(aFId, \"Dynamic\");\n tx.setField(aFId, altRoot);\n await tx.commit();\n\n return await altRoot.globalId;\n });\n }\n }\n\n /** Returns true if field existed */\n public async deleteAlternativeRoot(alternativeRootName: string): Promise<boolean> {\n this.checkInitialized();\n if (this.ll.conf.alternativeRoot !== undefined)\n throw new Error(\"Initialized with alternative root.\");\n return await this.withWriteTx(\"delete-alternative-root\", async (tx) => {\n const fId = {\n resourceId: tx.clientRoot,\n fieldName: alternativeRootFieldName(alternativeRootName),\n };\n const exists = tx.fieldExists(fId);\n tx.removeField(fId);\n await tx.commit();\n return await exists;\n });\n }\n\n private async _withTx<T>(\n name: string,\n writable: boolean,\n clientRoot: OptionalSignedResourceId,\n body: (tx: PlTransaction) => Promise<T>,\n ops?: TxOps,\n ): Promise<T> {\n // for exponential / linear backoff\n let retryState = createRetryState(ops?.retryOptions ?? this.defaultRetryOptions);\n\n while (true) {\n const release = ops?.lockId ? await advisoryLock(ops.lockId) : () => {};\n\n try {\n // opening low-level tx\n const llTx = this.ll.createTx(writable, ops);\n // wrapping it into high-level tx (this also asynchronously sends initialization message)\n const tx = new PlTransaction(\n llTx,\n name,\n writable,\n clientRoot,\n this.finalPredicate,\n this.resourceDataCache,\n );\n\n // Auto-set default color proof from the client root's signature.\n // Skip when backend doesn't implement the `set_default_color` TX request.\n if (this.ll.supportsResourceSignatures && !isNullSignedResourceId(clientRoot) && writable) {\n const parsed = parseSignedResourceId(clientRoot);\n if (parsed.signature) {\n tx.setDefaultColor(parsed.signature as ColorProof);\n }\n }\n\n let ok = false;\n let result: T | undefined = undefined;\n let txId;\n\n try {\n // executing transaction body\n result = await body(tx);\n // collecting stat\n this._txCommittedStat = addStat(this._txCommittedStat, tx.stat);\n ok = true;\n } catch (e: unknown) {\n // the only recoverable\n if (e instanceof TxCommitConflict) {\n // ignoring\n // collecting stat\n this._txConflictStat = addStat(this._txConflictStat, tx.stat);\n } else {\n // collecting stat\n this._txErrorStat = addStat(this._txErrorStat, tx.stat);\n throw e;\n }\n } finally {\n // close underlying grpc stream, if not yet done\n\n // even though we can skip two lines below for read-only transactions,\n // we don't do it to simplify reasoning about what is going on in\n // concurrent code, especially in significant latency situations\n await tx.complete();\n await tx.await();\n\n txId = await tx.getGlobalTxId();\n }\n\n if (ok) {\n // syncing on transaction if requested\n if (ops?.sync === undefined ? this.forceSync : ops?.sync) await this.ll.txSync(txId);\n\n // introducing artificial delay, if requested\n if (writable && this.txDelay > 0)\n await tp.setTimeout(this.txDelay, undefined, { signal: ops?.abortSignal });\n\n return result!;\n }\n } finally {\n release();\n }\n\n // we only get here after TxCommitConflict error,\n // all other errors terminate this loop instantly\n\n await tp.setTimeout(retryState.nextDelay, undefined, { signal: ops?.abortSignal });\n retryState = nextRetryStateOrError(retryState);\n }\n }\n\n private async withTx<T>(\n name: string,\n writable: boolean,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n this.checkInitialized();\n return await this._withTx(name, writable, this.clientRoot, body, { ...ops, ...defaultTxOps });\n }\n\n public async withWriteTx<T>(\n name: string,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n return await this.withTx(name, true, body, { ...ops, ...defaultTxOps });\n }\n\n public async withReadTx<T>(\n name: string,\n body: (tx: PlTransaction) => Promise<T>,\n ops: Partial<TxOps> = {},\n ): Promise<T> {\n return await this.withTx(name, false, body, { ...ops, ...defaultTxOps });\n }\n\n public getDriver<Drv extends PlDriver>(definition: PlDriverDefinition<Drv>): Drv {\n const attached = this.drivers.get(definition.name);\n if (attached !== undefined) return attached as Drv;\n const driver = definition.init(this, this.ll, this.httpDispatcher);\n this.drivers.set(definition.name, driver);\n return driver;\n }\n\n /** Closes underlying transport */\n public async close() {\n await this.ll.close();\n }\n\n public static async init(\n configOrAddress: PlClientConfig | string,\n auth: AuthOps,\n ops: {\n statusListener?: PlConnectionStatusListener;\n logger?: MiLogger;\n } = {},\n ) {\n const pl = new PlClient(configOrAddress, auth, ops);\n await pl.init();\n return pl;\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { SignedResourceId } from "./types.js";
2
2
  import { MaintenanceAPI_License_Response, MaintenanceAPI_Ping_Response } from "../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js";
3
3
  import { FinalResourceDataPredicate } from "./final.js";
4
4
  import { AllTxStat, TxStat } from "./stat.js";
5
- import { PlTransaction } from "./transaction.js";
5
+ import { PlTransaction, Role } from "./transaction.js";
6
6
  import { AuthOps, PlClientConfig, PlConnectionStatusListener } from "./config.js";
7
7
  import { BackendCapability } from "./capabilities.js";
8
8
  import { WireConnection } from "./wire.js";
@@ -35,6 +35,10 @@ declare class PlClient {
35
35
  /** Stores client root (this abstraction is intended for future implementation of the security model) */
36
36
  private _clientRoot;
37
37
  private _userResources?;
38
+ /** Cached effective role of the authenticated session, fetched once during
39
+ * init via the GetSessionInfo RPC. `null` for an anonymous (no-auth)
40
+ * connection — mirrors {@link authUser}. Read through {@link currentUserRole}. */
41
+ private _currentUserRole;
38
42
  private _txCommittedStat;
39
43
  private _txConflictStat;
40
44
  private _txErrorStat;
@@ -72,10 +76,16 @@ declare class PlClient {
72
76
  get clientRoot(): SignedResourceId;
73
77
  get serverInfo(): MaintenanceAPI_Ping_Response;
74
78
  hasCapability(capability: BackendCapability): boolean;
79
+ /** Effective role of the authenticated session, resolved once during init via
80
+ * the GetSessionInfo RPC and cached. `null` for an anonymous (no-auth)
81
+ * connection, or when the backend predates GetSessionInfo. Mirrors
82
+ * {@link authUser}'s null contract. */
83
+ get currentUserRole(): Role | null;
84
+ /** Login of the authenticated user, or `null` for an anonymous connection. */
85
+ get authUser(): string | null;
75
86
  /**
76
- * True if the backend honors per-file `permissions` on workdir fill rules
77
- * (PR #1830 in milaboratory/pl). See `LLPlClient.supportsWritableWorkdirFiles`
78
- * for the full definition.
87
+ * True if the backend honors per-file `permissions` on workdir fill rules.
88
+ * See {@link LLPlClient.supportsWritableWorkdirFiles} for the full definition.
79
89
  */
80
90
  get supportsWritableWorkdirFiles(): boolean;
81
91
  /** User resources index for discovering data libraries and other shared resources. */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/core/client.ts"],"mappings":";;;;;;;;;;;;;;;KAmCY,KAAA,GAAQ,SAAA;EAClB,IAAA;EACA,YAAA,GAAe,YAAA;EACf,IAAA;EACA,MAAA;AAAA;;cAYW,QAAA;EAAA,iBACM,OAAA;EAfF;;EAAA,iBAmBE,OAAA;EAjBX;EAAA,iBAoBW,SAAA;EARN;EAAA,iBAWM,mBAAA;EAAA,iBAEA,eAAA;EAAA,QAIT,GAAA;EAAA,YAEI,EAAA,CAAA;EAiFiB;EAAA,QAzErB,WAAA;EAAA,QAEA,cAAA;EAAA,QAEA,gBAAA;EAAA,QACA,eAAA;EAAA,QACA,YAAA;EA2FwB;EAAA,SApFhB,cAAA,EAAgB,0BAAA;EAiGpB;EAAA,iBA9FK,iBAAA;EAAA,QAEV,WAAA,CAAA;EAAA,IAmDI,eAAA,CAAA,GAAmB,MAAA;EAAA,IAInB,cAAA,CAAA,GAAkB,MAAA;EAAA,IAIlB,WAAA,CAAA,GAAe,MAAA;EAAA,IAIf,WAAA,CAAA,GAAe,MAAA;EAAA,IAIf,SAAA,CAAA,GAAa,SAAA;EAQX,IAAA,CAAA,GAAQ,OAAA,CAAQ,4BAAA;EAIhB,OAAA,CAAA,GAAW,OAAA,CAAQ,+BAAA;EAsEJ;;;;;;EA5Df,WAAA,CAAY,IAAA;IACvB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EACC,WAAA,CAAY,IAAA;IACvB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EAAA,IAOD,IAAA,CAAA,GAAQ,cAAA;EAAA,IAIR,cAAA,CAAA,GAAkB,UAAA;EAAA,IAIlB,cAAA,CAAA,GAAkB,cAAA;EAAA,YAIjB,WAAA,CAAA;EAAA,QAIJ,gBAAA;EAAA,IAIG,UAAA,CAAA,GAAc,gBAAA;EAAA,IAKd,UAAA,CAAA,GAAc,4BAAA;EAKlB,aAAA,CAAc,UAAA,EAAY,iBAAA;EAyNzB;;;;;EAAA,IA/MG,4BAAA,CAAA;EAmNH;EAAA,IA7MG,aAAA,CAAA,GAAiB,aAAA;EA7LX;;EAAA,QAyMH,IAAA;EAjMG;EA2OJ,qBAAA,CAAsB,mBAAA,WAA8B,OAAA;EAAA,QAgBnD,OAAA;EAAA,QA0FA,MAAA;EAUD,WAAA,GAAA,CACX,IAAA,UACA,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,GACrC,GAAA,GAAK,OAAA,CAAQ,KAAA,IACZ,OAAA,CAAQ,CAAA;EAIE,UAAA,GAAA,CACX,IAAA,UACA,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,GACrC,GAAA,GAAK,OAAA,CAAQ,KAAA,IACZ,OAAA,CAAQ,CAAA;EAIJ,SAAA,aAAsB,QAAA,CAAA,CAAU,UAAA,EAAY,kBAAA,CAAmB,GAAA,IAAO,GAAA;EA3VrE;EAoWK,KAAA,CAAA,GAAK,OAAA;EAAA,OAIE,IAAA,CAClB,eAAA,EAAiB,cAAA,WACjB,IAAA,EAAM,OAAA,EACN,GAAA;IACE,cAAA,GAAiB,0BAAA;IACjB,MAAA,GAAS,QAAA;EAAA,IACL,OAAA,CAAA,QAAA;AAAA"}
1
+ {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/core/client.ts"],"mappings":";;;;;;;;;;;;;;;KAoCY,KAAA,GAAQ,SAAA;EAClB,IAAA;EACA,YAAA,GAAe,YAAY;EAC3B,IAAA;EACA,MAAA;AAAA;;cAYW,QAAA;EAAA,iBACM,OAAA;EAdjB;;EAAA,iBAkBiB,OAAA;EAjBX;EAAA,iBAoBW,SAAA;EARE;EAAA,iBAWF,mBAAA;EAAA,iBAEA,eAAA;EAAA,QAIT,GAAA;EAAA,YAEI,EAAA;EA0Fc;EAAA,QAlFlB,WAAA;EAAA,QAEA,cAAA;EAgGqB;;;EAAA,QA3FrB,gBAAA;EAAA,QAEA,gBAAA;EAAA,QACA,eAAA;EAAA,QACA,YAAA;EA4GJ;EAAA,SArGY,cAAA,EAAgB,0BAAA;EAgHH;EAAA,iBA7GZ,iBAAA;EAAA,QAEV,WAAA;EAAA,IAmDI,eAAA,IAAmB,MAAA;EAAA,IAInB,cAAA,IAAkB,MAAA;EAAA,IAIlB,WAAA,IAAe,MAAA;EAAA,IAIf,WAAA,IAAe,MAAA;EAAA,IAIf,SAAA,IAAa,SAAA;EAQX,IAAA,IAAQ,OAAA,CAAQ,4BAAA;EAIhB,OAAA,IAAW,OAAA,CAAQ,+BAAA;EAuQD;;;;;;EA7PlB,WAAA,CAAY,IAAA;IACvB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EACC,WAAA,CAAY,IAAA;IACvB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EAAA,IAOD,IAAA,IAAQ,cAAA;EAAA,IAIR,cAAA,IAAkB,UAAA;EAAA,IAIlB,cAAA,IAAkB,cAAA;EAAA,YAIjB,WAAA;EAAA,QAIJ,gBAAA;EAAA,IAIG,UAAA,IAAc,gBAAA;EAAA,IAKd,UAAA,IAAc,4BAAA;EAKlB,aAAA,CAAc,UAAA,EAAY,iBAAA;EAkPzB;;;;EAAA,IAzOG,eAAA,IAAmB,IAAA;EAxLb;EAAA,IA8LN,QAAA;EAzLM;;;;EAAA,IAkMN,4BAAA;EA7KH;EAAA,IAmLG,aAAA,IAAiB,aAAA;EAhLpB;;EAAA,QA4LM,IAAA;EApLkB;EAqOnB,qBAAA,CAAsB,mBAAA,WAA8B,OAAA;EAAA,QAgBnD,OAAA;EAAA,QA0FA,MAAA;EAUD,WAAA,IACX,IAAA,UACA,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,GACrC,GAAA,GAAK,OAAA,CAAQ,KAAA,IACZ,OAAA,CAAQ,CAAA;EAIE,UAAA,IACX,IAAA,UACA,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,GACrC,GAAA,GAAK,OAAA,CAAQ,KAAA,IACZ,OAAA,CAAQ,CAAA;EAIJ,SAAA,aAAsB,QAAA,EAAU,UAAA,EAAY,kBAAA,CAAmB,GAAA,IAAO,GAAA;EAzSlE;EAkTE,KAAA,IAAK,OAAA;EAAA,OAIE,IAAA,CAClB,eAAA,EAAiB,cAAA,WACjB,IAAA,EAAM,OAAA,EACN,GAAA;IACE,cAAA,GAAiB,0BAAA;IACjB,MAAA,GAAS,QAAA;EAAA,IACL,OAAA,CAAA,QAAA;AAAA"}
@@ -1,5 +1,5 @@
1
1
  import { ensureSignedResourceIdNotNull, isNullSignedResourceId, parseSignedResourceId } from "./types.js";
2
- import { MaintenanceAPI_Ping_Response_Compression } from "../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js";
2
+ import "../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js";
3
3
  import { addStat, initialTxStat } from "./stat.js";
4
4
  import { PlTransaction, TxCommitConflict } from "./transaction.js";
5
5
  import { ClientRoot } from "../helpers/pl.js";
@@ -35,6 +35,10 @@ var PlClient = class PlClient {
35
35
  /** Stores client root (this abstraction is intended for future implementation of the security model) */
36
36
  _clientRoot = "";
37
37
  _userResources;
38
+ /** Cached effective role of the authenticated session, fetched once during
39
+ * init via the GetSessionInfo RPC. `null` for an anonymous (no-auth)
40
+ * connection — mirrors {@link authUser}. Read through {@link currentUserRole}. */
41
+ _currentUserRole = null;
38
42
  _txCommittedStat = initialTxStat();
39
43
  _txConflictStat = initialTxStat();
40
44
  _txErrorStat = initialTxStat();
@@ -136,10 +140,22 @@ var PlClient = class PlClient {
136
140
  this.checkInitialized();
137
141
  return this._ll.hasCapability(capability);
138
142
  }
143
+ /** Effective role of the authenticated session, resolved once during init via
144
+ * the GetSessionInfo RPC and cached. `null` for an anonymous (no-auth)
145
+ * connection, or when the backend predates GetSessionInfo. Mirrors
146
+ * {@link authUser}'s null contract. */
147
+ get currentUserRole() {
148
+ this.checkInitialized();
149
+ return this._currentUserRole;
150
+ }
151
+ /** Login of the authenticated user, or `null` for an anonymous connection. */
152
+ get authUser() {
153
+ this.checkInitialized();
154
+ return this.userResources.authUser;
155
+ }
139
156
  /**
140
- * True if the backend honors per-file `permissions` on workdir fill rules
141
- * (PR #1830 in milaboratory/pl). See `LLPlClient.supportsWritableWorkdirFiles`
142
- * for the full definition.
157
+ * True if the backend honors per-file `permissions` on workdir fill rules.
158
+ * See {@link LLPlClient.supportsWritableWorkdirFiles} for the full definition.
143
159
  */
144
160
  get supportsWritableWorkdirFiles() {
145
161
  this.checkInitialized();
@@ -157,11 +173,12 @@ var PlClient = class PlClient {
157
173
  if (this.initialized) throw new Error("Already initialized");
158
174
  this._ll = await this.buildLLPlClient(false);
159
175
  const wireProtocol = this._ll.wireProtocol;
160
- if (this._ll.serverInfo.compression === MaintenanceAPI_Ping_Response_Compression.GZIP) {
176
+ if (this._ll.serverInfo.compression === 1) {
161
177
  await this._ll.close();
162
178
  this._ll = await this.buildLLPlClient(true, wireProtocol);
163
179
  }
164
180
  const userRoot = await this.userResources.getUserRoot({ createIfNotExists: true });
181
+ if (this.userResources.authUser !== null && this._ll.hasCapability("publicGrants:v1")) this._currentUserRole = (await this._ll.getSessionInfo()).role;
165
182
  if (this.conf.alternativeRoot === void 0) this._clientRoot = userRoot;
166
183
  else this._clientRoot = await this._withTx("initialization", true, userRoot, async (tx) => {
167
184
  const aFId = {