caraer-cli 0.1.2__py3-none-any.whl

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 (83) hide show
  1. caraer_cli/__init__.py +4 -0
  2. caraer_cli/api/__init__.py +1 -0
  3. caraer_cli/api/apps.py +78 -0
  4. caraer_cli/api/auth.py +53 -0
  5. caraer_cli/api/client.py +179 -0
  6. caraer_cli/api/functions.py +72 -0
  7. caraer_cli/api/installation.py +93 -0
  8. caraer_cli/api/integration_runtime.py +77 -0
  9. caraer_cli/api/projects.py +213 -0
  10. caraer_cli/api/sandboxes.py +29 -0
  11. caraer_cli/api/webhooks.py +59 -0
  12. caraer_cli/app_sync.py +697 -0
  13. caraer_cli/apps_local.py +274 -0
  14. caraer_cli/commands/__init__.py +1 -0
  15. caraer_cli/commands/apps.py +2025 -0
  16. caraer_cli/commands/auth.py +173 -0
  17. caraer_cli/commands/company.py +68 -0
  18. caraer_cli/commands/installation.py +182 -0
  19. caraer_cli/commands/profile.py +239 -0
  20. caraer_cli/commands/publish.py +40 -0
  21. caraer_cli/commands/sandbox.py +92 -0
  22. caraer_cli/commands/skill.py +165 -0
  23. caraer_cli/commands/webhooks.py +68 -0
  24. caraer_cli/completion.py +77 -0
  25. caraer_cli/completion_callbacks.py +162 -0
  26. caraer_cli/context.py +41 -0
  27. caraer_cli/errors.py +84 -0
  28. caraer_cli/formatters/__init__.py +1 -0
  29. caraer_cli/formatters/output.py +381 -0
  30. caraer_cli/formatters/timestamps.py +98 -0
  31. caraer_cli/install_completion.py +38 -0
  32. caraer_cli/local_app.py +135 -0
  33. caraer_cli/main.py +104 -0
  34. caraer_cli/models/__init__.py +1 -0
  35. caraer_cli/models/api.py +52 -0
  36. caraer_cli/project/__init__.py +17 -0
  37. caraer_cli/project/app_bars_sync.py +154 -0
  38. caraer_cli/project/app_manifest_template.py +68 -0
  39. caraer_cli/project/inbound_sync.py +192 -0
  40. caraer_cli/project/json_schemas.py +66 -0
  41. caraer_cli/project/lifecycle_sync.py +119 -0
  42. caraer_cli/project/local_dev.py +825 -0
  43. caraer_cli/project/manifest_edit.py +51 -0
  44. caraer_cli/project/marketplace_assemble.py +165 -0
  45. caraer_cli/project/oauth_providers_sync.py +180 -0
  46. caraer_cli/project/paths.py +102 -0
  47. caraer_cli/project/pricing_sync.py +81 -0
  48. caraer_cli/project/push_plan.py +590 -0
  49. caraer_cli/project/release.py +128 -0
  50. caraer_cli/project/scaffold.py +537 -0
  51. caraer_cli/project/schedules_sync.py +170 -0
  52. caraer_cli/project/schema.py +160 -0
  53. caraer_cli/project/settings_sync.py +77 -0
  54. caraer_cli/project/state.py +51 -0
  55. caraer_cli/project/sync.py +308 -0
  56. caraer_cli/project/typegen.py +278 -0
  57. caraer_cli/project/validate_app.py +1215 -0
  58. caraer_cli/project/webhooks_sync.py +233 -0
  59. caraer_cli/resolve.py +55 -0
  60. caraer_cli/schemas/app.caraer.schema.json +175 -0
  61. caraer_cli/schemas/function.caraer.schema.json +29 -0
  62. caraer_cli/schemas/inbound.caraer.schema.json +49 -0
  63. caraer_cli/schemas/lifecycle.caraer.schema.json +50 -0
  64. caraer_cli/schemas/schedule.caraer.schema.json +39 -0
  65. caraer_cli/schemas/webhook.caraer.schema.json +50 -0
  66. caraer_cli/skills/.gitkeep +2 -0
  67. caraer_cli/skills/caraer-apps/SKILL.md +172 -0
  68. caraer_cli/skills/caraer-apps/reference.md +163 -0
  69. caraer_cli/state/__init__.py +1 -0
  70. caraer_cli/state/config.py +148 -0
  71. caraer_cli/state/session.py +98 -0
  72. caraer_cli/utils.py +40 -0
  73. caraer_cli/wizard/__init__.py +9 -0
  74. caraer_cli/wizard/catalog.py +170 -0
  75. caraer_cli/wizard/marketplace.py +350 -0
  76. caraer_cli/wizard/prompts.py +99 -0
  77. caraer_cli/wizard/public_app.py +519 -0
  78. caraer_cli/wizard/scope_macros.py +214 -0
  79. caraer_cli-0.1.2.dist-info/METADATA +266 -0
  80. caraer_cli-0.1.2.dist-info/RECORD +83 -0
  81. caraer_cli-0.1.2.dist-info/WHEEL +4 -0
  82. caraer_cli-0.1.2.dist-info/entry_points.txt +2 -0
  83. caraer_cli-0.1.2.dist-info/licenses/LICENSE +8 -0
