@stigmer/server 3.22.1-dev.20260922095755 → 3.23.0

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 (330) hide show
  1. package/dist/artifactstorage/artifact-storage.d.ts +29 -31
  2. package/dist/artifactstorage/artifact-storage.d.ts.map +1 -1
  3. package/dist/artifactstorage/artifact-storage.js +5 -7
  4. package/dist/artifactstorage/artifact-storage.js.map +1 -1
  5. package/dist/artifactstorage/r2-storage.d.ts +12 -7
  6. package/dist/artifactstorage/r2-storage.d.ts.map +1 -1
  7. package/dist/artifactstorage/r2-storage.js +6 -14
  8. package/dist/artifactstorage/r2-storage.js.map +1 -1
  9. package/dist/authorization/authorizer.d.ts +8 -4
  10. package/dist/authorization/authorizer.d.ts.map +1 -1
  11. package/dist/authorization/authorizer.js +9 -5
  12. package/dist/authorization/authorizer.js.map +1 -1
  13. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  14. package/dist/authorization/derived-tuples.js +25 -10
  15. package/dist/authorization/derived-tuples.js.map +1 -1
  16. package/dist/authorization/evaluator.d.ts +8 -7
  17. package/dist/authorization/evaluator.d.ts.map +1 -1
  18. package/dist/authorization/evaluator.js +20 -4
  19. package/dist/authorization/evaluator.js.map +1 -1
  20. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  21. package/dist/authorization/list-read-scope.js +9 -5
  22. package/dist/authorization/list-read-scope.js.map +1 -1
  23. package/dist/authorization/model/agent.d.ts.map +1 -1
  24. package/dist/authorization/model/agent.js +5 -4
  25. package/dist/authorization/model/agent.js.map +1 -1
  26. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  27. package/dist/authorization/model/agent_instance.js +2 -2
  28. package/dist/authorization/model/agent_instance.js.map +1 -1
  29. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  30. package/dist/authorization/model/mcp_server.js +2 -2
  31. package/dist/authorization/model/mcp_server.js.map +1 -1
  32. package/dist/authorization/model/plugin.d.ts.map +1 -1
  33. package/dist/authorization/model/plugin.js +4 -3
  34. package/dist/authorization/model/plugin.js.map +1 -1
  35. package/dist/authorization/model/rewrite.d.ts +10 -8
  36. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  37. package/dist/authorization/model/rewrite.js +3 -0
  38. package/dist/authorization/model/rewrite.js.map +1 -1
  39. package/dist/authorization/model/skill.d.ts.map +1 -1
  40. package/dist/authorization/model/skill.js +2 -2
  41. package/dist/authorization/model/skill.js.map +1 -1
  42. package/dist/authorization/model/workflow.d.ts.map +1 -1
  43. package/dist/authorization/model/workflow.js +2 -2
  44. package/dist/authorization/model/workflow.js.map +1 -1
  45. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  46. package/dist/authorization/model/workflow_instance.js +2 -2
  47. package/dist/authorization/model/workflow_instance.js.map +1 -1
  48. package/dist/authorization/organization-directory.d.ts.map +1 -1
  49. package/dist/authorization/organization-directory.js +3 -2
  50. package/dist/authorization/organization-directory.js.map +1 -1
  51. package/dist/authorization/store-test-kit.d.ts +6 -0
  52. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  53. package/dist/authorization/store-test-kit.js +62 -16
  54. package/dist/authorization/store-test-kit.js.map +1 -1
  55. package/dist/authorization/tuples.d.ts +32 -13
  56. package/dist/authorization/tuples.d.ts.map +1 -1
  57. package/dist/authorization/tuples.js +11 -3
  58. package/dist/authorization/tuples.js.map +1 -1
  59. package/dist/boot/compose.d.ts.map +1 -1
  60. package/dist/boot/compose.js +49 -24
  61. package/dist/boot/compose.js.map +1 -1
  62. package/dist/boot/config.d.ts +4 -3
  63. package/dist/boot/config.d.ts.map +1 -1
  64. package/dist/boot/config.js.map +1 -1
  65. package/dist/boot/skill-transfer-origin.d.ts +52 -0
  66. package/dist/boot/skill-transfer-origin.d.ts.map +1 -0
  67. package/dist/boot/skill-transfer-origin.js +54 -0
  68. package/dist/boot/skill-transfer-origin.js.map +1 -0
  69. package/dist/domain/agent/controller.d.ts.map +1 -1
  70. package/dist/domain/agent/controller.js +4 -4
  71. package/dist/domain/agent/controller.js.map +1 -1
  72. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  73. package/dist/domain/agentchannel/controller.js +1 -3
  74. package/dist/domain/agentchannel/controller.js.map +1 -1
  75. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  76. package/dist/domain/agentexecution/controller.js +1 -3
  77. package/dist/domain/agentexecution/controller.js.map +1 -1
  78. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  79. package/dist/domain/agentinstance/controller.js +4 -3
  80. package/dist/domain/agentinstance/controller.js.map +1 -1
  81. package/dist/domain/agentshare/constants.d.ts +11 -6
  82. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  83. package/dist/domain/agentshare/constants.js +16 -8
  84. package/dist/domain/agentshare/constants.js.map +1 -1
  85. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  86. package/dist/domain/agentshare/controller.js +1 -3
  87. package/dist/domain/agentshare/controller.js.map +1 -1
  88. package/dist/domain/agentshare/steps.d.ts +25 -18
  89. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  90. package/dist/domain/agentshare/steps.js +142 -41
  91. package/dist/domain/agentshare/steps.js.map +1 -1
  92. package/dist/domain/environment/controller.d.ts.map +1 -1
  93. package/dist/domain/environment/controller.js +3 -2
  94. package/dist/domain/environment/controller.js.map +1 -1
  95. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  96. package/dist/domain/executioncontext/controller.js +1 -2
  97. package/dist/domain/executioncontext/controller.js.map +1 -1
  98. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  99. package/dist/domain/mcpserver/controller.js +4 -3
  100. package/dist/domain/mcpserver/controller.js.map +1 -1
  101. package/dist/domain/plugin/controller.d.ts +3 -7
  102. package/dist/domain/plugin/controller.d.ts.map +1 -1
  103. package/dist/domain/plugin/controller.js +11 -9
  104. package/dist/domain/plugin/controller.js.map +1 -1
  105. package/dist/domain/plugin/push.d.ts +5 -7
  106. package/dist/domain/plugin/push.d.ts.map +1 -1
  107. package/dist/domain/plugin/push.js +14 -8
  108. package/dist/domain/plugin/push.js.map +1 -1
  109. package/dist/domain/schedule/controller.d.ts.map +1 -1
  110. package/dist/domain/schedule/controller.js +1 -3
  111. package/dist/domain/schedule/controller.js.map +1 -1
  112. package/dist/domain/session/controller.d.ts.map +1 -1
  113. package/dist/domain/session/controller.js +2 -3
  114. package/dist/domain/session/controller.js.map +1 -1
  115. package/dist/domain/skill/constants.d.ts +26 -3
  116. package/dist/domain/skill/constants.d.ts.map +1 -1
  117. package/dist/domain/skill/constants.js +26 -3
  118. package/dist/domain/skill/constants.js.map +1 -1
  119. package/dist/domain/skill/controller.d.ts +6 -11
  120. package/dist/domain/skill/controller.d.ts.map +1 -1
  121. package/dist/domain/skill/controller.js +35 -22
  122. package/dist/domain/skill/controller.js.map +1 -1
  123. package/dist/domain/skill/push.d.ts +2 -2
  124. package/dist/domain/skill/push.d.ts.map +1 -1
  125. package/dist/domain/skill/push.js +2 -2
  126. package/dist/domain/skill/push.js.map +1 -1
  127. package/dist/domain/skill/transfer/handler.d.ts +17 -9
  128. package/dist/domain/skill/transfer/handler.d.ts.map +1 -1
  129. package/dist/domain/skill/transfer/handler.js +19 -8
  130. package/dist/domain/skill/transfer/handler.js.map +1 -1
  131. package/dist/domain/skill/transfer/slots.d.ts +26 -41
  132. package/dist/domain/skill/transfer/slots.d.ts.map +1 -1
  133. package/dist/domain/skill/transfer/slots.js +80 -87
  134. package/dist/domain/skill/transfer/slots.js.map +1 -1
  135. package/dist/domain/skill/transfer/staging.d.ts +48 -0
  136. package/dist/domain/skill/transfer/staging.d.ts.map +1 -0
  137. package/dist/domain/skill/transfer/staging.js +127 -0
  138. package/dist/domain/skill/transfer/staging.js.map +1 -0
  139. package/dist/domain/workflow/controller.d.ts.map +1 -1
  140. package/dist/domain/workflow/controller.js +6 -14
  141. package/dist/domain/workflow/controller.js.map +1 -1
  142. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  143. package/dist/domain/workflow/validation/task-config-constraints.d.ts +1 -10
  144. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  145. package/dist/domain/workflow/validation/task-config-constraints.js +2 -3
  146. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  147. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  148. package/dist/domain/workflowexecution/controller.js +2 -4
  149. package/dist/domain/workflowexecution/controller.js.map +1 -1
  150. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  151. package/dist/domain/workflowinstance/controller.js +4 -3
  152. package/dist/domain/workflowinstance/controller.js.map +1 -1
  153. package/dist/extensions/authorization-queries.d.ts +5 -6
  154. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  155. package/dist/extensions/list-read-scope.d.ts +1 -1
  156. package/dist/extensions/resource-authorization.d.ts +2 -3
  157. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  158. package/dist/index.d.ts +3 -1
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +13 -0
  161. package/dist/index.js.map +1 -1
  162. package/dist/pipeline/apiresource-meta.d.ts +3 -12
  163. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  164. package/dist/pipeline/apiresource-meta.js +10 -21
  165. package/dist/pipeline/apiresource-meta.js.map +1 -1
  166. package/dist/pipeline/steps/authorization-tuples.d.ts +3 -9
  167. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  168. package/dist/pipeline/steps/authorization-tuples.js +11 -9
  169. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  170. package/dist/pipeline/steps/references.d.ts +20 -178
  171. package/dist/pipeline/steps/references.d.ts.map +1 -1
  172. package/dist/pipeline/steps/references.js +43 -344
  173. package/dist/pipeline/steps/references.js.map +1 -1
  174. package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
  175. package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
  176. package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
  177. package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
  178. package/dist/pipeline/steps/visibility-gates.d.ts +27 -0
  179. package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -0
  180. package/dist/pipeline/steps/visibility-gates.js +139 -0
  181. package/dist/pipeline/steps/visibility-gates.js.map +1 -0
  182. package/dist/query/search/controller.js +1 -0
  183. package/dist/query/search/controller.js.map +1 -1
  184. package/dist/query/search/criteria.d.ts +5 -1
  185. package/dist/query/search/criteria.d.ts.map +1 -1
  186. package/dist/query/search/criteria.js +13 -3
  187. package/dist/query/search/criteria.js.map +1 -1
  188. package/dist/query/search/handler.d.ts +4 -5
  189. package/dist/query/search/handler.d.ts.map +1 -1
  190. package/dist/query/search/handler.js +6 -7
  191. package/dist/query/search/handler.js.map +1 -1
  192. package/dist/query/search/query-store.d.ts.map +1 -1
  193. package/dist/query/search/query-store.js +2 -0
  194. package/dist/query/search/query-store.js.map +1 -1
  195. package/dist/store/interface.d.ts +6 -3
  196. package/dist/store/interface.d.ts.map +1 -1
  197. package/dist/store/interface.js.map +1 -1
  198. package/dist/store/postgres/migrations.d.ts +1 -3
  199. package/dist/store/postgres/migrations.d.ts.map +1 -1
  200. package/dist/store/postgres/migrations.js +1 -35
  201. package/dist/store/postgres/migrations.js.map +1 -1
  202. package/dist/store/postgres/store.d.ts.map +1 -1
  203. package/dist/store/postgres/store.js +9 -4
  204. package/dist/store/postgres/store.js.map +1 -1
  205. package/dist/store/sqlite/migrations.d.ts +1 -3
  206. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  207. package/dist/store/sqlite/migrations.js +1 -36
  208. package/dist/store/sqlite/migrations.js.map +1 -1
  209. package/dist/store/sqlite/store.d.ts.map +1 -1
  210. package/dist/store/sqlite/store.js +8 -4
  211. package/dist/store/sqlite/store.js.map +1 -1
  212. package/package.json +6 -6
  213. package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
  214. package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
  215. package/src/artifactstorage/artifact-storage.ts +37 -33
  216. package/src/artifactstorage/r2-storage.ts +6 -15
  217. package/src/authorization/README.md +26 -24
  218. package/src/authorization/__tests__/authorizer.test.ts +9 -10
  219. package/src/authorization/__tests__/derived-tuples.test.ts +11 -4
  220. package/src/authorization/__tests__/evaluator.test.ts +73 -14
  221. package/src/authorization/__tests__/facts.test.ts +2 -2
  222. package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +185 -0
  223. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +98 -6
  224. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
  225. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +61 -4
  226. package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +143 -0
  227. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +21 -1
  228. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +25 -1
  229. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
  230. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +3 -1
  231. package/src/authorization/__tests__/list-read-scope.test.ts +17 -18
  232. package/src/authorization/__tests__/store-tests.test.ts +8 -1
  233. package/src/authorization/__tests__/tuples.test.ts +11 -12
  234. package/src/authorization/authorizer.ts +9 -4
  235. package/src/authorization/derived-tuples.ts +31 -14
  236. package/src/authorization/evaluator.ts +44 -8
  237. package/src/authorization/list-read-scope.ts +11 -5
  238. package/src/authorization/model/agent.ts +5 -2
  239. package/src/authorization/model/agent_instance.ts +2 -0
  240. package/src/authorization/model/mcp_server.ts +2 -0
  241. package/src/authorization/model/plugin.ts +4 -1
  242. package/src/authorization/model/rewrite.ts +13 -8
  243. package/src/authorization/model/skill.ts +2 -0
  244. package/src/authorization/model/workflow.ts +2 -0
  245. package/src/authorization/model/workflow_instance.ts +2 -0
  246. package/src/authorization/organization-directory.ts +3 -1
  247. package/src/authorization/store-test-kit.ts +75 -16
  248. package/src/authorization/tuples.ts +39 -16
  249. package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
  250. package/src/boot/compose.ts +62 -25
  251. package/src/boot/config.ts +4 -3
  252. package/src/boot/skill-transfer-origin.ts +76 -0
  253. package/src/domain/agent/__tests__/agent.test.ts +4 -11
  254. package/src/domain/agent/controller.ts +7 -7
  255. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +48 -223
  256. package/src/domain/agentchannel/controller.ts +1 -6
  257. package/src/domain/agentexecution/controller.ts +1 -6
  258. package/src/domain/agentinstance/controller.ts +12 -6
  259. package/src/domain/agentshare/__tests__/agentshare.test.ts +172 -196
  260. package/src/domain/agentshare/__tests__/create-authorization.test.ts +31 -16
  261. package/src/domain/agentshare/constants.ts +26 -14
  262. package/src/domain/agentshare/controller.ts +1 -6
  263. package/src/domain/agentshare/steps.ts +194 -41
  264. package/src/domain/environment/controller.ts +8 -5
  265. package/src/domain/executioncontext/controller.ts +1 -5
  266. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +28 -115
  267. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +18 -53
  268. package/src/domain/mcpserver/controller.ts +12 -6
  269. package/src/domain/plugin/controller.ts +23 -18
  270. package/src/domain/plugin/push.ts +16 -8
  271. package/src/domain/schedule/controller.ts +1 -6
  272. package/src/domain/session/controller.ts +4 -12
  273. package/src/domain/skill/__tests__/skill.test.ts +5 -3
  274. package/src/domain/skill/__tests__/slots.test.ts +113 -60
  275. package/src/domain/skill/__tests__/staging.test.ts +304 -0
  276. package/src/domain/skill/constants.ts +28 -3
  277. package/src/domain/skill/controller.ts +51 -35
  278. package/src/domain/skill/push.ts +3 -3
  279. package/src/domain/skill/transfer/handler.ts +33 -15
  280. package/src/domain/skill/transfer/slots.ts +89 -100
  281. package/src/domain/skill/transfer/staging.ts +191 -0
  282. package/src/domain/workflow/controller.ts +10 -28
  283. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  284. package/src/domain/workflow/validation/task-config-constraints.ts +3 -7
  285. package/src/domain/workflowexecution/controller.ts +2 -7
  286. package/src/domain/workflowinstance/controller.ts +12 -6
  287. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +19 -32
  288. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  289. package/src/extensions/__tests__/list-read-scope-composed.test.ts +6 -9
  290. package/src/extensions/authorization-queries.ts +5 -6
  291. package/src/extensions/list-read-scope.ts +1 -1
  292. package/src/extensions/resource-authorization.ts +5 -3
  293. package/src/index.ts +14 -0
  294. package/src/pipeline/apiresource-meta.ts +10 -21
  295. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +31 -18
  296. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +187 -0
  297. package/src/pipeline/steps/authorization-tuples.ts +11 -9
  298. package/src/pipeline/steps/references.ts +70 -578
  299. package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
  300. package/src/pipeline/steps/visibility-gates.ts +174 -0
  301. package/src/query/search/__tests__/criteria.test.ts +4 -0
  302. package/src/query/search/__tests__/query-store.test.ts +40 -11
  303. package/src/query/search/controller.ts +1 -0
  304. package/src/query/search/criteria.ts +14 -0
  305. package/src/query/search/handler.ts +7 -6
  306. package/src/query/search/query-store.ts +2 -0
  307. package/src/store/__tests__/store-contract.ts +51 -6
  308. package/src/store/interface.ts +6 -3
  309. package/src/store/postgres/__tests__/migrations.test.ts +6 -187
  310. package/src/store/postgres/__tests__/store-contract.test.ts +2 -0
  311. package/src/store/postgres/migrations.ts +1 -48
  312. package/src/store/postgres/store.ts +11 -4
  313. package/src/store/sqlite/__tests__/migrations.test.ts +5 -191
  314. package/src/store/sqlite/migrations.ts +1 -45
  315. package/src/store/sqlite/store.ts +10 -4
  316. package/src/transport/registry/__tests__/lanes.test.ts +1 -1
  317. package/dist/domain/workflow/agent-call-references.d.ts +0 -54
  318. package/dist/domain/workflow/agent-call-references.d.ts.map +0 -1
  319. package/dist/domain/workflow/agent-call-references.js +0 -97
  320. package/dist/domain/workflow/agent-call-references.js.map +0 -1
  321. package/dist/store/public-visibility-retired.d.ts +0 -67
  322. package/dist/store/public-visibility-retired.d.ts.map +0 -1
  323. package/dist/store/public-visibility-retired.js +0 -55
  324. package/dist/store/public-visibility-retired.js.map +0 -1
  325. package/src/domain/workflow/__tests__/agent-call-references.test.ts +0 -222
  326. package/src/domain/workflow/agent-call-references.ts +0 -157
  327. package/src/pipeline/__tests__/supports-visibility.test.ts +0 -112
  328. package/src/pipeline/steps/__tests__/references.test.ts +0 -703
  329. package/src/store/__tests__/public-visibility-retired.test.ts +0 -127
  330. package/src/store/public-visibility-retired.ts +0 -119
