update axum

This commit is contained in:
Ruben Fiszel
2023-01-11 07:08:58 +01:00
parent b4e9468461
commit c0df9a5e20
13 changed files with 126 additions and 101 deletions
+21 -18
View File
@@ -2706,7 +2706,7 @@ paths:
schema:
$ref: "#/components/schemas/AppWithLastVersion"
/w/{workspace}/apps/public_app/{path}:
/w/{workspace}/apps_u/public_app/{path}:
get:
summary: get public app by secret
operationId: getPublicAppBySecret
@@ -2843,7 +2843,7 @@ paths:
schema:
type: string
/w/{workspace}/apps/execute_component/{path}:
/w/{workspace}/apps_u/execute_component/{path}:
post:
summary: executeComponent
operationId: executeComponent
@@ -3151,7 +3151,7 @@ paths:
items:
$ref: "#/components/schemas/Job"
/w/{workspace}/jobs/get/{id}:
/w/{workspace}/jobs_u/get/{id}:
get:
summary: get job
operationId: getJob
@@ -3185,7 +3185,7 @@ paths:
# schema:
# type: string
/w/{workspace}/jobs/getupdate/{id}:
/w/{workspace}/jobs_u/getupdate/{id}:
get:
summary: get job updates
operationId: getJobUpdates
@@ -3343,7 +3343,7 @@ paths:
- resume
- cancel
/w/{workspace}/jobs/resume/{id}/{resume_id}/{signature}:
/w/{workspace}/jobs_u/resume/{id}/{resume_id}/{signature}:
get:
summary: resume a job for a suspended flow
operationId: resumeSuspendedJobGet
@@ -3433,7 +3433,7 @@ paths:
schema:
type: string
/w/{workspace}/jobs/cancel/{id}/{resume_id}/{signature}:
/w/{workspace}/jobs_u/cancel/{id}/{resume_id}/{signature}:
get:
summary: cancel a job for a suspended flow
operationId: cancelSuspendedJobGet
@@ -3500,7 +3500,7 @@ paths:
schema:
type: string
/w/{workspace}/jobs/get_flow/{id}/{resume_id}/{signature}:
/w/{workspace}/jobs_u/get_flow/{id}/{resume_id}/{signature}:
get:
summary: get parent flow job of suspended job
operationId: getSuspendedJobFlow
@@ -4265,6 +4265,20 @@ paths:
schema:
type: string
/w/{workspace}/capture_u/{path}:
post:
summary: update flow preview capture
operationId: updateCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"204":
description: flow preview captured
/w/{workspace}/capture/{path}:
put:
summary: create flow preview capture
@@ -4277,17 +4291,6 @@ paths:
responses:
"201":
description: flow preview capture created
post:
summary: update flow preview capture
operationId: updateCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"204":
description: flow preview captured
get:
summary: get flow preview capture
operationId: getCapture
+4 -4
View File
@@ -14,9 +14,9 @@ use crate::{
variables::build_crypt,
};
use axum::{
extract::{Extension, Path, Query},
extract::{Extension, Json, Path, Query},
routing::{delete, get, post},
Json, Router,
Router,
};
use hyper::StatusCode;
use magic_crypt::MagicCryptTrait;
@@ -137,10 +137,10 @@ pub struct EditApp {
async fn list_apps(
authed: Authed,
Query(pagination): Query<Pagination>,
Query(lq): Query<ListAppQuery>,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Query(pagination): Query<Pagination>,
Query(lq): Query<ListAppQuery>,
) -> JsonResult<Vec<ListableApp>> {
let (per_page, offset) = paginate(pagination);
+22 -20
View File
@@ -10,13 +10,14 @@ use std::sync::Arc;
use anyhow::Context;
use axum::{
extract::{FromRequest, Path, Query},
extract::{FromRequest, Json, Path, Query},
response::{IntoResponse, Response},
routing::{get, post},
Extension, Json, Router,
Extension, Router,
};
use base64::Engine;
use hmac::Mac;
use hyper::{HeaderMap, StatusCode};
use hyper::{HeaderMap, Request, StatusCode};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sql_builder::{prelude::*, quote, SqlBuilder};
use sqlx::{query_scalar, types::Uuid, FromRow, Postgres, Transaction};
@@ -552,8 +553,8 @@ pub async fn resume_suspended_job(
/* unauthed */
Extension(db): Extension<DB>,
Path((w_id, job_id, resume_id, secret)): Path<(String, Uuid, u32, String)>,
QueryOrBody(value): QueryOrBody<serde_json::Value>,
Query(approver): Query<QueryApprover>,
QueryOrBody(value): QueryOrBody<serde_json::Value>,
) -> error::Result<StatusCode> {
let value = value.unwrap_or(serde_json::Value::Null);
let mut tx = db.begin().await?;
@@ -896,7 +897,7 @@ fn build_resume_url(
approver: &str,
base_url: &str,
) -> String {
format!("{base_url}/api/w/{w_id}/jobs/{op}/{job_id}/{resume_id}/{signature}{approver}")
format!("{base_url}/api/w/{w_id}/jobs_u/{op}/{job_id}/{resume_id}/{signature}{approver}")
}
pub async fn get_resume_urls(
@@ -1075,20 +1076,19 @@ struct PreviewFlow {
pub struct QueryOrBody<D>(pub Option<D>);
#[axum::async_trait]
impl<D, B> FromRequest<B> for QueryOrBody<D>
impl<S, D> FromRequest<S, axum::body::Body> for QueryOrBody<D>
where
D: DeserializeOwned,
B: Send + axum::body::HttpBody,
<B as axum::body::HttpBody>::Data: Send,
<B as axum::body::HttpBody>::Error: Into<axum::BoxError>,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(
req: &mut axum::extract::RequestParts<B>,
req: Request<axum::body::Body>,
state: &S,
) -> std::result::Result<Self, Self::Rejection> {
return if req.method() == axum::http::Method::GET {
let Query(InPayload { payload }) = Query::from_request(req)
let Query(InPayload { payload }) = Query::from_request(req, state)
.await
.map_err(IntoResponse::into_response)?;
payload
@@ -1100,7 +1100,7 @@ where
})
.unwrap_or(Ok(QueryOrBody(None)))
} else {
Json::from_request(req)
Json::from_request(req, state)
.await
.map(|Json(v)| QueryOrBody(Some(v)))
.map_err(IntoResponse::into_response)
@@ -1112,7 +1112,9 @@ where
}
fn decode_payload<D: DeserializeOwned, T: AsRef<[u8]>>(t: T) -> anyhow::Result<D> {
let vec = base64::decode_config(&t, base64::URL_SAFE).context("invalid base64")?;
let vec = base64::engine::general_purpose::URL_SAFE
.decode(t)
.context("invalid base64")?;
serde_json::from_slice(vec.as_slice()).context("invalid json")
}
}
@@ -1121,9 +1123,9 @@ pub async fn run_flow_by_path(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path((w_id, flow_path)): Path<(String, StripPath)>,
axum::Json(args): axum::Json<Option<serde_json::Map<String, serde_json::Value>>>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
) -> error::Result<(StatusCode, String)> {
let flow_path = flow_path.to_path();
let mut tx = user_db.begin(&authed).await?;
@@ -1155,9 +1157,9 @@ pub async fn run_job_by_path(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path((w_id, script_path)): Path<(String, StripPath)>,
axum::Json(args): axum::Json<Option<serde_json::Map<String, serde_json::Value>>>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
) -> error::Result<(StatusCode, String)> {
let script_path = script_path.to_path();
let mut tx = user_db.begin(&authed).await?;
@@ -1222,9 +1224,9 @@ pub async fn run_wait_result_job_by_path(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path((w_id, script_path)): Path<(String, StripPath)>,
axum::Json(args): axum::Json<Option<serde_json::Map<String, serde_json::Value>>>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
) -> error::JsonResult<serde_json::Value> {
let script_path = script_path.to_path();
let mut tx = user_db.clone().begin(&authed).await?;
@@ -1259,9 +1261,9 @@ pub async fn run_wait_result_job_by_hash(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path((w_id, script_hash)): Path<(String, ScriptHash)>,
axum::Json(args): axum::Json<Option<serde_json::Map<String, serde_json::Value>>>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
) -> error::JsonResult<serde_json::Value> {
let hash = script_hash.0;
let mut tx = user_db.clone().begin(&authed).await?;
@@ -1310,9 +1312,9 @@ async fn run_preview_job(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Json(preview): Json<Preview>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(preview): Json<Preview>,
) -> error::Result<(StatusCode, String)> {
let mut tx = user_db.begin(&authed).await?;
let scheduled_for = run_query.get_scheduled_for(&mut tx).await?;
@@ -1348,9 +1350,9 @@ async fn run_preview_flow_job(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Json(raw_flow): Json<PreviewFlow>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(raw_flow): Json<PreviewFlow>,
) -> error::Result<(StatusCode, String)> {
let mut tx = user_db.begin(&authed).await?;
let scheduled_for = run_query.get_scheduled_for(&mut tx).await?;
@@ -1381,9 +1383,9 @@ pub async fn run_job_by_hash(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Path((w_id, script_hash)): Path<(String, ScriptHash)>,
axum::Json(args): axum::Json<Option<serde_json::Map<String, serde_json::Value>>>,
Query(run_query): Query<RunJobQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
) -> error::Result<(StatusCode, String)> {
let hash = script_hash.0;
let mut tx = user_db.begin(&authed).await?;
+6 -6
View File
@@ -7,7 +7,7 @@
*/
use argon2::Argon2;
use axum::{handler::Handler, middleware::from_extractor, routing::get, Extension, Router};
use axum::{middleware::from_extractor, routing::get, Extension, Router};
use db::DB;
use git_version::git_version;
use std::{net::SocketAddr, sync::Arc};
@@ -127,9 +127,9 @@ pub async fn run_server(
.nest("/audit", audit::workspaced_service())
.nest("/acls", granular_acls::workspaced_service())
.nest("/workspaces", workspaces::workspaced_service())
.nest("/apps", apps::workspaced_service())
.nest("/flows", flows::workspaced_service())
.nest("/capture", capture::workspaced_service())
.nest("/apps", apps::workspaced_service())
.nest("/favorites", favorite::workspaced_service())
.nest("/folders", folders::workspaced_service()),
)
@@ -146,11 +146,11 @@ pub async fn run_server(
.route_layer(from_extractor::<Authed>())
.route_layer(from_extractor::<users::Tokened>())
.nest(
"/w/:workspace_id/apps",
"/w/:workspace_id/apps_u",
apps::unauthed_service().layer(from_extractor::<OptAuthed>()),
)
.nest("/w/:workspace_id/jobs", jobs::global_service())
.nest("/w/:workspace_id/capture", capture::global_service())
.nest("/w/:workspace_id/jobs_u", jobs::global_service())
.nest("/w/:workspace_id/capture_u", capture::global_service())
.nest(
"/auth",
users::make_unauthed_service().layer(Extension(argon2)),
@@ -162,7 +162,7 @@ pub async fn run_server(
.route("/version", get(git_v))
.route("/openapi.yaml", get(openapi)),
)
.fallback(static_assets::static_handler.into_service())
.fallback(static_assets::static_handler)
.layer(middleware_stack);
let instance_name = rd_string(5);
+14 -9
View File
@@ -11,10 +11,12 @@ use std::{collections::HashMap, fmt::Debug};
use std::sync::Arc;
use anyhow::Context;
use axum::extract::FromRequestParts;
use axum::http::request::Parts;
use axum::{
async_trait,
body::Bytes,
extract::{Extension, FromRequest, Path, Query, RequestParts},
extract::{Extension, Path, Query},
response::Redirect,
routing::{get, post},
Json, Router,
@@ -485,10 +487,10 @@ struct VariablePath {
async fn refresh_token(
authed: Authed,
Path((w_id, id)): Path<(String, i32)>,
Json(VariablePath { path }): Json<VariablePath>,
Extension(user_db): Extension<UserDB>,
Extension(clients): Extension<Arc<AllClients>>,
Extension(http_client): Extension<Client>,
Json(VariablePath { path }): Json<VariablePath>,
) -> error::Result<String> {
let tx = user_db.begin(&authed).await?;
@@ -606,9 +608,9 @@ pub struct OAuthCallback {
async fn connect_callback(
cookies: Cookies,
Path(client_name): Path<String>,
Json(callback): Json<OAuthCallback>,
Extension(clients): Extension<Arc<AllClients>>,
Extension(http_client): Extension<Client>,
Json(callback): Json<OAuthCallback>,
) -> error::JsonResult<TokenResponse> {
let client_w_scopes = &clients
.connects
@@ -628,10 +630,10 @@ async fn connect_slack_callback(
Path(w_id): Path<String>,
authed: Authed,
cookies: Cookies,
Json(callback): Json<OAuthCallback>,
Extension(user_db): Extension<UserDB>,
Extension(clients): Extension<Arc<AllClients>>,
Extension(http_client): Extension<Client>,
Json(callback): Json<OAuthCallback>,
) -> error::Result<String> {
let client = clients
.slack
@@ -717,14 +719,17 @@ pub struct SlackSig {
}
#[async_trait]
impl<B> FromRequest<B> for SlackSig
impl<S> FromRequestParts<S> for SlackSig
where
B: Send,
S: Send + Sync,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> std::result::Result<Self, Self::Rejection> {
let hm = req.headers();
async fn from_request_parts(
parts: &mut Parts,
_state: &S,
) -> std::result::Result<Self, Self::Rejection> {
let hm = &parts.headers;
Ok(Self {
sig: hm
.get("X-Slack-Signature")
@@ -833,13 +838,13 @@ pub struct UserInfo {
async fn login_callback(
Path(client_name): Path<String>,
Json(callback): Json<OAuthCallback>,
cookies: Cookies,
Extension(clients): Extension<Arc<AllClients>>,
Extension(db): Extension<DB>,
Extension(http_client): Extension<Client>,
Extension(is_secure): Extension<Arc<IsSecure>>,
Extension(cookie_domain): Extension<Arc<CookieDomain>>,
Json(callback): Json<OAuthCallback>,
) -> error::Result<String> {
let client_w_config = &clients
.logins
+1 -1
View File
@@ -383,7 +383,7 @@ pub struct PreviewPayload {
}
fn get_offset(offset: Option<i32>) -> FixedOffset {
FixedOffset::west(offset.unwrap_or(0) * 60)
FixedOffset::west_opt(offset.unwrap_or(0) * 60).expect("Invalid offset")
}
#[derive(Deserialize)]
+13 -10
View File
@@ -8,7 +8,8 @@
use axum::{
body::{self, BoxBody},
http::{header, response::Builder, Response, Uri},
extract::OriginalUri,
http::{header, response::Builder, Response},
response::IntoResponse,
Extension,
};
@@ -20,26 +21,28 @@ use std::sync::Arc;
// static_handler is a handler that serves static files from the
pub async fn static_handler(
uri: Uri,
Extension(is_secure): Extension<Arc<IsSecure>>,
Extension(is_cloud_hosted): Extension<Arc<CloudHosted>>,
Extension(csp): Extension<Arc<ContentSecurityPolicy>>,
) -> impl IntoResponse {
let path = uri.path().trim_start_matches('/').to_string();
OriginalUri(original_uri): OriginalUri,
) -> StaticFile {
let path = original_uri.path().trim_start_matches('/').to_string();
StaticFile(path, is_secure.0, is_cloud_hosted.0, csp)
}
#[derive(RustEmbed)]
#[folder = "../../frontend/build/"]
struct Asset;
pub struct StaticFile<T>(pub T, pub bool, pub bool, pub Arc<ContentSecurityPolicy>);
pub struct StaticFile(
pub String,
pub bool,
pub bool,
pub Arc<ContentSecurityPolicy>,
);
impl<T> IntoResponse for StaticFile<T>
where
T: Into<String>,
{
impl IntoResponse for StaticFile {
fn into_response(self) -> Response<BoxBody> {
let path = self.0.into();
let path = self.0;
let can_set_security_headers = self.1 && self.2;
let csp = self.3;
serve_path(path, can_set_security_headers, csp)
+37 -26
View File
@@ -18,8 +18,8 @@ use crate::{
use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use axum::{
async_trait,
extract::{Extension, FromRequest, Path, Query, RequestParts},
http,
extract::{Extension, FromRequestParts, Path, Query},
http::{self, request::Parts},
response::{IntoResponse, Response},
routing::{delete, get, post},
Json, Router,
@@ -275,16 +275,16 @@ impl AuthCache {
}
}
async fn extract_token<B: Send>(req: &mut RequestParts<B>) -> Option<String> {
let auth_header = req
.headers()
async fn extract_token<S: Send + Sync>(parts: &mut Parts, state: &S) -> Option<String> {
let auth_header = parts
.headers
.get(http::header::AUTHORIZATION)
.and_then(|value| value.to_str().ok())
.and_then(|s| s.strip_prefix("Bearer "));
let from_cookie = match auth_header {
Some(x) => Some(x.to_owned()),
None => Extension::<Cookies>::from_request(req)
None => Extension::<Cookies>::from_request_parts(parts, state)
.await
.ok()
.and_then(|cookies| cookies.get(COOKIE_NAME).map(|c| c.value().to_owned())),
@@ -296,7 +296,7 @@ async fn extract_token<B: Send>(req: &mut RequestParts<B>) -> Option<String> {
}
match from_cookie {
Some(token) => Some(token),
None => Query::<Token>::from_request(req)
None => Query::<Token>::from_request_parts(parts, state)
.await
.ok()
.and_then(|token| token.token.clone()),
@@ -309,21 +309,24 @@ pub struct Tokened {
}
#[async_trait]
impl<B> FromRequest<B> for Tokened
impl<S> FromRequestParts<S> for Tokened
where
B: Send,
S: Send + Sync,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> std::result::Result<Self, Self::Rejection> {
let already_tokened = req.extensions().get::<Tokened>();
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> std::result::Result<Self, Self::Rejection> {
let already_tokened = parts.extensions.get::<Tokened>();
if let Some(tokened) = already_tokened {
Ok(tokened.clone())
} else {
let token_o = extract_token(req).await;
let token_o = extract_token(parts, state).await;
if let Some(token) = token_o {
let tokened = Self { token };
req.extensions_mut().insert(tokened.clone());
parts.extensions.insert(tokened.clone());
Ok(tokened)
} else {
Err((StatusCode::UNAUTHORIZED, "Unauthorized".to_owned()))
@@ -342,33 +345,38 @@ pub struct Authed {
}
#[async_trait]
impl<B> FromRequest<B> for Authed
impl<S> FromRequestParts<S> for Authed
where
B: Send,
S: Send + Sync,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> std::result::Result<Self, Self::Rejection> {
let already_authed = req.extensions().get::<Authed>();
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> std::result::Result<Self, Self::Rejection> {
let already_authed = parts.extensions.get::<Authed>();
if let Some(authed) = already_authed {
Ok(authed.clone())
} else {
let already_tokened = req.extensions().get::<Tokened>();
let already_tokened = parts.extensions.get::<Tokened>();
let token_o = if let Some(token) = already_tokened {
Some(token.token.clone())
} else {
extract_token(req).await
extract_token(parts, state).await
};
let path_vec: Vec<&str> = req.uri().path().split("/").collect();
let path_vec: Vec<&str> = parts.uri.path().split("/").collect();
let workspace_id = if path_vec[0] == "" && path_vec[1] == "w" {
Some(path_vec[2].to_owned())
} else {
None
};
if let Some(token) = token_o {
if let Ok(Extension(cache)) = Extension::<Arc<AuthCache>>::from_request(req).await {
if let Ok(Extension(cache)) =
Extension::<Arc<AuthCache>>::from_request_parts(parts, state).await
{
if let Some(authed) = cache.get_authed(workspace_id.clone(), &token).await {
req.extensions_mut().insert(authed.clone());
parts.extensions.insert(authed.clone());
Span::current().record("username", &authed.username.as_str());
Span::current().record("email", &authed.email);
@@ -388,14 +396,17 @@ where
pub struct OptAuthed(pub Option<Authed>);
#[async_trait]
impl<B> FromRequest<B> for OptAuthed
impl<S> FromRequestParts<S> for OptAuthed
where
B: Send,
S: Send + Sync,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> std::result::Result<Self, Self::Rejection> {
Authed::from_request(req)
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> std::result::Result<Self, Self::Rejection> {
Authed::from_request_parts(parts, state)
.await
.map(|authed| Self(Some(authed)))
.or_else(|_| Ok(Self(None)))
+1 -1
View File
@@ -10,7 +10,7 @@
use axum::{
body::{self, BoxBody},
response::IntoResponse,
Json,
response::Json,
};
#[cfg(feature = "sqlx")]
@@ -181,7 +181,7 @@
<div class="w-full h-full">
<FlowJobResult result={job.result} logs={job.logs ?? ''} />
</div>
{:else if job.flow_status?.modules?.[job?.flow_status?.step].type === FlowStatusModule.type.WAITING_FOR_EVENTS}
{:else if job.flow_status?.modules?.[job?.flow_status?.step]?.type === FlowStatusModule.type.WAITING_FOR_EVENTS}
<div class="w-full h-full mt-2 text-sm text-gray-600">
<p>Waiting to be resumed</p>
<div>
@@ -135,6 +135,7 @@
policy
}
})
closeSaveDrawer()
goto(`/apps/edit/${appId}`)
} catch (e) {
sendUserToast('Error creating app', e)
@@ -65,13 +65,13 @@
on:click={(e) => {
e.preventDefault()
copyToClipboard(
`${$page.url.protocol}//${$page.url.hostname}/api/w/${$workspaceStore}/capture/${$flowStore.path}`
`${$page.url.protocol}//${$page.url.hostname}/api/w/${$workspaceStore}/capture_u/${$flowStore.path}`
)
}}
href="{$page.url.protocol}//{$page.url
.hostname}/api/w/{$workspaceStore}/capture/{$flowStore.path}"
.hostname}/api/w/{$workspaceStore}/capture_u/{$flowStore.path}"
>{$page.url.protocol}//{$page.url
.hostname}/api/w/{$workspaceStore}/capture/{$flowStore.path}
.hostname}/api/w/{$workspaceStore}/capture_u/{$flowStore.path}
<Icon data={faClipboard} /></a
>
</div>
@@ -79,7 +79,7 @@
<div class="text-xs box mb-4 b">
<pre class="overflow-auto"
>{`curl -X POST ${$page.url.protocol}//${$page.url.hostname}/api/w/${$workspaceStore}/capture/${$flowStore.path} \\
>{`curl -X POST ${$page.url.protocol}//${$page.url.hostname}/api/w/${$workspaceStore}/capture_u/${$flowStore.path} \\
-H 'Content-Type: application/json' \\
-d '{"foo": 42}'`}</pre
>
@@ -19,7 +19,7 @@
let pageIndex: number | undefined = Number($page.url.searchParams.get('page')) || undefined
let before: string | undefined = $page.url.searchParams.get('before') ?? undefined
let after: string | undefined = $page.url.searchParams.get('after') ?? undefined
let perPage: number | undefined = Number($page.url.searchParams.get('perPage')) || undefined
let perPage: number | undefined = Number($page.url.searchParams.get('perPage')) || 100
let operation: string | undefined = $page.url.searchParams.get('operation') ?? undefined
let resource: string | undefined = $page.url.searchParams.get('resource') ?? undefined
let actionKind: ActionKind | undefined =