Documentation
¶
Overview ¶
Package ioworkspace provides types and utilities for workspace import/export operations.
This package defines the core data structures used to bundle all workspace entities (HTTP requests, flows, files, environments, etc.) for serialization, transfer, and deserialization across different formats (JSON, YAML, etc.).
Key Types:
- WorkspaceBundle: Complete snapshot of all workspace entities
- ImportOptions: Configuration for import operations
- ExportOptions: Configuration for export operations
The WorkspaceBundle structure serves as a comprehensive container for all workspace data, making it easy to:
- Export entire workspaces to various formats
- Import workspaces from external sources
- Clone or backup workspace state
- Migrate workspaces between environments
Example usage:
// Create a bundle with workspace data
bundle := &ioworkspace.WorkspaceBundle{
Workspace: workspace,
HTTPRequests: httpRequests,
Flows: flows,
// ... other entities
}
// Get entity counts for logging
counts := bundle.CountEntities()
fmt.Printf("Exporting %d HTTP requests and %d flows\n",
counts["http_requests"], counts["flows"])
// Find specific entities
flow := bundle.GetFlowByName("Main Flow")
http := bundle.GetHTTPByID(httpID)
Index ¶
- Constants
- Variables
- type ExportOptions
- type FlowCleanup
- type FlowCleanupStep
- type IOWorkspaceService
- func (s *IOWorkspaceService) Export(ctx context.Context, opts ExportOptions) (*WorkspaceBundle, error)
- func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *WorkspaceBundle, opts ImportOptions) (*ImportResult, error)
- func (s *IOWorkspaceService) TX(tx *sql.Tx) *IOWorkspaceService
- type ImportOptions
- type ImportResult
- type WorkspaceBundle
- func (wb *WorkspaceBundle) AllHTTPNoRedirects() map[idwrap.IDWrap]bool
- func (wb *WorkspaceBundle) AllHTTPStreams() map[idwrap.IDWrap]mhttp.HTTPStream
- func (wb *WorkspaceBundle) CleanupFlowIDs() map[idwrap.IDWrap]bool
- func (wb *WorkspaceBundle) CleanupsByFlowID() map[idwrap.IDWrap]FlowCleanup
- func (wb *WorkspaceBundle) CountEntities() map[string]int
- func (wb *WorkspaceBundle) EnsureFlowStructure() error
- func (wb *WorkspaceBundle) GetEnvironmentByID(id idwrap.IDWrap) *menv.Env
- func (wb *WorkspaceBundle) GetEnvironmentByName(name string) *menv.Env
- func (wb *WorkspaceBundle) GetFileByContentID(contentID idwrap.IDWrap) *mfile.File
- func (wb *WorkspaceBundle) GetFileByID(id idwrap.IDWrap) *mfile.File
- func (wb *WorkspaceBundle) GetFlowByID(id idwrap.IDWrap) *mflow.Flow
- func (wb *WorkspaceBundle) GetFlowByName(name string) *mflow.Flow
- func (wb *WorkspaceBundle) GetGraphQLByID(id idwrap.IDWrap) *mgraphql.GraphQL
- func (wb *WorkspaceBundle) GetHTTPByID(id idwrap.IDWrap) *mhttp.HTTP
- func (wb *WorkspaceBundle) GetNodeByID(id idwrap.IDWrap) *mflow.Node
- func (wb *WorkspaceBundle) StepExpects() map[idwrap.IDWrap]mexpect.Expect
Constants ¶
const ( NodeSpacingX = 400 // Horizontal spacing between parallel nodes NodeSpacingY = 300 // Vertical spacing between levels StartX = 0 // Starting X position StartY = 0 // Starting Y position )
Layout constants for node positioning (kept for backward compatibility)
const FlowCleanupsNotStoredMessage = "" /* 162-byte string literal not displayed */
FlowCleanupsNotStoredMessage is logged when a bundle with cleanup blocks is imported without ImportOptions.ImportFlowCleanups.
const LoadScenariosNotStoredMessage = "" /* 143-byte string literal not displayed */
LoadScenariosNotStoredMessage is logged when an imported bundle carries load scenarios. It is a constant so tests can assert on the warning without pinning the surrounding log format.
Variables ¶
var ( // ErrWorkspaceIDRequired is returned when a workspace ID is not provided ErrWorkspaceIDRequired = errors.New("workspace ID is required") // ErrInvalidMergeMode is returned when an invalid merge mode is specified ErrInvalidMergeMode = errors.New("invalid merge mode: must be 'skip', 'replace', or 'create_new'") // ErrInvalidExportFormat is returned when an invalid export format is specified ErrInvalidExportFormat = errors.New("invalid export format: must be 'json', 'yaml', or 'zip'") // ErrWorkspaceNotFound is returned when a workspace is not found ErrWorkspaceNotFound = errors.New("workspace not found") // ErrInvalidBundle is returned when a workspace bundle fails validation ErrInvalidBundle = errors.New("invalid workspace bundle") // ErrImportFailed is returned when an import operation fails ErrImportFailed = errors.New("import operation failed") // ErrFlowCleanupsNeedPreservedIDs is returned when ImportFlowCleanups is // set without PreserveIDs: FlowCleanup refers to nodes by bundle ID. ErrFlowCleanupsNeedPreservedIDs = errors.New("importing flow cleanups requires PreserveIDs") // ErrExportFailed is returned when an export operation fails ErrExportFailed = errors.New("export operation failed") )
Functions ¶
This section is empty.
Types ¶
type ExportOptions ¶
type ExportOptions struct {
// WorkspaceID is the source workspace ID for the export (required)
WorkspaceID idwrap.IDWrap
// IncludeHTTP determines whether to include HTTP requests in the export
IncludeHTTP bool
// IncludeFlows determines whether to include flows in the export
IncludeFlows bool
// IncludeEnvironments determines whether to include environments in the export
IncludeEnvironments bool
// IncludeFiles determines whether to include file structure in the export
IncludeFiles bool
// ExportFormat specifies the output format (e.g., "json", "yaml", "zip")
ExportFormat string
// FilterByFolderID optionally filters export to a specific folder and its children
FilterByFolderID *idwrap.IDWrap
// FilterByFlowIDs optionally filters export to specific flows
FilterByFlowIDs []idwrap.IDWrap
// FilterByHTTPIDs optionally filters export to specific HTTP requests
FilterByHTTPIDs []idwrap.IDWrap
}
ExportOptions contains configuration options for workspace export operations.
func GetDefaultExportOptions ¶
func GetDefaultExportOptions(workspaceID idwrap.IDWrap) ExportOptions
GetDefaultExportOptions returns ExportOptions with sensible defaults.
func (ExportOptions) Validate ¶
func (opts ExportOptions) Validate() error
Validate validates the ExportOptions and returns an error if invalid.
type FlowCleanup ¶
type FlowCleanup struct {
// FlowID is the flow that owns the cleanup block.
FlowID idwrap.IDWrap
// CleanupFlowID is the hidden flow holding the cleanup nodes. It is
// Bundle.Flows[0].ID.
CleanupFlowID idwrap.IDWrap
// Steps lists the cleanup steps in execution order.
Steps []FlowCleanupStep
// Bundle holds the cleanup flow and every entity its nodes need (nodes,
// HTTP and GraphQL requests and their children).
Bundle *WorkspaceBundle
}
FlowCleanup is the `cleanup:` block of one flow.
The cleanup steps are converted into nodes of a separate, hidden flow (CleanupFlowID) with no start node and no edges between them, so they can never run as part of the owning flow's graph. A runner executes them one by one, in Steps order, after the owning flow reaches a terminal state, reusing the owning flow's variable map so they can read step outputs.
type FlowCleanupStep ¶
type FlowCleanupStep struct {
NodeID idwrap.IDWrap
Name string
// DependsOn names other cleanup steps of the same block. A step whose
// dependency did not succeed is skipped.
DependsOn []string
// References names the steps (normal or cleanup) whose output this step's
// templates read. A step referencing a step that produced no output (it
// never ran) is skipped instead of being sent with an unresolved template.
References []string
}
FlowCleanupStep is one cleanup step, in execution order.
type IOWorkspaceService ¶
type IOWorkspaceService struct {
// contains filtered or unexported fields
}
IOWorkspaceService provides import/export operations for workspaces.
func New ¶
func New(queries *gen.Queries, logger *slog.Logger) *IOWorkspaceService
New creates a new IOWorkspaceService.
func (*IOWorkspaceService) Export ¶
func (s *IOWorkspaceService) Export(ctx context.Context, opts ExportOptions) (*WorkspaceBundle, error)
Export exports a workspace and all its entities to a WorkspaceBundle
func (*IOWorkspaceService) Import ¶
func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *WorkspaceBundle, opts ImportOptions) (*ImportResult, error)
Import imports a WorkspaceBundle into the database using the provided options. This operation should be performed within a transaction for atomicity.
Load scenarios are the one part of a bundle Import does not store: there is no schema for them yet. Rather than lose them quietly, an import that carries any says so - see warnUnstoredLoadScenarios.
func (*IOWorkspaceService) TX ¶
func (s *IOWorkspaceService) TX(tx *sql.Tx) *IOWorkspaceService
TX returns a new service instance with transaction support.
type ImportOptions ¶
type ImportOptions struct {
// WorkspaceID is the target workspace ID for the import (required)
WorkspaceID idwrap.IDWrap
// ParentFolderID is the optional parent folder to import files under
ParentFolderID *idwrap.IDWrap
// CreateFiles determines whether to create file entries during import
CreateFiles bool
// MergeMode determines how to handle conflicts with existing entities
// - "skip": Skip entities that already exist
// - "replace": Replace existing entities with imported ones
// - "create_new": Create new entities even if similar ones exist
MergeMode string
// PreserveIDs determines whether to preserve entity IDs from the source
// If false, new IDs will be generated during import
PreserveIDs bool
// ImportHTTP determines whether to import HTTP requests
ImportHTTP bool
// ImportFlows determines whether to import flows
ImportFlows bool
// ImportEnvironments determines whether to import environments
ImportEnvironments bool
// StartOrder is the starting order value for imported files
StartOrder float64
// ImportFlowCleanups stores each FlowCleanup's hidden cleanup flow and its
// entities, so a runner can build and execute the cleanup nodes. It
// requires PreserveIDs, because FlowCleanup refers to nodes and flows by
// their bundle IDs. When false (the desktop import path), cleanup blocks
// are dropped with a warning.
ImportFlowCleanups bool
}
ImportOptions contains configuration options for workspace import operations.
func GetDefaultImportOptions ¶
func GetDefaultImportOptions(workspaceID idwrap.IDWrap) ImportOptions
GetDefaultImportOptions returns ImportOptions with sensible defaults.
func (ImportOptions) Validate ¶
func (opts ImportOptions) Validate() error
Validate validates the ImportOptions and returns an error if invalid.
type ImportResult ¶
type ImportResult struct {
// Entity counts
HTTPRequestsCreated int
HTTPSearchParamsCreated int
HTTPHeadersCreated int
HTTPBodyFormsCreated int
HTTPBodyUrlencodedCreated int
HTTPBodyRawCreated int
HTTPAssertsCreated int
FilesCreated int
FlowsCreated int
FlowVariablesCreated int
FlowNodesCreated int
FlowEdgesCreated int
FlowRequestNodesCreated int
FlowConditionNodesCreated int
FlowForNodesCreated int
FlowForEachNodesCreated int
FlowJSNodesCreated int
FlowAINodesCreated int
FlowAIProviderNodesCreated int
FlowAIMemoryNodesCreated int
FlowGraphQLNodesCreated int
FlowWsConnectionNodesCreated int
FlowWsSendNodesCreated int
FlowWaitNodesCreated int
FlowSubFlowTriggerNodesCreated int
FlowSubFlowReturnNodesCreated int
FlowRunSubFlowNodesCreated int
WebSocketsCreated int
WebSocketHeadersCreated int
GraphQLRequestsCreated int
GraphQLHeadersCreated int
GraphQLAssertsCreated int
EnvironmentsCreated int
EnvironmentVarsCreated int
// ID mappings for reference (old ID -> new ID)
HTTPIDMap map[idwrap.IDWrap]idwrap.IDWrap
FlowIDMap map[idwrap.IDWrap]idwrap.IDWrap
NodeIDMap map[idwrap.IDWrap]idwrap.IDWrap
FileIDMap map[idwrap.IDWrap]idwrap.IDWrap
EnvironmentIDMap map[idwrap.IDWrap]idwrap.IDWrap
WebSocketIDMap map[idwrap.IDWrap]idwrap.IDWrap
}
ImportResult contains statistics and mappings from the import operation.
type WorkspaceBundle ¶
type WorkspaceBundle struct {
// Workspace metadata
Workspace mworkspace.Workspace
// HTTP requests and associated data structures
HTTPRequests []mhttp.HTTP
HTTPSearchParams []mhttp.HTTPSearchParam
HTTPHeaders []mhttp.HTTPHeader
HTTPBodyForms []mhttp.HTTPBodyForm
HTTPBodyUrlencoded []mhttp.HTTPBodyUrlencoded
HTTPBodyRaw []mhttp.HTTPBodyRaw
HTTPAsserts []mhttp.HTTPAssert
// GraphQL requests and associated data
GraphQLRequests []mgraphql.GraphQL
GraphQLHeaders []mgraphql.GraphQLHeader
GraphQLAsserts []mgraphql.GraphQLAssert
// WebSocket requests and associated data
WebSockets []mwebsocket.WebSocket
WebSocketHeaders []mwebsocket.WebSocketHeader
// File organization
Files []mfile.File
// Flow structures
Flows []mflow.Flow
FlowVariables []mflow.FlowVariable
FlowNodes []mflow.Node
FlowEdges []mflow.Edge
// Flow node implementations by type
FlowRequestNodes []mflow.NodeRequest
FlowConditionNodes []mflow.NodeIf
FlowForNodes []mflow.NodeFor
FlowForEachNodes []mflow.NodeForEach
FlowJSNodes []mflow.NodeJS
FlowAINodes []mflow.NodeAI
FlowAIProviderNodes []mflow.NodeAiProvider
FlowAIMemoryNodes []mflow.NodeMemory
FlowGraphQLNodes []mflow.NodeGraphQL
FlowWsConnectionNodes []mflow.NodeWsConnection
FlowWsSendNodes []mflow.NodeWsSend
FlowWaitNodes []mflow.NodeWait
FlowSubFlowTriggerNodes []mflow.NodeSubFlowTrigger
FlowSubFlowReturnNodes []mflow.NodeSubFlowReturn
FlowRunSubFlowNodes []mflow.NodeRunSubFlow
// Environments and variables
Environments []menv.Env
EnvironmentVars []menv.Variable
// Credentials (metadata only, secrets are never exported)
Credentials []mcredential.Credential
// LoadScenarios carries the yamlflow `load:` block so it survives the
// YAML import -> export round trip.
//
// Unlike every other field here it is NOT database-backed: Import ignores
// it and Export never populates it, because there is no storage for load
// scenarios yet (Phase 2). Only the file-to-file path (the CLI and the
// yamlflow translator) reads and writes it.
LoadScenarios []mload.Scenario
// FlowCleanups carries each flow's yamlflow `cleanup:` steps: steps that
// run after the flow's normal steps finish, whether they passed or failed.
//
// Like LoadScenarios it is file-only: the cleanup entities live in each
// FlowCleanup's own Bundle rather than in the slices above, so a regular
// Import does not store them (and says so) and Export never populates
// this field. Import stores them only when ImportOptions.ImportFlowCleanups
// is set, which the CLI does so it can execute them.
FlowCleanups []FlowCleanup
// AIChecks carries the yamlflow AI checks: the file's and flows' judge:,
// quality: and iterations:, and each step's expect: block (by flow node ID).
// Import stores the flows' settings (with the file's folded in) and the
// steps' blocks; Export reads them back as flow settings and steps. Expect
// blocks of cleanup steps live in the cleanup's own Bundle.
AIChecks *mexpect.Checks
// HTTPStreams carries request steps' stream: settings, by HTTP request.
HTTPStreams []mhttp.HTTPStream
// HTTPNoRedirects lists the HTTP requests of steps with follow_redirects: false.
// File-only: the CLI applies it to the built nodes; the workspace DB does not store it.
HTTPNoRedirects []idwrap.IDWrap
}
WorkspaceBundle contains all entities that make up a complete workspace including HTTP requests, flows, files, folders, environments, and all associated data. This structure is used for workspace import/export operations.
func (*WorkspaceBundle) AllHTTPNoRedirects ¶
func (wb *WorkspaceBundle) AllHTTPNoRedirects() map[idwrap.IDWrap]bool
AllHTTPNoRedirects returns the HTTP requests of every step with follow_redirects: false, cleanup steps included.
func (*WorkspaceBundle) AllHTTPStreams ¶
func (wb *WorkspaceBundle) AllHTTPStreams() map[idwrap.IDWrap]mhttp.HTTPStream
AllHTTPStreams returns every HTTP request's stream: settings, cleanup steps included, by HTTP request ID.
func (*WorkspaceBundle) CleanupFlowIDs ¶
func (wb *WorkspaceBundle) CleanupFlowIDs() map[idwrap.IDWrap]bool
CleanupFlowIDs returns the IDs of every hidden cleanup flow in the bundle.
func (*WorkspaceBundle) CleanupsByFlowID ¶
func (wb *WorkspaceBundle) CleanupsByFlowID() map[idwrap.IDWrap]FlowCleanup
CleanupsByFlowID indexes the bundle's cleanup blocks by owning flow ID.
func (*WorkspaceBundle) CountEntities ¶
func (wb *WorkspaceBundle) CountEntities() map[string]int
CountEntities returns a map containing the count of each entity type in the bundle. Useful for logging, debugging, and displaying import/export statistics.
func (*WorkspaceBundle) EnsureFlowStructure ¶
func (wb *WorkspaceBundle) EnsureFlowStructure() error
EnsureFlowStructure ensures each flow in the bundle has a proper start node and positions all nodes using a level-based layout algorithm. This should be called after all flow data has been populated but before saving.
func (*WorkspaceBundle) GetEnvironmentByID ¶
func (wb *WorkspaceBundle) GetEnvironmentByID(id idwrap.IDWrap) *menv.Env
GetEnvironmentByID finds and returns an environment by its ID. Returns nil if the environment is not found.
func (*WorkspaceBundle) GetEnvironmentByName ¶
func (wb *WorkspaceBundle) GetEnvironmentByName(name string) *menv.Env
GetEnvironmentByName finds and returns an environment by its name. Returns nil if the environment is not found.
func (*WorkspaceBundle) GetFileByContentID ¶
func (wb *WorkspaceBundle) GetFileByContentID(contentID idwrap.IDWrap) *mfile.File
GetFileByContentID finds and returns a file by its ContentID. Returns nil if no file is found with that content ID.
func (*WorkspaceBundle) GetFileByID ¶
func (wb *WorkspaceBundle) GetFileByID(id idwrap.IDWrap) *mfile.File
GetFileByID finds and returns a file by its ID. Returns nil if the file is not found.
func (*WorkspaceBundle) GetFlowByID ¶
func (wb *WorkspaceBundle) GetFlowByID(id idwrap.IDWrap) *mflow.Flow
GetFlowByID finds and returns a flow by its ID. Returns nil if the flow is not found.
func (*WorkspaceBundle) GetFlowByName ¶
func (wb *WorkspaceBundle) GetFlowByName(name string) *mflow.Flow
GetFlowByName finds and returns a flow by its name. Returns nil if the flow is not found.
func (*WorkspaceBundle) GetGraphQLByID ¶
func (wb *WorkspaceBundle) GetGraphQLByID(id idwrap.IDWrap) *mgraphql.GraphQL
GetGraphQLByID finds and returns a GraphQL request by its ID. Returns nil if the GraphQL request is not found.
func (*WorkspaceBundle) GetHTTPByID ¶
func (wb *WorkspaceBundle) GetHTTPByID(id idwrap.IDWrap) *mhttp.HTTP
GetHTTPByID finds and returns an HTTP request by its ID. Returns nil if the HTTP request is not found.
func (*WorkspaceBundle) GetNodeByID ¶
func (wb *WorkspaceBundle) GetNodeByID(id idwrap.IDWrap) *mflow.Node
GetNodeByID finds and returns a flow node by its ID. Returns nil if the node is not found.
func (*WorkspaceBundle) StepExpects ¶
func (wb *WorkspaceBundle) StepExpects() map[idwrap.IDWrap]mexpect.Expect
StepExpects returns every step's expect: block, cleanup steps included, by flow node ID.