@@ -41,11 +41,7 @@ import { composeServer } from "../../../boot/compose.js";
41
41
  import type { ComposedServer } from "../../../boot/compose.js";
42
42
  import { createLogger } from "../../../boot/logger.js";
43
43
 
44
- const silentLogger = createLogger({
45
- level: "error",
46
- pretty: false,
47
- write: () => {},
48
- });
44
+ const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
49
45
 
50
46
  const API_VERSION = "agentic.stigmer.ai/v1";
51
47
  const KIND = "McpServer";
@@ -132,11 +128,7 @@ function serverInput(overrides?: {
132
128
  };
133
129
  }
134
130
 
135
- async function expectCode(
136
- promise: Promise<unknown>,
137
- code: Code,
138
- arm: string,
139
- ): Promise<ConnectError> {
131
+ async function expectCode(promise: Promise<unknown>, code: Code, arm: string): Promise<ConnectError> {
140
132
  try {
141
133
  await promise;
142
134
  } catch (error) {
@@ -165,10 +157,7 @@ async function seedCapabilities(
165
157
  serverId,
166
158
  McpServerSchema,
167
159
  );
168
- const patched = fromBinary(
169
- McpServerSchema,
170
- toBinary(McpServerSchema, stored),
171
- );
160
+ const patched = fromBinary(McpServerSchema, toBinary(McpServerSchema, stored));
172
161
  patched.status ??= create(McpServerStatusSchema, {});
173
162
  patched.status.discoveredCapabilities = create(DiscoveredCapabilitiesSchema, {
174
163
  tools: tools.map((name) => ({ name })),
@@ -187,19 +176,13 @@ describe("CRUD", () => {
187
176
  const created = await command.create(serverInput({ name: "GitHub Tools" }));
188
177
  expect(created.metadata?.id).toMatch(/^mcp_[0-9a-z]{26}$/);
189
178
  expect(created.metadata?.slug).toBe("github-tools");
190
- expect(created.metadata?.visibility).toBe(
191
- ApiResourceVisibility.visibility_org,
192
- );
179
+ expect(created.metadata?.visibility).toBe(ApiResourceVisibility.visibility_org);
193
180
  });
194
181
 
195
182
  it("rejects a duplicate create by slug within the org; a different org reuses the slug", async () => {
196
183
  const name = `Dup Target ${++counter}`;
197
184
  await command.create(serverInput({ name }));
198
- await expectCode(
199
- command.create(serverInput({ name })),
200
- Code.AlreadyExists,
201
- "duplicate create",
202
- );
185
+ await expectCode(command.create(serverInput({ name })), Code.AlreadyExists, "duplicate create");
203
186
  const other = await command.create(serverInput({ name, org: "other-org" }));
204
187
  expect(other.metadata?.org).toBe("other-org");
205
188
  });
@@ -218,17 +201,10 @@ describe("CRUD", () => {
218
201
  it("get and getByReference resolve the same resource; unknowns answer NotFound", async () => {
219
202
  const created = await command.create(serverInput());
220
203
  const byId = await query.get({ value: created.metadata!.id });
221
- const byRef = await query.getByReference({
222
- org: ORG,
223
- slug: created.metadata!.slug,
224
- });
204
+ const byRef = await query.getByReference({ org: ORG, slug: created.metadata!.slug });
225
205
  expect(byId.metadata?.id).toBe(created.metadata?.id);
226
206
  expect(byRef.metadata?.id).toBe(created.metadata?.id);
227
- await expectCode(
228
- query.get({ value: "mcps_missing" }),
229
- Code.NotFound,
230
- "get unknown",
231
- );
207
+ await expectCode(query.get({ value: "mcps_missing" }), Code.NotFound, "get unknown");
232
208
  await expectCode(
233
209
  query.getByReference({ org: ORG, slug: "never-created" }),
234
210
  Code.NotFound,
@@ -240,11 +216,7 @@ describe("CRUD", () => {
240
216
  const created = await command.create(serverInput());
241
217
  const deleted = await command.delete({ resourceId: created.metadata!.id });
242
218
  expect(deleted.metadata?.id).toBe(created.metadata?.id);
243
- await expectCode(
244
- query.get({ value: created.metadata!.id }),
245
- Code.NotFound,
246
- "get after delete",
247
- );
219
+ await expectCode(query.get({ value: created.metadata!.id }), Code.NotFound, "get after delete");
248
220
  });
249
221
 
250
222
  it("update of a non-existent server and delete of a non-existent server answer NotFound; delete with an empty id is InvalidArgument", async () => {
@@ -261,11 +233,7 @@ describe("CRUD", () => {
261
233
  Code.NotFound,
262
234
  "delete non-existent",
263
235
  );
264
- await expectCode(
265
- command.delete({}),
266
- Code.InvalidArgument,
267
- "delete empty id",
268
- );
236
+ await expectCode(command.delete({}), Code.InvalidArgument, "delete empty id");
269
237
  });
270
238
  });
271
239
 
@@ -276,17 +244,13 @@ describe("updateVisibility (no conformance coverage for this domain — the D4-d
276
244
  resourceId: created.metadata!.id,
277
245
  visibility: ApiResourceVisibility.visibility_private,
278
246
  });
279
- expect(updated.metadata?.visibility).toBe(
280
- ApiResourceVisibility.visibility_private,
281
- );
247
+ expect(updated.metadata?.visibility).toBe(ApiResourceVisibility.visibility_private);
282
248
  expect(updated.spec?.description).toBe(created.spec?.description);
283
249
  // A visibility change is a STATUS mutation: status_audit re-stamped
284
250
  // (updated event, fresh timestamp bounds are creation-or-later),
285
251
  // spec_audit byte-untouched.
286
252
  expect(updated.status?.audit?.statusAudit?.event).toBe("updated");
287
- expect(updated.status?.audit?.specAudit).toEqual(
288
- created.status?.audit?.specAudit,
289
- );
253
+ expect(updated.status?.audit?.specAudit).toEqual(created.status?.audit?.specAudit);
290
254
  });
291
255
 
292
256
  it("answers NotFound for an unknown id", async () => {
@@ -332,9 +296,7 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
332
296
  it("accepts names the server exposes; skips when the list is empty or the server never connected", async () => {
333
297
  // Never connected: any names pass (no authoritative toolset yet).
334
298
  const fresh = await command.create(serverInput());
335
- const freshUpdate = await command.update(
336
- updateInput(fresh, ["anything-goes"]),
337
- );
299
+ const freshUpdate = await command.update(updateInput(fresh, ["anything-goes"]));
338
300
  expect(freshUpdate.spec?.defaultEnabledTools).toEqual(["anything-goes"]);
339
301
 
340
302
  // Connected: valid names pass.
@@ -346,11 +308,7 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
346
308
 
347
309
  it("rejects unknown tools and resource templates with the byte-pinned teaching copy", async () => {
348
310
  const created = await command.create(serverInput());
349
- await seedCapabilities(
350
- created.metadata!.id,
351
- ["search", "fetch"],
352
- ["files"],
353
- );
311
+ await seedCapabilities(created.metadata!.id, ["search", "fetch"], ["files"]);
354
312
 
355
313
  const err = await expectCode(
356
314
  command.update(updateInput(created, ["serch", "files"])),
@@ -376,10 +334,7 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
376
334
  OAuthAppSchema,
377
335
  create(OAuthAppSchema, {
378
336
  metadata: { id, org: ORG, slug, name: slug },
379
- spec: {
380
- vendorApprovalStatus: approval,
381
- vendorApprovalDocsUrl: docsUrl,
382
- },
337
+ spec: { vendorApprovalStatus: approval, vendorApprovalDocsUrl: docsUrl },
383
338
  }),
384
339
  );
385
340
  }
@@ -391,25 +346,14 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
391
346
  });
392
347
 
393
348
  it("a missing OAuthApp skips enrichment (the initiate path owns refusing)", async () => {
394
- // The app must exist when the server is written (the reference rule);
395
- // a reference dangles when its target leaves afterwards.
396
- await seedOAuthApp("never-applied", VendorApprovalStatus.UNSPECIFIED, "");
397
- const created = await command.create(
398
- serverInput({ oauthAppSlug: "never-applied" }),
399
- );
400
- await server.store.deleteResource(
401
- ApiResourceKind.oauth_app,
402
- "oaa_neverapplied",
403
- );
349
+ const created = await command.create(serverInput({ oauthAppSlug: "never-applied" }));
404
350
  const got = await query.get({ value: created.metadata!.id });
405
351
  expect(got.status?.oauthStatus).toBeUndefined();
406
352
  });
407
353
 
408
354
  it("nothing-to-report means ABSENT — presence itself is the SDK's signal", async () => {
409
355
  await seedOAuthApp("plain-app", VendorApprovalStatus.UNSPECIFIED, "");
410
- const created = await command.create(
411
- serverInput({ oauthAppSlug: "plain-app" }),
412
- );
356
+ const created = await command.create(serverInput({ oauthAppSlug: "plain-app" }));
413
357
  const got = await query.get({ value: created.metadata!.id });
414
358
  expect(got.status?.oauthStatus).toBeUndefined();
415
359
  });
@@ -419,42 +363,24 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
419
363
  // alone must enrich (Go enrich_oauth_status_test.go's docs-only and
420
364
  // status-only arms — the executable spec of the #523 shared contract).
421
365
  it("a docs URL ALONE enriches, even with an UNSPECIFIED approval status", async () => {
422
- await seedOAuthApp(
423
- "docs-only-app",
424
- VendorApprovalStatus.UNSPECIFIED,
425
- "https://vendor.example/setup",
426
- );
427
- const created = await command.create(
428
- serverInput({ oauthAppSlug: "docs-only-app" }),
429
- );
366
+ await seedOAuthApp("docs-only-app", VendorApprovalStatus.UNSPECIFIED, "https://vendor.example/setup");
367
+ const created = await command.create(serverInput({ oauthAppSlug: "docs-only-app" }));
430
368
  const got = await query.get({ value: created.metadata!.id });
431
- expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(
432
- VendorApprovalStatus.UNSPECIFIED,
433
- );
434
- expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe(
435
- "https://vendor.example/setup",
436
- );
369
+ expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.UNSPECIFIED);
370
+ expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("https://vendor.example/setup");
437
371
  });
438
372
 
439
373
  it("a non-default approval status ALONE enriches — REJECTED and even APPROVED are reported", async () => {
440
374
  await seedOAuthApp("rejected-app", VendorApprovalStatus.REJECTED, "");
441
- const rejected = await command.create(
442
- serverInput({ oauthAppSlug: "rejected-app" }),
443
- );
375
+ const rejected = await command.create(serverInput({ oauthAppSlug: "rejected-app" }));
444
376
  const gotRejected = await query.get({ value: rejected.metadata!.id });
445
- expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(
446
- VendorApprovalStatus.REJECTED,
447
- );
377
+ expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.REJECTED);
448
378
  expect(gotRejected.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("");
449
379
 
450
380
  await seedOAuthApp("approved-app", VendorApprovalStatus.APPROVED, "");
451
- const approved = await command.create(
452
- serverInput({ oauthAppSlug: "approved-app" }),
453
- );
381
+ const approved = await command.create(serverInput({ oauthAppSlug: "approved-app" }));
454
382
  const gotApproved = await query.get({ value: approved.metadata!.id });
455
- expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(
456
- VendorApprovalStatus.APPROVED,
457
- );
383
+ expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.APPROVED);
458
384
  });
459
385
 
460
386
  it("an auth block WITHOUT an oauth_app_ref (the DCR arm) is untouched", async () => {
@@ -465,14 +391,8 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
465
391
  });
466
392
 
467
393
  it("a gating approval status or docs URL enriches BOTH read paths, response-only", async () => {
468
- await seedOAuthApp(
469
- "gated-app",
470
- VendorApprovalStatus.PENDING,
471
- "https://vendor.example/approval",
472
- );
473
- const created = await command.create(
474
- serverInput({ oauthAppSlug: "gated-app" }),
475
- );
394
+ await seedOAuthApp("gated-app", VendorApprovalStatus.PENDING, "https://vendor.example/approval");
395
+ const created = await command.create(serverInput({ oauthAppSlug: "gated-app" }));
476
396
 
477
397
  for (const loaded of [
478
398
  await query.get({ value: created.metadata!.id }),
@@ -510,12 +430,7 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
510
430
  expect(getErr.rawMessage).toBe("method GetOrgOAuthApp not implemented");
511
431
 
512
432
  const setErr = await expectCode(
513
- command.setOrgOAuthApp({
514
- resourceId: "mcps_test",
515
- org: ORG,
516
- clientId: "x",
517
- clientSecret: "y",
518
- }),
433
+ command.setOrgOAuthApp({ resourceId: "mcps_test", org: ORG, clientId: "x", clientSecret: "y" }),
519
434
  Code.Unimplemented,
520
435
  "setOrgOAuthApp",
521
436
  );
@@ -526,8 +441,6 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
526
441
  Code.Unimplemented,
527
442
  "deleteOrgOAuthApp",
528
443
  );
529
- expect(deleteErr.rawMessage).toBe(
530
- "method DeleteOrgOAuthApp not implemented",
531
- );
444
+ expect(deleteErr.rawMessage).toBe("method DeleteOrgOAuthApp not implemented");
532
445
  });
533
446
  });
@@ -41,11 +41,7 @@ import { composeServer } from "../../../boot/compose.js";
41
41
  import type { ComposedServer } from "../../../boot/compose.js";
42
42
  import { createLogger } from "../../../boot/logger.js";
43
43
 
44
- const silentLogger = createLogger({
45
- level: "error",
46
- pretty: false,
47
- write: () => {},
48
- });
44
+ const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
49
45
 
50
46
  const REDIRECT_URI = "http://127.0.0.1:8234/auth/oauth/callback";
51
47
  const ORG = "acme";
@@ -372,30 +368,20 @@ describe("initiateOAuthConnect", () => {
372
368
  "OAuth sign-in is unavailable: the platform's OAuth app for 'exampleco' is pending approval by the vendor. This server only accepts OAuth sign-in; an org admin can configure your own OAuth app instead.",
373
369
  ],
374
370
  ];
375
- it.each(refusals)(
376
- "vendor arm refuses %s",
377
- async (_label, status, oauthOnly, copy) => {
378
- const slug = `vendor-${status}-${oauthOnly ? "only" : "manual"}`;
379
- await seedOAuthApp(slug, status);
380
- const id = await applyServer({ vendorSlug: slug, oauthOnly });
381
- const error = await expectCode(
382
- command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
383
- Code.FailedPrecondition,
384
- copy,
385
- );
386
- expect(error.rawMessage).toBe(copy);
387
- },
388
- );
371
+ it.each(refusals)("vendor arm refuses %s", async (_label, status, oauthOnly, copy) => {
372
+ const slug = `vendor-${status}-${oauthOnly ? "only" : "manual"}`;
373
+ await seedOAuthApp(slug, status);
374
+ const id = await applyServer({ vendorSlug: slug, oauthOnly });
375
+ const error = await expectCode(
376
+ command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
377
+ Code.FailedPrecondition,
378
+ copy,
379
+ );
380
+ expect(error.rawMessage).toBe(copy);
381
+ });
389
382
 
390
383
  it("vendor arm answers NotFound for an unresolvable oauth_app_ref", async () => {
391
- // The app must exist when the server is written (the reference rule);
392
- // the reference becomes unresolvable when its target leaves afterwards.
393
- await seedOAuthApp("no-such-app", VendorApprovalStatus.APPROVED);
394
384
  const id = await applyServer({ vendorSlug: "no-such-app" });
395
- await server.store.deleteResource(
396
- ApiResourceKind.oauth_app,
397
- "oap_no-such-app",
398
- );
399
385
  await expectCode(
400
386
  command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
401
387
  Code.NotFound,
@@ -420,29 +406,17 @@ describe("initiateOAuthConnect", () => {
420
406
  describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", () => {
421
407
  it("guards its inputs (proto rules answer first, exactly as on Go)", async () => {
422
408
  await expectCode(
423
- command.completeOAuthConnect({
424
- mcpServerId: "",
425
- state: "s",
426
- authorizationCode: "c",
427
- }),
409
+ command.completeOAuthConnect({ mcpServerId: "", state: "s", authorizationCode: "c" }),
428
410
  Code.InvalidArgument,
429
411
  "mcp_server_id: value is required [required]",
430
412
  );
431
413
  await expectCode(
432
- command.completeOAuthConnect({
433
- mcpServerId: "m",
434
- state: "",
435
- authorizationCode: "c",
436
- }),
414
+ command.completeOAuthConnect({ mcpServerId: "m", state: "", authorizationCode: "c" }),
437
415
  Code.InvalidArgument,
438
416
  "state:",
439
417
  );
440
418
  await expectCode(
441
- command.completeOAuthConnect({
442
- mcpServerId: "m",
443
- state: "s",
444
- authorizationCode: "",
445
- }),
419
+ command.completeOAuthConnect({ mcpServerId: "m", state: "s", authorizationCode: "" }),
446
420
  Code.InvalidArgument,
447
421
  "authorization_code:",
448
422
  );
@@ -526,10 +500,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
526
500
 
527
501
  // The grant is queryable and HEALTHY; the refresh-token env var is
528
502
  // stamped unconditionally (oss#863's precondition, ported as-is).
529
- const status = await query.getOAuthGrantStatus({
530
- resourceId: id,
531
- org: ORG,
532
- });
503
+ const status = await query.getOAuthGrantStatus({ resourceId: id, org: ORG });
533
504
  expect(status.connected).toBe(true);
534
505
  expect(status.targetEnvVar).toBe("EXAMPLE_TOKEN");
535
506
  expect(status.authMethod).toBe("mcp_oauth");
@@ -543,10 +514,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
543
514
  expect(firstEnvId).not.toBe("");
544
515
 
545
516
  // Re-connect reuses the managed environment.
546
- const again = await command.initiateOAuthConnect({
547
- mcpServerId: id,
548
- org: ORG,
549
- });
517
+ const again = await command.initiateOAuthConnect({ mcpServerId: id, org: ORG });
550
518
  await command.completeOAuthConnect({
551
519
  mcpServerId: id,
552
520
  state: again.state,
@@ -557,10 +525,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
557
525
 
558
526
  // Disconnect tears down grant + environment; a second disconnect is
559
527
  // the idempotent no-grant arm.
560
- const disconnected = await command.disconnectOAuth({
561
- resourceId: id,
562
- org: ORG,
563
- });
528
+ const disconnected = await command.disconnectOAuth({ resourceId: id, org: ORG });
564
529
  expect(disconnected.disconnected).toBe(true);
565
530
  expect(await server.store.oauthGrants.find("", id, ORG)).toBeUndefined();
566
531
  const againDisconnected = await command.disconnectOAuth({
@@ -58,6 +58,10 @@ import {
58
58
  newAuthorizeResolvedTargetStep,
59
59
  } from "../../pipeline/steps/authorize-resolved-target.js";
60
60
  import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
61
+ import {
62
+ newAuthorizeVisibilityTransitionStep,
63
+ newGuardPublicVisibilityStep,
64
+ } from "../../pipeline/steps/visibility-gates.js";
61
65
  import {
62
66
  setAuditFieldsForUpdate,
63
67
  newBuildNewStateStep,
@@ -88,10 +92,7 @@ import {
88
92
  TARGET_RESOURCE_KEY,
89
93
  newLoadTargetStep,
90
94
  } from "../../pipeline/steps/load-target.js";
91
- import {
92
- newNormalizeReferencesStep,
93
- newValidateReferencesStep,
94
- } from "../../pipeline/steps/references.js";
95
+ import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
95
96
  import {
96
97
  newCleanupIamPoliciesStep,
97
98
  newCreateAuthorizationTuplesStep,
@@ -240,13 +241,13 @@ async function createMcpServer(
240
241
  .addStep(newResolveSlugStep())
241
242
  .addStep(newCheckDuplicateStep(deps.store))
242
243
  .addStep(newBuildNewStateStep())
244
+ .addStep(newGuardPublicVisibilityStep(deps.authorizer))
243
245
  // A URL-only server is asked once whether it wants OAuth and completed
244
246
  // when it does; immediately before GuardReservedLabels because the
245
247
  // provenance label it stamps is one the guard diffs.
246
248
  .addStep(newCompleteEndpointAuthStep(endpointAuthDeps(deps)))
247
249
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
248
250
  .addStep(newNormalizeReferencesStep())
249
- .addStep(newValidateReferencesStep(deps.store))
250
251
  .addStep(newPersistStep(deps.store))
251
252
  .addStep(
252
253
  newCreateAuthorizationTuplesStep(
@@ -299,7 +300,6 @@ async function update(
299
300
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
300
301
  .addStep(newValidateDefaultEnabledToolsStep())
301
302
  .addStep(newNormalizeReferencesStep())
302
- .addStep(newValidateReferencesStep(deps.store))
303
303
  .addStep(newPersistStep(deps.store))
304
304
  .addStep(
305
305
  newIndexSearchStep(deps.store, mcpServerSearchExtractor, deps.logger),
@@ -463,6 +463,12 @@ async function updateVisibility(
463
463
  newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_MCP_SERVER_KEY),
464
464
  )
465
465
  .addStep(newValidateVisibilityUpdateStep())
466
+ .addStep(
467
+ newAuthorizeVisibilityTransitionStep(
468
+ UPDATE_VISIBILITY_MCP_SERVER_KEY,
469
+ deps.authorizer,
470
+ ),
471
+ )
466
472
  .addStep(newSetMcpServerVisibilityStep())
467
473
  .addStep(newPersistMcpServerForVisibilityUpdateStep(deps.store))
468
474
  .addStep(
@@ -103,10 +103,13 @@ import {
103
103
  newAuthorizeResolvedTargetStep,
104
104
  } from "../../pipeline/steps/authorize-resolved-target.js";
105
105
  import type { VersionHistoryBinding } from "../../pipeline/steps/version-history.js";
106
+ import { newAuthorizeVisibilityTransitionStep } from "../../pipeline/steps/visibility-gates.js";
106
107
  import { metadataOf } from "../../pipeline/steps/shapes.js";
107
108
  import type { Store } from "../../store/interface.js";
108
- import { uploadUrl } from "../skill/transfer/handler.js";
109
- import type { UploadSlots } from "../skill/transfer/slots.js";
109
+ import type {
110
+ ArchiveStaging,
111
+ StagedUpload,
112
+ } from "../skill/transfer/staging.js";
110
113
  import { TRANSFER_LANE_NOT_CONFIGURED } from "./constants.js";
111
114
  import type { PluginMaterializerProvider } from "./materialize/ports.js";
112
115
  import { findMembers } from "./members.js";
@@ -139,12 +142,6 @@ import {
139
142
  } from "./push.js";
140
143
  import { pluginSearchExtractor } from "./search-extractor.js";
141
144
 
142
- /** The transfer lane's controller-side pair; the slots are the skill lane's (one upload surface). */
143
- export interface PluginTransferLaneDeps {
144
- readonly slots: UploadSlots;
145
- readonly baseUrl: string;
146
- }
147
-
148
145
  export interface PluginControllerDeps {
149
146
  readonly store: Store;
150
147
  readonly logger: Logger;
@@ -152,7 +149,8 @@ export interface PluginControllerDeps {
152
149
  readonly authorizationLifecycle: ResourceAuthorizationLifecycle | undefined;
153
150
  readonly artifactStorage: ContentAddressedArchiveStore;
154
151
  readonly materializerProvider: PluginMaterializerProvider;
155
- readonly transferLane?: PluginTransferLaneDeps;
152
+ /** The skill lane's staging port (one upload surface for every archive); absent, the lane answers FailedPrecondition. */
153
+ readonly staging?: ArchiveStaging;
156
154
  }
157
155
 
158
156
  /** Registers both plugin services on the router (routes stage). */
@@ -207,7 +205,7 @@ async function push(
207
205
  .addStep(newValidateProtoStep())
208
206
  .addStep(
209
207
  newResolveArtifactSourceStep<typeof PushPluginRequestSchema>(
210
- deps.transferLane?.slots,
208
+ deps.staging,
211
209
  {
212
210
  source: (input) => ({
213
211
  artifact: input.artifact,
@@ -225,7 +223,7 @@ async function push(
225
223
  .addStep(newParseOverlayDocumentsStep())
226
224
  .addStep(newSanitizePluginMetadataStep(deps.authorizer))
227
225
  .addStep(newPlanMaterializationStep(deps.store, deps.authorizer))
228
- .addStep(newGuardPluginVisibilityStep())
226
+ .addStep(newGuardPluginVisibilityStep(deps.authorizer))
229
227
  .addStep(newResolveConvergenceStep())
230
228
  .build()
231
229
  .execute(reqCtx);
@@ -273,16 +271,17 @@ async function push(
273
271
  // ─── createArtifactUploadUrl ─────────────────────────────────────────────
274
272
 
275
273
  /**
276
- * Mints a short-lived, single-use upload URL over the shared slots; an
277
- * over-limit declaration is refused with the limit BEFORE any bytes move.
274
+ * Mints a short-lived, single-use upload URL through the shared staging
275
+ * port; an over-limit declaration is refused with the limit BEFORE any
276
+ * bytes move.
278
277
  */
279
278
  async function createArtifactUploadUrl(
280
279
  deps: PluginControllerDeps,
281
280
  req: CreatePluginArtifactUploadUrlRequest,
282
281
  ctx: HandlerContext,
283
282
  ): Promise<PluginArtifactUploadUrl> {
284
- const lane = deps.transferLane;
285
- if (lane === undefined) {
283
+ const staging = deps.staging;
284
+ if (staging === undefined) {
286
285
  throw failedPreconditionError(TRANSFER_LANE_NOT_CONFIGURED);
287
286
  }
288
287
  const reqCtx = new RequestContext(
@@ -309,14 +308,14 @@ async function createArtifactUploadUrl(
309
308
  `plugin archive size ${req.sizeBytes} bytes exceeds the ${MAX_ZIP_SIZE}-byte (100MB) archive limit`,
310
309
  );
311
310
  }
312
- let minted: { ref: string; ttlMs: number };
311
+ let minted: StagedUpload;
313
312
  try {
314
- minted = lane.slots.mint(Number(req.sizeBytes));
313
+ minted = await staging.mint(Number(req.sizeBytes));
315
314
  } catch (error) {
316
315
  throw internalError(error, "failed to mint upload reference");
317
316
  }
318
317
  return create(PluginArtifactUploadUrlSchema, {
319
- url: uploadUrl(lane.baseUrl, minted.ref),
318
+ url: minted.url,
320
319
  artifactUploadRef: minted.ref,
321
320
  ttlSeconds: Math.trunc(minted.ttlMs / 1000),
322
321
  });
@@ -358,6 +357,12 @@ async function updateVisibility(
358
357
  .addStep(newLoadPluginByIdStep(deps.store, UPDATE_VISIBILITY_PLUGIN_KEY))
359
358
  .addStep(newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_PLUGIN_KEY))
360
359
  .addStep(newValidateVisibilityUpdateStep())
360
+ .addStep(
361
+ newAuthorizeVisibilityTransitionStep(
362
+ UPDATE_VISIBILITY_PLUGIN_KEY,
363
+ deps.authorizer,
364
+ ),
365
+ )
361
366
  .addStep(newSetPluginVisibilityStep())
362
367
  .addStep(
363
368
  newPersistPluginStep(
@@ -94,6 +94,7 @@ import { ARTIFACT_BYTES_KEY } from "../../pipeline/steps/resolve-artifact-source
94
94
  import { generateSlug } from "../../pipeline/steps/slug.js";
95
95
  import { rejectUnsupportedVisibility } from "../../pipeline/steps/validate-visibility.js";
96
96
  import { newArchiveCurrentVersionStep } from "../../pipeline/steps/version-archive.js";
97
+ import { requireOperatorMaySetPublic } from "../../pipeline/steps/visibility-gates.js";
97
98
  import { ResourceNotFoundError } from "../../store/interface.js";
98
99
  import type { Store } from "../../store/interface.js";
99
100
  import { openPluginArchive } from "./archive.js";
@@ -492,23 +493,30 @@ export function newPlanMaterializationStep(
492
493
 
493
494
  /**
494
495
  * GuardPluginVisibility — the requested level must be one the plugin and
495
- * every planned member kind support: the push chain's counterpart of the
496
- * ValidateVisibility step on the resource create chains, asked here for
497
- * the head and for each member kind before anything is written, so a
498
- * plugin cannot be installed at a level one of its members may not hold.
499
- * Each member's own chain checks again in-process; refusing here keeps the
500
- * head from being written before the answer is known.
496
+ * every planned member kind support, and PUBLIC needs the operator grant
497
+ * (the one owner of that question, shared with every other create door).
498
+ * Each member's own chain will check again in-process; refusing here keeps
499
+ * the head from being written before the answer is known.
501
500
  */
502
- export function newGuardPluginVisibilityStep(): PipelineStep<PushDesc> {
501
+ export function newGuardPluginVisibilityStep(
502
+ authorizer: Authorizer,
503
+ ): PipelineStep<PushDesc> {
503
504
  return {
504
505
  name: "GuardPluginVisibility",
505
- execute(ctx: RequestContext<PushDesc>): void {
506
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
506
507
  const level = requestedVisibility(ctx);
507
508
  const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
508
509
  rejectUnsupportedVisibility(ctx.apiResourceKind, level);
509
510
  for (const kind of new Set(plan.members.map((member) => member.kind))) {
510
511
  rejectUnsupportedVisibility(kind, level);
511
512
  }
513
+ if (level !== ApiResourceVisibility.visibility_public) {
514
+ return;
515
+ }
516
+ if (ctx.callerIdentity.callerClass === "internal") {
517
+ return;
518
+ }
519
+ await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
512
520
  },
513
521
  };
514
522
  }
@@ -97,10 +97,7 @@ import {
97
97
  newCreateAuthorizationTuplesStep,
98
98
  } from "../../pipeline/steps/authorization-tuples.js";
99
99
  import { newPersistStep } from "../../pipeline/steps/persist.js";
100
- import {
101
- newNormalizeReferencesStep,
102
- newValidateReferencesStep,
103
- } from "../../pipeline/steps/references.js";
100
+ import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
104
101
  import { newResolveSlugStep } from "../../pipeline/steps/slug.js";
105
102
  import { newValidateProtoStep } from "../../pipeline/steps/validation.js";
106
103
  import { newValidateVisibilityStep } from "../../pipeline/steps/validate-visibility.js";
@@ -223,7 +220,6 @@ async function createSchedule(
223
220
  .addStep(newBuildNewStateStep())
224
221
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
225
222
  .addStep(newNormalizeReferencesStep())
226
- .addStep(newValidateReferencesStep(deps.store))
227
223
  .addStep(newPersistStep(deps.store))
228
224
  .addStep(
229
225
  newCreateAuthorizationTuplesStep(
@@ -263,7 +259,6 @@ async function update(
263
259
  .addStep(newBuildUpdateStateStep())
264
260
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
265
261
  .addStep(newNormalizeReferencesStep())
266
- .addStep(newValidateReferencesStep(deps.store))
267
262
  .addStep(newPersistScheduleUpdateStep(deps.store))
268
263
  .addStep(newArmScheduleStep(deps.clock, deps.logger))
269
264
  .build()