flowstash-cli 0.1.3__tar.gz → 0.2.0__tar.gz

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 (48) hide show
  1. {flowstash_cli-0.1.3 → flowstash_cli-0.2.0}/PKG-INFO +1 -1
  2. {flowstash_cli-0.1.3 → flowstash_cli-0.2.0}/pyproject.toml +3 -3
  3. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/webhook.py +1 -1
  4. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/main.py +1 -0
  5. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/AGENTS.md +68 -10
  6. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/README.md +4 -4
  7. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_api_main.py +2 -2
  8. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_api/_routes/webhooks.py +3 -3
  9. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_shared/clients/client.py +1 -1
  10. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_shared/tasks/sharedTasks.py +2 -2
  11. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_worker/tasks/tasks.py +2 -2
  12. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_worker_main.py +2 -2
  13. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/__init__.py +0 -0
  14. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/__init__.py +0 -0
  15. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/auth.py +0 -0
  16. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/build.py +0 -0
  17. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/deploy.py +0 -0
  18. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/project.py +0 -0
  19. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/commands/run.py +0 -0
  20. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/__init__.py +0 -0
  21. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/api_client.py +0 -0
  22. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/auth_server.py +0 -0
  23. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/builder.py +0 -0
  24. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/config.py +0 -0
  25. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/docker_utils.py +0 -0
  26. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/core/patcher.py +0 -0
  27. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_.dockerignore +0 -0
  28. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_.flowstash +0 -0
  29. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/[env]/(backend-asyncio)/backend.yaml +0 -0
  30. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/[env]/(backend-dramatiq)/backend.yaml +0 -0
  31. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/[env]/(backend-managed)/backend.yaml +0 -0
  32. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/[env]/_backend.yaml +0 -0
  33. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/shared/.env +0 -0
  34. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/shared/backend.yaml +0 -0
  35. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/shared/clients/demoClient.yaml +0 -0
  36. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_config/shared/clients.yaml +0 -0
  37. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/[env]/(backend-asyncio)/docker-compose.yaml +0 -0
  38. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/[env]/(backend-dramatiq)/docker-compose.yaml +0 -0
  39. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/[env]/.env +0 -0
  40. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/shared/.env +0 -0
  41. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/shared/api.Dockerfile +0 -0
  42. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_deployment/shared/worker.Dockerfile +0 -0
  43. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_pyproject.toml +0 -0
  44. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_api/__init__.py +0 -0
  45. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_shared/__init__.py +0 -0
  46. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_shared/models/models.py +0 -0
  47. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/templates/_src/_worker/__init__.py +0 -0
  48. {flowstash_cli-0.1.3/flowstash → flowstash_cli-0.2.0/src/flowstash/cli}/ui/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flowstash-cli
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: CLI for the flowstash Managed Platform
5
5
  Author: juraj.bezdek@gmail.com
6
6
  Author-email: juraj.bezdek@gmail.com
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "flowstash-cli"
3
- version = "0.1.3"
3
+ version = "0.2.0"
4
4
  description = "CLI for the flowstash Managed Platform"
5
5
  authors = [{name = "juraj.bezdek@gmail.com", email = "juraj.bezdek@gmail.com"}]
6
6
  requires-python = ">=3.11"
@@ -18,11 +18,11 @@ dependencies = [
18
18
  ]
19
19
 
20
20
  [project.scripts]
21
- flowstash = "flowstash.main:app"
21
+ flowstash = "flowstash.cli.main:app"
22
22
 
23
23
  [tool.poetry]
24
24
  packages = [
25
- { include = "flowstash" }
25
+ { include = "flowstash", from = "src" }
26
26
  ]
27
27
 
28
28
  [tool.poetry.dependencies]
@@ -60,7 +60,7 @@ except Exception as e:
60
60
  print(json.dumps({{"error": str(e)}}))
61
61
  sys.exit(1)
62
62
 
63
- from flowstash_lib.pipelines.ingress import ingress
63
+ from flowstash.ingress import ingress
64
64
  result = []
65
65
  for h in ingress.get_webhooks():