@@ -0,0 +1,233 @@
1
+ """Sync webhooks between src/app/webhooks/*.json and the remote API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from caraer_cli.api import webhooks as webhook_api
11
+ from caraer_cli.api.client import CaraerApiClient
12
+ from caraer_cli.project.paths import webhooks_dir
13
+ from caraer_cli.project.schema import ProjectConfig
14
+ from caraer_cli.project.state import load_state, save_state
15
+
16
+ LOCAL_WEBHOOK_KEYS = (
17
+ "uuid",
18
+ "topic",
19
+ "deliveryMode",
20
+ "webhookFormat",
21
+ "description",
22
+ "url",
23
+ "serverlessFunction",
24
+ "enabled",
25
+ )
26
+
27
+
28
+ def _slug(value: str) -> str:
29
+ text = value.strip().lower()
30
+ text = re.sub(r"[^a-z0-9]+", "-", text)
31
+ return text.strip("-") or "webhook"
32
+
33
+
34
+ def webhook_filename(item: dict[str, Any]) -> str:
35
+ topic = str(item.get("topic") or "webhook")
36
+ mode = str(item.get("deliveryMode") or "").lower()
37
+ uuid = str(item.get("uuid") or "")[:8]
38
+ parts = [_slug(topic)]
39
+ if mode:
40
+ parts.append(_slug(mode))
41
+ if uuid:
42
+ parts.append(uuid)
43
+ return "-".join(parts) + ".json"
44
+
45
+
46
+ def discover_local_webhooks(root: Path, config: ProjectConfig) -> list[tuple[Path, dict[str, Any]]]:
47
+ base = webhooks_dir(root, config.srcDir)
48
+ if not base.is_dir():
49
+ return []
50
+ found: list[tuple[Path, dict[str, Any]]] = []
51
+ for path in sorted(base.glob("*.json")):
52
+ data = json.loads(path.read_text(encoding="utf-8"))
53
+ if isinstance(data, dict):
54
+ found.append((path, data))
55
+ return found
56
+
57
+
58
+ def _sanitize_local_webhook(item: dict[str, Any]) -> dict[str, Any]:
59
+ payload: dict[str, Any] = {}
60
+ for key in LOCAL_WEBHOOK_KEYS:
61
+ if key in item and item[key] is not None:
62
+ payload[key] = item[key]
63
+ # Prefer portable function name over uuid in local files.
64
+ sf = payload.get("serverlessFunction")
65
+ if isinstance(sf, dict):
66
+ name = sf.get("name")
67
+ uuid = sf.get("uuid")
68
+ cleaned: dict[str, Any] = {}
69
+ if name:
70
+ cleaned["name"] = name
71
+ elif uuid:
72
+ cleaned["uuid"] = uuid
73
+ if cleaned:
74
+ payload["serverlessFunction"] = cleaned
75
+ else:
76
+ payload.pop("serverlessFunction", None)
77
+ return payload
78
+
79
+
80
+ def _resolve_serverless_for_api(
81
+ payload: dict[str, Any],
82
+ *,
83
+ fn_by_name: dict[str, str],
84
+ ) -> dict[str, Any]:
85
+ out = dict(payload)
86
+ out.pop("uuid", None) # never send local uuid as create identity unless updating
87
+ sf = out.get("serverlessFunction")
88
+ if not isinstance(sf, dict):
89
+ return out
90
+ if sf.get("uuid"):
91
+ out["serverlessFunction"] = {"uuid": sf["uuid"]}
92
+ return out
93
+ name = sf.get("name")
94
+ if name and name in fn_by_name:
95
+ out["serverlessFunction"] = {"uuid": fn_by_name[name]}
96
+ return out
97
+ if name:
98
+ raise ValueError(
99
+ f"Webhook references function '{name}' but no UUID is known. "
100
+ "Push functions first or set serverlessFunction.uuid."
101
+ )
102
+ return out
103
+
104
+
105
+ def _match_key(item: dict[str, Any]) -> str:
106
+ topic = str(item.get("topic") or "")
107
+ mode = str(item.get("deliveryMode") or "")
108
+ return f"{topic}|{mode}"
109
+
110
+
111
+ def push_webhooks(
112
+ client: CaraerApiClient,
113
+ root: Path,
114
+ config: ProjectConfig,
115
+ *,
116
+ delete_missing: bool = False,
117
+ ) -> dict[str, Any]:
118
+ if not config.appUuid:
119
+ raise ValueError("App has no remote UUID. Run 'caraer apps select' or 'caraer apps push'.")
120
+
121
+ remote = webhook_api.list_webhooks(client, config.appUuid, page=1, limit=200)
122
+ remote_items = [i for i in (remote.get("data") or []) if isinstance(i, dict)]
123
+ by_uuid = {str(i.get("uuid")): i for i in remote_items if i.get("uuid")}
124
+ by_key = {_match_key(i): i for i in remote_items}
125
+
126
+ state = load_state(root)
127
+ fn_state = state.get("functions") or {}
128
+ fn_by_name = {
129
+ name: str(meta["uuid"])
130
+ for name, meta in fn_state.items()
131
+ if isinstance(meta, dict) and meta.get("uuid")
132
+ }
133
+ wh_state: dict[str, Any] = state.setdefault("webhooks", {})
134
+
135
+ results: list[dict[str, Any]] = []
136
+ local_uuids: set[str] = set()
137
+ local_keys: set[str] = set()
138
+
139
+ for path, raw in discover_local_webhooks(root, config):
140
+ local = _sanitize_local_webhook(raw)
141
+ key = _match_key(local)
142
+ local_keys.add(key)
143
+ tracked = wh_state.get(path.stem) or {}
144
+ existing_uuid = str(local.get("uuid") or tracked.get("uuid") or "")
145
+ remote_item = by_uuid.get(existing_uuid) if existing_uuid else by_key.get(key)
146
+
147
+ api_payload = _resolve_serverless_for_api(local, fn_by_name=fn_by_name)
148
+
149
+ if remote_item and remote_item.get("uuid"):
150
+ uuid = str(remote_item["uuid"])
151
+ local_uuids.add(uuid)
152
+ response = webhook_api.update_webhook(client, config.appUuid, uuid, api_payload)
153
+ data = response.get("data") or {}
154
+ results.append({"file": path.name, "uuid": data.get("uuid", uuid), "action": "updated"})
155
+ wh_state[path.stem] = {"uuid": data.get("uuid", uuid), "topic": local.get("topic")}
156
+ else:
157
+ create_payload = {k: v for k, v in api_payload.items() if k != "uuid"}
158
+ response = webhook_api.create_webhook(client, config.appUuid, create_payload)
159
+ data = response.get("data") or {}
160
+ uuid = data.get("uuid")
161
+ if uuid:
162
+ local_uuids.add(str(uuid))
163
+ results.append({"file": path.name, "uuid": uuid, "action": "created"})
164
+ if uuid:
165
+ wh_state[path.stem] = {"uuid": uuid, "topic": local.get("topic")}
166
+ # Persist uuid back into the local file for stable future matches.
167
+ if uuid and not raw.get("uuid"):
168
+ raw["uuid"] = uuid
169
+ path.write_text(json.dumps(_sanitize_local_webhook(raw), indent=2) + "\n", encoding="utf-8")
170
+
171
+ deleted: list[dict[str, Any]] = []
172
+ if delete_missing:
173
+ for item in remote_items:
174
+ uuid = str(item.get("uuid") or "")
175
+ if not uuid or uuid in local_uuids:
176
+ continue
177
+ if _match_key(item) in local_keys:
178
+ continue
179
+ webhook_api.delete_webhook(client, config.appUuid, uuid)
180
+ deleted.append({"uuid": uuid, "topic": item.get("topic"), "action": "deleted"})
181
+ for stem, meta in list(wh_state.items()):
182
+ if isinstance(meta, dict) and meta.get("uuid") == uuid:
183
+ wh_state.pop(stem, None)
184
+
185
+ save_state(root, state)
186
+ return {"webhooks": results, "deleted": deleted}
187
+
188
+
189
+ def pull_webhooks(
190
+ client: CaraerApiClient,
191
+ root: Path,
192
+ config: ProjectConfig,
193
+ ) -> dict[str, Any]:
194
+ if not config.appUuid:
195
+ raise ValueError("App has no remote UUID. Run 'caraer apps select' or 'caraer apps push'.")
196
+
197
+ remote = webhook_api.list_webhooks(client, config.appUuid, page=1, limit=200)
198
+ remote_items = [i for i in (remote.get("data") or []) if isinstance(i, dict)]
199
+ base = webhooks_dir(root, config.srcDir)
200
+ base.mkdir(parents=True, exist_ok=True)
201
+
202
+ # Clear previous webhook files for a clean export.
203
+ for existing in base.glob("*.json"):
204
+ existing.unlink()
205
+
206
+ state = load_state(root)
207
+ fn_state = state.get("functions") or {}
208
+ uuid_to_name = {
209
+ str(meta["uuid"]): name
210
+ for name, meta in fn_state.items()
211
+ if isinstance(meta, dict) and meta.get("uuid")
212
+ }
213
+ wh_state: dict[str, Any] = {}
214
+ pulled: list[dict[str, Any]] = []
215
+
216
+ for item in remote_items:
217
+ local = _sanitize_local_webhook(item)
218
+ sf = local.get("serverlessFunction")
219
+ if isinstance(sf, dict) and sf.get("uuid"):
220
+ name = uuid_to_name.get(str(sf["uuid"]))
221
+ if name:
222
+ local["serverlessFunction"] = {"name": name}
223
+ filename = webhook_filename(item)
224
+ path = base / filename
225
+ path.write_text(json.dumps(local, indent=2) + "\n", encoding="utf-8")
226
+ stem = path.stem
227
+ if item.get("uuid"):
228
+ wh_state[stem] = {"uuid": item["uuid"], "topic": item.get("topic")}
229
+ pulled.append({"file": filename, "uuid": item.get("uuid"), "topic": item.get("topic")})
230
+
231
+ state["webhooks"] = wh_state
232
+ save_state(root, state)
233
+ return {"webhooks": pulled}
caraer_cli/resolve.py ADDED
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from caraer_cli.context import AppContext
6
+ from caraer_cli.local_app import resolve_app_file_path
7
+
8
+
9
+ def resolve_app_uuid(app_ctx: AppContext, app_uuid: str | None) -> str:
10
+ """Resolve a remote app UUID from an explicit arg or the selected profile app."""
11
+ resolved = (app_uuid or "").strip() or (app_ctx.profile.app_uuid or "").strip()
12
+ if not resolved:
13
+ local = (app_ctx.profile.app_file or "").strip()
14
+ hint = (
15
+ f" A local app file is selected ({local}); run 'caraer apps push' "
16
+ "to create it remotely first."
17
+ if local
18
+ else ""
19
+ )
20
+ raise ValueError(
21
+ "No remote app selected. Pass an app UUID, or run "
22
+ "'caraer apps select <uuid>' (after 'caraer apps list')."
23
+ + hint
24
+ )
25
+ return resolved
26
+
27
+
28
+ def resolve_app_file(app_ctx: AppContext, app_file: str | None = None) -> Path:
29
+ """Resolve a local app file from an explicit arg or the selected profile file."""
30
+ resolved = (app_file or "").strip() or (app_ctx.profile.app_file or "").strip()
31
+ if not resolved:
32
+ raise ValueError(
33
+ "No local app file selected. Pass --file, or run "
34
+ "'caraer apps select <uuid|path>' / 'caraer apps pull'."
35
+ )
36
+ return resolve_app_file_path(resolved)
37
+
38
+
39
+ def resolve_optional_file(
40
+ app_ctx: AppContext,
41
+ file: str | None,
42
+ *,
43
+ required_message: str | None = None,
44
+ ) -> Path | None:
45
+ """Resolve --file, falling back to the selected local app file."""
46
+ if file:
47
+ return resolve_app_file_path(file)
48
+ if app_ctx.profile.app_file:
49
+ try:
50
+ return resolve_app_file_path(app_ctx.profile.app_file)
51
+ except (FileNotFoundError, ValueError):
52
+ pass
53
+ if required_message:
54
+ raise ValueError(required_message)
55
+ return None
@@ -0,0 +1,175 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/app.caraer.schema.json",
4
+ "title": "Caraer app manifest (app.caraer.yaml)",
5
+ "type": "object",
6
+ "required": ["name", "label", "authMethod", "details"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "uuid": {
10
+ "type": "string",
11
+ "format": "uuid",
12
+ "description": "Remote app UUID (filled after push)."
13
+ },
14
+ "name": {
15
+ "type": "string",
16
+ "minLength": 1,
17
+ "description": "Stable machine name."
18
+ },
19
+ "label": {
20
+ "type": "string",
21
+ "minLength": 1,
22
+ "description": "Human-readable display name."
23
+ },
24
+ "description": { "type": "string" },
25
+ "runtime": {
26
+ "type": "string",
27
+ "enum": ["nodejs22", "python312"],
28
+ "description": "App-level runtime for platformVersion 2026.2."
29
+ },
30
+ "authMethod": {
31
+ "type": "string",
32
+ "enum": ["OAUTH2", "API_KEY"]
33
+ },
34
+ "oauthRedirectUris": {
35
+ "type": "array",
36
+ "items": { "type": "string", "format": "uri" },
37
+ "description": "Required when authMethod is OAUTH2."
38
+ },
39
+ "requiredScopes": {
40
+ "type": "array",
41
+ "items": { "type": "string" }
42
+ },
43
+ "settingsSchema": {
44
+ "type": "array",
45
+ "items": { "$ref": "#/$defs/settingField" }
46
+ },
47
+ "pricingPlans": {
48
+ "type": "array",
49
+ "items": { "$ref": "#/$defs/pricingPlan" }
50
+ },
51
+ "appBars": {
52
+ "type": "array",
53
+ "items": { "$ref": "#/$defs/appBar" }
54
+ },
55
+ "externalOAuthProviders": {
56
+ "type": "array",
57
+ "items": { "$ref": "#/$defs/oauthProvider" }
58
+ },
59
+ "webhookRateLimitPerMinute": { "type": "integer", "minimum": 0 },
60
+ "billFailedWebhookRequests": { "type": "boolean" },
61
+ "details": {
62
+ "type": "object",
63
+ "required": ["category", "brandColor"],
64
+ "additionalProperties": true,
65
+ "properties": {
66
+ "title": { "type": "string" },
67
+ "description": { "type": "string" },
68
+ "category": {
69
+ "type": "string",
70
+ "description": "Marketplace main category (e.g. developer_tools)."
71
+ },
72
+ "subcategories": {
73
+ "type": "array",
74
+ "items": { "type": "string" }
75
+ },
76
+ "url": { "type": "string", "format": "uri" },
77
+ "image": { "type": "string" },
78
+ "brandColor": {
79
+ "type": "string",
80
+ "pattern": "^#[0-9A-Fa-f]{6}$"
81
+ },
82
+ "textColor": {
83
+ "type": "string",
84
+ "pattern": "^#[0-9A-Fa-f]{6}$"
85
+ }
86
+ }
87
+ }
88
+ },
89
+ "$defs": {
90
+ "settingField": {
91
+ "type": "object",
92
+ "required": ["name", "type"],
93
+ "additionalProperties": true,
94
+ "properties": {
95
+ "name": { "type": "string", "minLength": 1 },
96
+ "label": { "type": "string" },
97
+ "type": {
98
+ "type": "string",
99
+ "enum": [
100
+ "SINGLE_LINE",
101
+ "MULTI_LINE",
102
+ "SINGLE_SELECT",
103
+ "MULTI_SELECT",
104
+ "RECORD_SINGLE_SELECT",
105
+ "RECORD_MULTI_SELECT",
106
+ "OBJECT_SINGLE_SELECT",
107
+ "OBJECT_MULTI_SELECT",
108
+ "PROPERTY_SINGLE_SELECT",
109
+ "PROPERTY_MULTI_SELECT",
110
+ "SWITCH",
111
+ "MAPPING",
112
+ "SECRET"
113
+ ]
114
+ },
115
+ "required": { "type": "boolean" },
116
+ "helpText": { "type": "string" },
117
+ "defaultValue": {},
118
+ "options": { "type": "array" },
119
+ "optionsSource": {}
120
+ }
121
+ },
122
+ "pricingPlan": {
123
+ "type": "object",
124
+ "required": ["pricingType"],
125
+ "additionalProperties": true,
126
+ "properties": {
127
+ "title": { "type": "string" },
128
+ "name": { "type": "string" },
129
+ "description": { "type": "string" },
130
+ "pricingType": { "type": "string", "enum": ["FLAT", "TIERED"] },
131
+ "pricePerUnit": { "type": ["number", "string"] },
132
+ "unit": { "type": "string" },
133
+ "tiers": { "type": "array" }
134
+ }
135
+ },
136
+ "appBar": {
137
+ "type": "object",
138
+ "required": ["location", "label"],
139
+ "additionalProperties": true,
140
+ "properties": {
141
+ "location": {
142
+ "type": "string",
143
+ "enum": [
144
+ "RECORD_PREVIEW",
145
+ "RECORD_OVERVIEW",
146
+ "RECORD_DETAIL",
147
+ "TOOL_BAR",
148
+ "TRAIT_BAR"
149
+ ]
150
+ },
151
+ "label": { "type": "string", "minLength": 1 },
152
+ "actionLabel": { "type": "string" },
153
+ "iframeUrl": { "type": "string" },
154
+ "webhook": { "type": "object" }
155
+ }
156
+ },
157
+ "oauthProvider": {
158
+ "type": "object",
159
+ "required": ["name", "authorizeUrl", "tokenUrl"],
160
+ "additionalProperties": true,
161
+ "properties": {
162
+ "uuid": { "type": "string", "format": "uuid" },
163
+ "name": { "type": "string", "minLength": 1 },
164
+ "authorizeUrl": { "type": "string" },
165
+ "tokenUrl": { "type": "string" },
166
+ "clientId": { "type": "string" },
167
+ "logo": { "type": "string" },
168
+ "scopes": {
169
+ "type": "array",
170
+ "items": { "type": "string" }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/function.caraer.schema.json",
4
+ "title": "Caraer function manifest (function.caraer.json)",
5
+ "type": "object",
6
+ "required": ["name", "runtime"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "minLength": 1,
12
+ "description": "Function name (usually matches the folder name)."
13
+ },
14
+ "runtime": {
15
+ "type": "string",
16
+ "enum": ["nodejs22", "python312"]
17
+ },
18
+ "entry": {
19
+ "type": "string",
20
+ "description": "Entrypoint file; defaults to index.js or main.py."
21
+ },
22
+ "description": { "type": "string" },
23
+ "uuid": {
24
+ "type": "string",
25
+ "format": "uuid",
26
+ "description": "Remote function UUID (filled after push)."
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/inbound.caraer.schema.json",
4
+ "title": "Caraer inbound route config",
5
+ "type": "object",
6
+ "required": ["name", "serverlessFunction"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "uuid": { "type": "string", "format": "uuid" },
10
+ "name": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "description": "Public route name (path segment)."
14
+ },
15
+ "authMode": {
16
+ "type": "string",
17
+ "enum": ["NONE", "SHARED_SECRET", "INSTALLATION_TOKEN"],
18
+ "default": "NONE"
19
+ },
20
+ "sharedSecret": {
21
+ "type": "string",
22
+ "description": "Recommended when authMode is SHARED_SECRET."
23
+ },
24
+ "hasSharedSecret": { "type": "boolean" },
25
+ "enqueue": {
26
+ "type": "boolean",
27
+ "description": "When true, invoke as an installation job."
28
+ },
29
+ "description": { "type": "string" },
30
+ "enabled": { "type": "boolean" },
31
+ "serverlessFunction": {
32
+ "$ref": "#/$defs/serverlessFunctionRef"
33
+ }
34
+ },
35
+ "$defs": {
36
+ "serverlessFunctionRef": {
37
+ "type": "object",
38
+ "additionalProperties": true,
39
+ "properties": {
40
+ "name": { "type": "string" },
41
+ "uuid": { "type": "string", "format": "uuid" }
42
+ },
43
+ "anyOf": [
44
+ { "required": ["name"] },
45
+ { "required": ["uuid"] }
46
+ ]
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/lifecycle.caraer.schema.json",
4
+ "title": "Caraer lifecycle hook config",
5
+ "type": "object",
6
+ "required": ["topic", "deliveryMode"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "topic": {
10
+ "type": "string",
11
+ "enum": [
12
+ "app.installed",
13
+ "app.uninstalled",
14
+ "app.rotated",
15
+ "app.updated"
16
+ ]
17
+ },
18
+ "deliveryMode": {
19
+ "type": "string",
20
+ "enum": ["SERVERLESS", "HTTP"]
21
+ },
22
+ "enabled": { "type": "boolean" },
23
+ "description": { "type": "string" },
24
+ "webhookFormat": { "type": "string" },
25
+ "secret": { "type": "string" },
26
+ "url": {
27
+ "type": "string",
28
+ "format": "uri",
29
+ "description": "Required when deliveryMode is HTTP."
30
+ },
31
+ "serverlessFunction": {
32
+ "$ref": "#/$defs/serverlessFunctionRef",
33
+ "description": "Required when deliveryMode is SERVERLESS."
34
+ }
35
+ },
36
+ "$defs": {
37
+ "serverlessFunctionRef": {
38
+ "type": "object",
39
+ "additionalProperties": true,
40
+ "properties": {
41
+ "name": { "type": "string" },
42
+ "uuid": { "type": "string", "format": "uuid" }
43
+ },
44
+ "anyOf": [
45
+ { "required": ["name"] },
46
+ { "required": ["uuid"] }
47
+ ]
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/schedule.caraer.schema.json",
4
+ "title": "Caraer schedule config",
5
+ "type": "object",
6
+ "required": ["name", "schedule", "serverlessFunction"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "uuid": { "type": "string", "format": "uuid" },
10
+ "name": {
11
+ "type": "string",
12
+ "minLength": 1
13
+ },
14
+ "schedule": {
15
+ "type": "string",
16
+ "minLength": 1,
17
+ "description": "5–6 field cron expression (Spring-style)."
18
+ },
19
+ "enabled": { "type": "boolean" },
20
+ "description": { "type": "string" },
21
+ "serverlessFunction": {
22
+ "$ref": "#/$defs/serverlessFunctionRef"
23
+ }
24
+ },
25
+ "$defs": {
26
+ "serverlessFunctionRef": {
27
+ "type": "object",
28
+ "additionalProperties": true,
29
+ "properties": {
30
+ "name": { "type": "string" },
31
+ "uuid": { "type": "string", "format": "uuid" }
32
+ },
33
+ "anyOf": [
34
+ { "required": ["name"] },
35
+ { "required": ["uuid"] }
36
+ ]
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/caraer/caraer-cli/main/schemas/webhook.caraer.schema.json",
4
+ "title": "Caraer webhook config",
5
+ "type": "object",
6
+ "required": ["topic", "deliveryMode"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "uuid": { "type": "string", "format": "uuid" },
10
+ "topic": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "description": "Event topic (e.g. record.created)."
14
+ },
15
+ "deliveryMode": {
16
+ "type": "string",
17
+ "enum": ["HTTP", "SERVERLESS"]
18
+ },
19
+ "webhookFormat": {
20
+ "type": "string",
21
+ "enum": ["USER_FRIENDLY", "RAW"]
22
+ },
23
+ "description": { "type": "string" },
24
+ "enabled": { "type": "boolean" },
25
+ "url": {
26
+ "type": "string",
27
+ "format": "uri",
28
+ "description": "Required when deliveryMode is HTTP."
29
+ },
30
+ "secret": { "type": "string" },
31
+ "serverlessFunction": {
32
+ "$ref": "#/$defs/serverlessFunctionRef",
33
+ "description": "Required when deliveryMode is SERVERLESS."
34
+ }
35
+ },
36
+ "$defs": {
37
+ "serverlessFunctionRef": {
38
+ "type": "object",
39
+ "additionalProperties": true,
40
+ "properties": {
41
+ "name": { "type": "string" },
42
+ "uuid": { "type": "string", "format": "uuid" }
43
+ },
44
+ "anyOf": [
45
+ { "required": ["name"] },
46
+ { "required": ["uuid"] }
47
+ ]
48
+ }
49
+ }
50
+ }