66
66
  m = h._ingress_metadata
@@ -43,6 +43,7 @@ app.add_typer(env_app, name="env")
43
43
  app.add_typer(
44
44
  webhook_cmds.app,
45
45
  name="webhook",
46
+ help="Start a temporary public webhook listener to capture sample payloads",
46
47
  no_args_is_help=True,
47
48
  )
48
49
 
@@ -13,13 +13,13 @@ flowstash integrations revolve around the following core ideas:
13
13
 
14
14
  ## Bringing Data In: Ingress
15
15
 
16
- You can trigger your pipelines through two main ingress decorators provided by `flowstash_lib.pipelines.ingress`:
16
+ You can trigger your pipelines through two main ingress decorators provided by `flowstash.ingress`:
17
17
 
18
18
  ### 1. Webhooks (`@ingress.webhook`)
19
19
  Use webhooks when an external system can push events to your application. This decorator registers the handler as part of the integration but leaves the exact handling logic to you.
20
20
 
21
21
  ```python
22
- from flowstash_lib.pipelines.ingress import ingress
22
+ from flowstash.ingress import ingress
23
23
 
24
24
  @router.post("/webhook/slack")
25
25
  @ingress.webhook(pipeline="slack.messages", integration="slack")
@@ -34,7 +34,7 @@ Use polling when you need to fetch data on a schedule. This decorator acts as a
34
34
  The state is automatically saved for you as long as the function executes without exceptions.
35
35
 
36
36
  ```python
37
- from flowstash_lib.pipelines.ingress import ingress
37
+ from flowstash.ingress import ingress
38
38
  from datetime import datetime
39
39
 
40
40
  @ingress.poll(pipeline="slack.messages", integration="slack", schedule="*/5 * * * *")
@@ -51,6 +51,64 @@ async def poll_slack(state: dict):
51
51
  state["since"] = datetime.now()
52
52
  ```
53
53
 
54
+ ## State Management: The State Machine Principle
55
+
56
+ Integrations often need to remember things between runs. flowstash treats every integration run as a transition in a **state machine**. You load the current state, perform your logic, and save the updated state.
57
+
58
+ ### The `State` Facade
59
+
60
+ The `State` facade (accessible via `from flowstash.integration import State`) provides a centralized interface for persistent storage. It automatically handles namespacing, serialization, and TTLs, so you can focus on the data.
61
+
62
+ #### Scopes
63
+ State is automatically isolated into three logical scopes based on the active context:
64
+ - **`integration` (Default)**: Shared across all tasks and pipelines in a specific integration (e.g., `slack`). Use for global settings or cross-pipeline flags.
65
+ - **`pipeline`**: Shared across all tasks in a specific pipeline (e.g., `slack.sync_users`).
66
+ - **`ingress`**: Private state for a specific ingress entrypoint (e.g., a specific poll timer). This is the default scope for the `state` dict injected into `@ingress.poll`.
67
+
68
+ #### Basic Usage
69
+ ```python
70
+ from flowstash.integration import State
71
+
72
+ @integration_task(integration="demo", pipeline="example")
73
+ async def my_stateful_task():
74
+ # 1. Get current state (scoped to integration:demo by default)
75
+ # Returns None or the decoded value (JSON objects are automatically parsed)
76
+ last_processed = State.get("last_id") or 0
77
+
78
+ # ... perform logic ...
79
+
80
+ # 2. Update state (persists to the configured backend: Redis, SQLite, Managed, etc.)
81
+ State.set("last_id", 123)
82
+ ```
83
+
84
+ ### Auto-Saving in Ingress
85
+ In `@ingress.poll`, state management is handled for you. The `state` dictionary is automatically loaded before your function runs and persisted back to the `ingress` scope precisely when your function returns successfully.
86
+
87
+ ```python
88
+ @ingress.poll(pipeline="demo", integration="acme", schedule="* * * * *")
89
+ async def poll_handler(state: dict):
90
+ # This 'state' is already loaded for you
91
+ cursor = state.get("cursor", "init")
92
+
93
+ # ... fetching data ...
94
+
95
+ # Changes to this dict are automatically saved on a successful return
96
+ state["cursor"] = "next_page_token"
97
+ ```
98
+
99
+ ### Context Bound
100
+ `State` is fully context-aware. You don't need to pass around tenant IDs or integration names. When you are inside an `@integration_task`, `@integration_step` or an `@ingress` handler, `State` already knows where to store the data.
101
+
102
+ If you need to use `State` in a CLI script or a test outside of a managed run, you can bind it manually:
103
+ ```python
104
+ from flowstash.context import integration_context
105
+
106
+ with integration_context(integration="my-int", integration_pipeline="pipe"):
107
+ # Inside this block, State is bound to "my-int" and "pipe"
108
+ State.set("setup_complete", True)
109
+ ```
110
+
111
+
54
112
  ## Making External Requests: Clients
55
113
 
56
114
  flowstash makes it easy to interact with external APIs via Clients. They handle setting Base URLs, automatic Authentication headers, observability tracing, and defaults out of the box.
@@ -64,11 +122,11 @@ pattern: "*.yaml"
64
122
  You can simply define `clients/slackClient.yaml` and the system will expose it to your tasks.
65
123
 
66
124
  ### Using a Client
67
- Once configured, you can retrieve the standard HTTP client (from the `flowstash_clients` package) anywhere.
125
+ Once configured, you can retrieve the standard HTTP client (from the `flowstash.clients` package) anywhere.
68
126
 
69
127
  ```python
70
- from flowstash_clients import get_client
71
- from flowstash_lib.decorators import integration_task
128
+ from flowstash.clients import get_client
129
+ from flowstash.decorators import integration_task
72
130
 
73
131
  # Load the client configuration
74
132
  slack_client = get_client("slackClient")
@@ -83,7 +141,7 @@ async def send_slack_message_task(message: str):
83
141
  If you have an API you interact with heavily, you can define a custom typed client. This encapsulates specific API routes for a better developer experience.
84
142
 
85
143
  ```python
86
- from flowstash_lib.clients import HttpClient, client
144
+ from flowstash.clients import HttpClient, client
87
145
  from typing import List
88
146
 
89
147
  # Extending HttpClient and registering with the @client decorator
@@ -113,8 +171,8 @@ The framework resolves deduplication using a unique combination of `(integration
113
171
  It also seamlessly supports feeding massive data payloads -- large objects (> 5KB) are automatically offloaded to a BlobStore.
114
172
 
115
173
  ```python
116
- from flowstash_lib.pipelines.records_feed import RecordsFeed
117
- from flowstash_lib.pipelines.records_model import RecordData
174
+ from flowstash.pipelines.records_feed import RecordsFeed
175
+ from flowstash.pipelines.records_model import RecordData
118
176
 
119
177
  # Retrieve your specific feed
120
178
  feed = RecordsFeed.get(feed_id="slack.messages")
@@ -131,7 +189,7 @@ await feed.publish(RecordData(
131
189
  To process the data asynchronously, decorate a function with `@feed_consumer`. This supports robust configurations like automatic batched receiving, delays, rate-limiting, and concurrency control.
132
190
 
133
191
  ```python
134
- from flowstash_lib import feed_consumer, RecordData
192
+ from flowstash.pipelines import feed_consumer, RecordData
135
193
 
136
194
  @feed_consumer(
137
195
  feed_id="slack.messages",
@@ -90,7 +90,7 @@ python worker.py
90
90
 
91
91
  ## flowstash Core Concepts Usage
92
92
 
93
- This project is built on `flowstash_lib` – a core library providing robust context management, queue abstractions, and observability. Here is how you can utilize its components in your application:
93
+ This project is built on `flowstash` – a core library providing robust context management, queue abstractions, and observability. Here is how you can utilize its components in your application:
94
94
 
95
95
  ### Integration Context
96
96
  `IntegrationContext` propagates automatically through all your integration operations. It manages the current `run_id`, `integration`, and `current_record_key` to ensure all logs and traces are correctly correlated without manual passing.
@@ -102,7 +102,7 @@ This project is built on `flowstash_lib` – a core library providing robust con
102
102
  ### RecordsFeed & Consumers
103
103
  Extract and ingest data efficiently using **RecordsFeed**:
104
104
  ```python
105
- from flowstash_lib.pipelines.records_feed import RecordsFeed, RecordData
105
+ from flowstash.pipelines.records_feed import RecordsFeed, RecordData
106
106
 
107
107
  feed = RecordsFeed.get(feed_id="your.pipeline")
108
108
  feed.publish(RecordData(record_id="123", record_type="invoice", data={...}))
@@ -111,7 +111,7 @@ Records are automatically deduplicated and optionally ordered by timestamp.
111
111
 
112
112
  Consume them robustly with **Feed Consumers**, which handle batching, rate-limiting, and parallel execution automatically:
113
113
  ```python
114
- from flowstash_lib.pipelines.consumer import feed_consumer
114
+ from flowstash.pipelines.consumer import feed_consumer
115
115
 
116
116
  @feed_consumer(
117
117
  feed_id="your.pipeline",
@@ -129,7 +129,7 @@ async def process_records(records: list[RecordData]):
129
129
  Use the provided `logger` to naturally correlate your logs with the active context. The framework tracks the lifecycle of records intrinsically (from publishing to consumption) without manual `record_id` logging.
130
130
 
131
131
  ```python
132
- from flowstash_lib import logger
132
+ from flowstash.observability.logging import logger
133
133
 
134
134
  logger.info("Processing the invoice batch", details="step 1 completed")
135
135
  ```
@@ -1,7 +1,7 @@
1
1
  from pathlib import Path
2
2
  from fastapi import Request
3
- from flowstash_lib.config.env_loader import load_config_dir
4
- from flowstash_runtime.ingress.app import create_fastapi_app
3
+ from flowstash.config.env_loader import load_config_dir
4
+ from flowstash.runtime.ingress.app import create_fastapi_app
5
5
  import os
6
6
  env = os.getenv("ENVIRONMENT", "dev")
7
7
  # Load configuration relative to this file
@@ -1,7 +1,7 @@
1
- from flowstash_lib import ingress
2
- from flowstash_lib import RecordData
1
+ from flowstash import ingress
2
+ from flowstash.pipelines import RecordData
3
3
  from fastapi import Request
4
- from flowstash_lib.pipelines.records_feed import RecordsFeed
4
+ from flowstash.pipelines.records_feed import RecordsFeed
5
5
 
6
6
  @ingress.webhook(integration="demo", pipeline="process_user", path="/demo/process_user", method="POST")
7
7
  async def process_user_webhook(request: Request):
@@ -1,5 +1,5 @@
1
1
  from typing import List, Optional
2
- from flowstash_lib.clients import HttpClient, client
2
+ from flowstash.clients import HttpClient, client
3
3
 
4
4
  @client("DemoClient")
5
5
  class DemoClient(HttpClient):
@@ -1,5 +1,5 @@
1
- from flowstash_lib.decorators import integration_task
2
- from flowstash_clients import get_client
1
+ from flowstash.decorators import integration_task
2
+ from flowstash.clients import get_client
3
3
 
4
4
  @integration_task(integration="demo", integration_pipeline="adhoc_task")
5
5
  async def adhoc_task(data: dict):
@@ -1,5 +1,5 @@
1
- from flowstash_lib.decorators import integration_task
2
- from flowstash_lib.queue.backend import Schedule
1
+ from flowstash.decorators import integration_task
2
+ from flowstash.queue.backend import Schedule
3
3
 
4
4
 
5
5
 
@@ -2,8 +2,8 @@ import os
2
2
  import asyncio
3
3
  import logging
4
4
  from pathlib import Path
5
- from flowstash_lib.config.env_loader import load_config_dir
6
- from flowstash_runtime import initialize_runtime, run_worker
5
+ from flowstash.config.env_loader import load_config_dir
6
+ from flowstash.runtime import initialize_runtime, run_worker
7
7
 
8
8
  logging.basicConfig(level=logging.INFO)
9
9