unitysvc-services 0.1.1__py3-none-any.whl → 0.2.0__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.
@@ -27,13 +27,9 @@ class ServiceDataQuery:
27
27
  ValueError: If base_url or api_key is not provided
28
28
  """
29
29
  if not base_url:
30
- raise ValueError(
31
- "Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var."
32
- )
30
+ raise ValueError("UNITYSVC_BASE_URL environment variable not set.")
33
31
  if not api_key:
34
- raise ValueError(
35
- "API key not provided. Use --api-key or set UNITYSVC_API_KEY env var."
36
- )
32
+ raise ValueError("UNITYSVC_API_KEY environment variable not set.")
37
33
 
38
34
  self.base_url = base_url.rstrip("/")
39
35
  self.api_key = api_key
@@ -98,40 +94,22 @@ class ServiceDataQuery:
98
94
  self.close()
99
95
 
100
96
  @staticmethod
101
- def from_env(
102
- backend_url: str | None = None, api_key: str | None = None
103
- ) -> "ServiceDataQuery":
104
- """Create ServiceDataQuery from environment variables or arguments.
105
-
106
- Args:
107
- backend_url: Optional backend URL (falls back to UNITYSVC_BACKEND_URL env var)
108
- api_key: Optional API key (falls back to UNITYSVC_API_KEY env var)
97
+ def from_env() -> "ServiceDataQuery":
98
+ """Create ServiceDataQuery from environment variables.
109
99
 
110
100
  Returns:
111
101
  ServiceDataQuery instance
112
102
 
113
103
  Raises:
114
- ValueError: If required credentials are not provided
104
+ ValueError: If required environment variables are not set
115
105
  """
116
- resolved_backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL") or ""
117
- resolved_api_key = api_key or os.getenv("UNITYSVC_API_KEY") or ""
118
- return ServiceDataQuery(base_url=resolved_backend_url, api_key=resolved_api_key)
106
+ backend_url = os.getenv("UNITYSVC_BASE_URL") or ""
107
+ api_key = os.getenv("UNITYSVC_API_KEY") or ""
108
+ return ServiceDataQuery(base_url=backend_url, api_key=api_key)
119
109
 
120
110
 
121
111
  @app.command("sellers")
122
112
  def query_sellers(
123
- backend_url: str | None = typer.Option(
124
- None,
125
- "--backend-url",
126
- "-u",
127
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
128
- ),
129
- api_key: str | None = typer.Option(
130
- None,
131
- "--api-key",
132
- "-k",
133
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
134
- ),
135
113
  format: str = typer.Option(
136
114
  "table",
137
115
  "--format",
@@ -141,7 +119,7 @@ def query_sellers(
141
119
  ):
142
120
  """Query all sellers from the backend."""
143
121
  try:
144
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
122
+ with ServiceDataQuery.from_env() as query:
145
123
  sellers = query.list_sellers()
146
124
 
147
125
  if format == "json":
@@ -179,18 +157,6 @@ def query_sellers(
179
157
 
180
158
  @app.command("providers")
181
159
  def query_providers(
182
- backend_url: str | None = typer.Option(
183
- None,
184
- "--backend-url",
185
- "-u",
186
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
187
- ),
188
- api_key: str | None = typer.Option(
189
- None,
190
- "--api-key",
191
- "-k",
192
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
193
- ),
194
160
  format: str = typer.Option(
195
161
  "table",
196
162
  "--format",
@@ -200,7 +166,7 @@ def query_providers(
200
166
  ):
201
167
  """Query all providers from the backend."""
202
168
  try:
203
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
169
+ with ServiceDataQuery.from_env() as query:
204
170
  providers = query.list_providers()
205
171
 
206
172
  if format == "json":
@@ -234,18 +200,6 @@ def query_providers(
234
200
 
235
201
  @app.command("offerings")
236
202
  def query_offerings(
237
- backend_url: str | None = typer.Option(
238
- None,
239
- "--backend-url",
240
- "-u",
241
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
242
- ),
243
- api_key: str | None = typer.Option(
244
- None,
245
- "--api-key",
246
- "-k",
247
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
248
- ),
249
203
  format: str = typer.Option(
250
204
  "table",
251
205
  "--format",
@@ -255,7 +209,7 @@ def query_offerings(
255
209
  ):
256
210
  """Query all service offerings from UnitySVC backend."""
257
211
  try:
258
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
212
+ with ServiceDataQuery.from_env() as query:
259
213
  offerings = query.list_service_offerings()
260
214
 
261
215
  if format == "json":
@@ -283,33 +237,17 @@ def query_offerings(
283
237
  )
284
238
 
285
239
  console.print(table)
286
- console.print(
287
- f"\n[green]Total:[/green] {len(offerings)} service offering(s)"
288
- )
240
+ console.print(f"\n[green]Total:[/green] {len(offerings)} service offering(s)")
289
241
  except ValueError as e:
290
242
  console.print(f"[red]✗[/red] {e}", style="bold red")
291
243
  raise typer.Exit(code=1)
292
244
  except Exception as e:
293
- console.print(
294
- f"[red]✗[/red] Failed to query service offerings: {e}", style="bold red"
295
- )
245
+ console.print(f"[red]✗[/red] Failed to query service offerings: {e}", style="bold red")
296
246
  raise typer.Exit(code=1)
297
247
 
298
248
 
299
249
  @app.command("listings")
300
250
  def query_listings(
301
- backend_url: str | None = typer.Option(
302
- None,
303
- "--backend-url",
304
- "-u",
305
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
306
- ),
307
- api_key: str | None = typer.Option(
308
- None,
309
- "--api-key",
310
- "-k",
311
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
312
- ),
313
251
  format: str = typer.Option(
314
252
  "table",
315
253
  "--format",
@@ -319,7 +257,7 @@ def query_listings(
319
257
  ):
320
258
  """Query all service listings from UnitySVC backend."""
321
259
  try:
322
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
260
+ with ServiceDataQuery.from_env() as query:
323
261
  listings = query.list_service_listings()
324
262
 
325
263
  if format == "json":
@@ -336,9 +274,7 @@ def query_listings(
336
274
  table.add_column("Interfaces")
337
275
 
338
276
  for listing in listings:
339
- interfaces_count = len(
340
- listing.get("user_access_interfaces", [])
341
- )
277
+ interfaces_count = len(listing.get("user_access_interfaces", []))
342
278
  table.add_row(
343
279
  str(listing.get("id", "N/A")),
344
280
  str(listing.get("service_id", "N/A")),
@@ -348,33 +284,17 @@ def query_listings(
348
284
  )
349
285
 
350
286
  console.print(table)
351
- console.print(
352
- f"\n[green]Total:[/green] {len(listings)} service listing(s)"
353
- )
287
+ console.print(f"\n[green]Total:[/green] {len(listings)} service listing(s)")
354
288
  except ValueError as e:
355
289
  console.print(f"[red]✗[/red] {e}", style="bold red")
356
290
  raise typer.Exit(code=1)
357
291
  except Exception as e:
358
- console.print(
359
- f"[red]✗[/red] Failed to query service listings: {e}", style="bold red"
360
- )
292
+ console.print(f"[red]✗[/red] Failed to query service listings: {e}", style="bold red")
361
293
  raise typer.Exit(code=1)
362
294
 
363
295
 
364
296
  @app.command("interfaces")
365
297
  def query_interfaces(
366
- backend_url: str | None = typer.Option(
367
- None,
368
- "--backend-url",
369
- "-u",
370
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
371
- ),
372
- api_key: str | None = typer.Option(
373
- None,
374
- "--api-key",
375
- "-k",
376
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
377
- ),
378
298
  format: str = typer.Option(
379
299
  "table",
380
300
  "--format",
@@ -384,7 +304,7 @@ def query_interfaces(
384
304
  ):
385
305
  """Query all access interfaces from UnitySVC backend (private endpoint)."""
386
306
  try:
387
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
307
+ with ServiceDataQuery.from_env() as query:
388
308
  data = query.list_access_interfaces()
389
309
 
390
310
  if format == "json":
@@ -413,33 +333,17 @@ def query_interfaces(
413
333
  )
414
334
 
415
335
  console.print(table)
416
- console.print(
417
- f"\n[green]Total:[/green] {data.get('count', 0)} access interface(s)"
418
- )
336
+ console.print(f"\n[green]Total:[/green] {data.get('count', 0)} access interface(s)")
419
337
  except ValueError as e:
420
338
  console.print(f"[red]✗[/red] {e}", style="bold red")
421
339
  raise typer.Exit(code=1)
422
340
  except Exception as e:
423
- console.print(
424
- f"[red]✗[/red] Failed to query access interfaces: {e}", style="bold red"
425
- )
341
+ console.print(f"[red]✗[/red] Failed to query access interfaces: {e}", style="bold red")
426
342
  raise typer.Exit(code=1)
427
343
 
428
344
 
429
345
  @app.command("documents")
430
346
  def query_documents(
431
- backend_url: str | None = typer.Option(
432
- None,
433
- "--backend-url",
434
- "-u",
435
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
436
- ),
437
- api_key: str | None = typer.Option(
438
- None,
439
- "--api-key",
440
- "-k",
441
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
442
- ),
443
347
  format: str = typer.Option(
444
348
  "table",
445
349
  "--format",
@@ -449,7 +353,7 @@ def query_documents(
449
353
  ):
450
354
  """Query all documents from UnitySVC backend (private endpoint)."""
451
355
  try:
452
- with ServiceDataQuery.from_env(backend_url, api_key) as query:
356
+ with ServiceDataQuery.from_env() as query:
453
357
  data = query.list_documents()
454
358
 
455
359
  if format == "json":
@@ -478,9 +382,7 @@ def query_documents(
478
382
  )
479
383
 
480
384
  console.print(table)
481
- console.print(
482
- f"\n[green]Total:[/green] {data.get('count', 0)} document(s)"
483
- )
385
+ console.print(f"\n[green]Total:[/green] {data.get('count', 0)} document(s)")
484
386
  except ValueError as e:
485
387
  console.print(f"[red]✗[/red] {e}", style="bold red")
486
388
  raise typer.Exit(code=1)
@@ -1,6 +1,5 @@
1
1
  """Update command group - update local data files."""
2
2
 
3
- import os
4
3
  from pathlib import Path
5
4
  from typing import Any
6
5
 
@@ -46,7 +45,7 @@ def update_offering(
46
45
  None,
47
46
  "--data-dir",
48
47
  "-d",
49
- help="Directory containing data files (default: ./data or UNITYSVC_DATA_DIR env var)",
48
+ help="Directory containing data files (default: current directory)",
50
49
  ),
51
50
  ):
52
51
  """
@@ -83,11 +82,7 @@ def update_offering(
83
82
 
84
83
  # Set data directory
85
84
  if data_dir is None:
86
- data_dir_str = os.getenv("UNITYSVC_DATA_DIR")
87
- if data_dir_str:
88
- data_dir = Path(data_dir_str)
89
- else:
90
- data_dir = Path.cwd() / "data"
85
+ data_dir = Path.cwd()
91
86
 
92
87
  if not data_dir.is_absolute():
93
88
  data_dir = Path.cwd() / data_dir
@@ -181,7 +176,7 @@ def update_listing(
181
176
  None,
182
177
  "--data-dir",
183
178
  "-d",
184
- help="Directory containing data files (default: ./data or UNITYSVC_DATA_DIR env var)",
179
+ help="Directory containing data files (default: current directory)",
185
180
  ),
186
181
  ):
187
182
  """
@@ -227,11 +222,7 @@ def update_listing(
227
222
 
228
223
  # Set data directory
229
224
  if data_dir is None:
230
- data_dir_str = os.getenv("UNITYSVC_DATA_DIR")
231
- if data_dir_str:
232
- data_dir = Path(data_dir_str)
233
- else:
234
- data_dir = Path.cwd() / "data"
225
+ data_dir = Path.cwd()
235
226
 
236
227
  if not data_dir.is_absolute():
237
228
  data_dir = Path.cwd() / data_dir
@@ -56,9 +56,7 @@ def write_data_file(file_path: Path, data: dict[str, Any], format: str) -> None:
56
56
 
57
57
 
58
58
  @lru_cache(maxsize=128)
59
- def find_data_files(
60
- data_dir: Path, extensions: tuple[str, ...] | None = None
61
- ) -> list[Path]:
59
+ def find_data_files(data_dir: Path, extensions: tuple[str, ...] | None = None) -> list[Path]:
62
60
  """
63
61
  Find all data files in a directory with specified extensions.
64
62
 
@@ -208,9 +206,7 @@ def resolve_provider_name(file_path: Path) -> str | None:
208
206
  return None
209
207
 
210
208
 
211
- def resolve_service_name_for_listing(
212
- listing_file: Path, listing_data: dict[str, Any]
213
- ) -> str | None:
209
+ def resolve_service_name_for_listing(listing_file: Path, listing_data: dict[str, Any]) -> str | None:
214
210
  """
215
211
  Resolve the service name for a listing file.
216
212
 
@@ -1,7 +1,6 @@
1
1
  """Data validation module for unitysvc_services."""
2
2
 
3
3
  import json
4
- import os
5
4
  import re
6
5
  import tomllib as toml
7
6
  from pathlib import Path
@@ -60,16 +59,12 @@ class DataValidator:
60
59
  if "anyOf" in obj:
61
60
  any_of = obj["anyOf"]
62
61
  # Count non-null items for the check
63
- non_null_items = [
64
- item for item in any_of if item.get("type") != "null"
65
- ]
62
+ non_null_items = [item for item in any_of if item.get("type") != "null"]
66
63
  has_plain_string = any(
67
- item.get("type") == "string" and "format" not in item
68
- for item in non_null_items
64
+ item.get("type") == "string" and "format" not in item for item in non_null_items
69
65
  )
70
66
  has_uri_string = any(
71
- item.get("type") == "string" and item.get("format") == "uri"
72
- for item in non_null_items
67
+ item.get("type") == "string" and item.get("format") == "uri" for item in non_null_items
73
68
  )
74
69
 
75
70
  # Check for Union[str, HttpUrl] or Union[str, HttpUrl, None]
@@ -84,9 +79,7 @@ class DataValidator:
84
79
 
85
80
  # Check other schema structures
86
81
  for key, value in obj.items():
87
- if key not in ["properties", "anyOf"] and isinstance(
88
- value, dict | list
89
- ):
82
+ if key not in ["properties", "anyOf"] and isinstance(value, dict | list):
90
83
  traverse_schema(value, path)
91
84
 
92
85
  elif isinstance(obj, list):
@@ -96,9 +89,7 @@ class DataValidator:
96
89
  traverse_schema(schema)
97
90
  return union_fields
98
91
 
99
- def validate_file_references(
100
- self, data: dict[str, Any], file_path: Path, union_fields: set[str]
101
- ) -> list[str]:
92
+ def validate_file_references(self, data: dict[str, Any], file_path: Path, union_fields: set[str]) -> list[str]:
102
93
  """
103
94
  Validate that file references in Union[str, HttpUrl] fields exist.
104
95
 
@@ -120,9 +111,7 @@ class DataValidator:
120
111
  ):
121
112
  # Empty string is not a valid file reference
122
113
  if value == "":
123
- errors.append(
124
- f"Empty string in field '{new_path}' is not a valid file reference or URL"
125
- )
114
+ errors.append(f"Empty string in field '{new_path}' is not a valid file reference or URL")
126
115
  # It's a file reference, must be relative path
127
116
  elif Path(value).is_absolute():
128
117
  errors.append(
@@ -172,9 +161,7 @@ class DataValidator:
172
161
  check_field(data, str(file_path))
173
162
  return errors
174
163
 
175
- def validate_name_consistency(
176
- self, data: dict[str, Any], file_path: Path, schema_name: str
177
- ) -> list[str]:
164
+ def validate_name_consistency(self, data: dict[str, Any], file_path: Path, schema_name: str) -> list[str]:
178
165
  """Validate that the name field matches the directory name."""
179
166
  errors: list[str] = []
180
167
 
@@ -199,9 +186,7 @@ class DataValidator:
199
186
  elif file_path.name in ["service.json", "service.toml"]:
200
187
  # For service.json, the service directory should match the service name
201
188
  service_directory_name = file_path.parent.name
202
- if self._normalize_name(name_value) != self._normalize_name(
203
- service_directory_name
204
- ):
189
+ if self._normalize_name(name_value) != self._normalize_name(service_directory_name):
205
190
  normalized_name = self._normalize_name(name_value)
206
191
  errors.append(
207
192
  f"Service name '{name_value}' does not match "
@@ -220,9 +205,7 @@ class DataValidator:
220
205
  normalized = normalized.strip("-")
221
206
  return normalized
222
207
 
223
- def load_data_file(
224
- self, file_path: Path
225
- ) -> tuple[dict[str, Any] | None, list[str]]:
208
+ def load_data_file(self, file_path: Path) -> tuple[dict[str, Any] | None, list[str]]:
226
209
  """Load data from JSON or TOML file."""
227
210
  errors: list[str] = []
228
211
 
@@ -237,9 +220,7 @@ class DataValidator:
237
220
  return None, [f"Unsupported file format: {file_path.suffix}"]
238
221
  return data, errors
239
222
  except Exception as e:
240
- format_name = {".json": "JSON", ".toml": "TOML"}.get(
241
- file_path.suffix, "data"
242
- )
223
+ format_name = {".json": "JSON", ".toml": "TOML"}.get(file_path.suffix, "data")
243
224
  return None, [f"Failed to parse {format_name}: {e}"]
244
225
 
245
226
  def validate_data_file(self, file_path: Path) -> tuple[bool, list[str]]:
@@ -268,17 +249,13 @@ class DataValidator:
268
249
 
269
250
  # Validate against schema with format checking enabled
270
251
  try:
271
- validator = Draft7Validator(
272
- schema, format_checker=Draft7Validator.FORMAT_CHECKER
273
- )
252
+ validator = Draft7Validator(schema, format_checker=Draft7Validator.FORMAT_CHECKER)
274
253
  validator.check_schema(schema) # Validate the schema itself
275
254
  validation_errors = list(validator.iter_errors(data))
276
255
  for error in validation_errors:
277
256
  errors.append(f"Schema validation error: {error.message}")
278
257
  if error.absolute_path:
279
- errors.append(
280
- f" Path: {'.'.join(str(p) for p in error.absolute_path)}"
281
- )
258
+ errors.append(f" Path: {'.'.join(str(p) for p in error.absolute_path)}")
282
259
  except Exception as e:
283
260
  errors.append(f"Validation error: {e}")
284
261
 
@@ -346,9 +323,7 @@ class DataValidator:
346
323
  "No seller file found. Each repository must have exactly one data file using the 'seller_v1' schema."
347
324
  )
348
325
  elif len(seller_files) > 1:
349
- errors.append(
350
- f"Found {len(seller_files)} seller files, but only one is allowed per repository:"
351
- )
326
+ errors.append(f"Found {len(seller_files)} seller files, but only one is allowed per repository:")
352
327
  for seller_file in seller_files:
353
328
  errors.append(f" - {seller_file}")
354
329
 
@@ -400,9 +375,7 @@ class DataValidator:
400
375
  )
401
376
 
402
377
  except Exception as e:
403
- warnings.append(
404
- f"Error checking provider status in {provider_file}: {e}"
405
- )
378
+ warnings.append(f"Error checking provider status in {provider_file}: {e}")
406
379
 
407
380
  # Return True (valid) but with warnings
408
381
  return True, warnings
@@ -525,9 +498,7 @@ class DataValidator:
525
498
  if schema == "service_v1":
526
499
  service_name = data.get("name")
527
500
  if not service_name:
528
- raise DataValidationError(
529
- f"Service file {file_path} missing 'name' field"
530
- )
501
+ raise DataValidationError(f"Service file {file_path} missing 'name' field")
531
502
 
532
503
  # Check for duplicate service names in same directory
533
504
  if service_name in services:
@@ -555,9 +526,7 @@ class DataValidator:
555
526
  if service_name:
556
527
  # If service_name is explicitly defined, it must match a service in the directory
557
528
  if service_name not in services:
558
- available_services = (
559
- ", ".join(services.keys()) if services else "none"
560
- )
529
+ available_services = ", ".join(services.keys()) if services else "none"
561
530
  raise DataValidationError(
562
531
  f"Listing file {listing_file} references service_name '{service_name}' "
563
532
  f"which does not exist in the same directory.\n"
@@ -621,7 +590,7 @@ console = Console()
621
590
  def validate(
622
591
  data_dir: Path | None = typer.Argument(
623
592
  None,
624
- help="Directory containing data files to validate (default: ./data or UNITYSVC_DATA_DIR env var)",
593
+ help="Directory containing data files to validate (default: current directory)",
625
594
  ),
626
595
  ):
627
596
  """
@@ -634,11 +603,7 @@ def validate(
634
603
  """
635
604
  # Determine data directory
636
605
  if data_dir is None:
637
- data_dir_str = os.environ.get("UNITYSVC_DATA_DIR")
638
- if data_dir_str:
639
- data_dir = Path(data_dir_str)
640
- else:
641
- data_dir = Path.cwd() / "data"
606
+ data_dir = Path.cwd()
642
607
 
643
608
  if not data_dir.exists():
644
609
  console.print(f"[red]✗[/red] Data directory not found: {data_dir}")
@@ -668,9 +633,7 @@ def validate(
668
633
  validation_errors.extend(directory_errors)
669
634
 
670
635
  if validation_errors:
671
- console.print(
672
- f"[red]✗ Validation failed with {len(validation_errors)} error(s):[/red]"
673
- )
636
+ console.print(f"[red]✗ Validation failed with {len(validation_errors)} error(s):[/red]")
674
637
  console.print()
675
638
  for i, error in enumerate(validation_errors, 1):
676
639
  console.print(f"[red]{i}.[/red] {error}")
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unitysvc-services
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: SDK for digital service providers on UnitySVC
5
5
  Author-email: Bo Peng <bo.peng@unitysvc.com>
6
6
  Maintainer-email: Bo Peng <bo.peng@unitysvc.com>
7
- License: MIT
7
+ License-Expression: MIT
8
8
  Project-URL: bugs, https://github.com/unitysvc/unitysvc-services/issues
9
9
  Project-URL: changelog, https://github.com/unitysvc/unitysvc-services/blob/master/changelog.md
10
10
  Project-URL: homepage, https://github.com/unitysvc/unitysvc-services
@@ -53,11 +53,11 @@ Client library and CLI tools for digital service providers to interact with the
53
53
 
54
54
  UnitySVC Provider SDK enables digital service providers to manage their service offerings through a **local-first, version-controlled workflow**:
55
55
 
56
- - **Define** service data using schema-validated files (JSON/TOML)
57
- - **Manage** everything locally in git-controlled directories
58
- - **Validate** data against schemas before publishing
59
- - **Publish** to UnitySVC platform when ready
60
- - **Automate** with populate scripts for dynamic catalogs
56
+ - **Define** service data using schema-validated files (JSON/TOML)
57
+ - **Manage** everything locally in git-controlled directories
58
+ - **Validate** data against schemas before publishing
59
+ - **Publish** to UnitySVC platform when ready
60
+ - **Automate** with populate scripts for dynamic catalogs
61
61
 
62
62
  ## Installation
63
63
 
@@ -79,14 +79,13 @@ unitysvc_services init seller my-marketplace
79
79
  unitysvc_services validate
80
80
  unitysvc_services format
81
81
 
82
- # Publish to platform
83
- export UNITYSVC_BACKEND_URL="https://api.unitysvc.com/api/v1"
82
+ # Publish to platform (publishes all: sellers, providers, offerings, listings)
83
+ export UNITYSVC_BASE_URL="https://api.unitysvc.com/api/v1"
84
84
  export UNITYSVC_API_KEY="your-api-key"
85
+ unitysvc_services publish
85
86
 
87
+ # Or publish specific types only
86
88
  unitysvc_services publish providers
87
- unitysvc_services publish sellers
88
- unitysvc_services publish offerings
89
- unitysvc_services publish listings
90
89
 
91
90
  # Verify
92
91
  unitysvc_services query offerings
@@ -94,12 +93,12 @@ unitysvc_services query offerings
94
93
 
95
94
  ## Key Features
96
95
 
97
- - 📋 **Pydantic Models** - Type-safe data models for all entities
98
- - ✅ **Data Validation** - Comprehensive schema validation
99
- - 🔄 **Local-First** - Work offline, commit to git, publish when ready
100
- - 🚀 **CLI Tools** - Complete command-line interface
101
- - 🤖 **Automation** - Script-based service generation
102
- - 📝 **Multiple Formats** - Support for JSON and TOML
96
+ - 📋 **Pydantic Models** - Type-safe data models for all entities
97
+ - ✅ **Data Validation** - Comprehensive schema validation
98
+ - 🔄 **Local-First** - Work offline, commit to git, publish when ready
99
+ - 🚀 **CLI Tools** - Complete command-line interface
100
+ - 🤖 **Automation** - Script-based service generation
101
+ - 📝 **Multiple Formats** - Support for JSON and TOML
103
102
 
104
103
  ## Workflows
105
104
 
@@ -135,34 +134,34 @@ See [Data Structure Documentation](https://unitysvc-services.readthedocs.io/en/l
135
134
 
136
135
  ## CLI Commands
137
136
 
138
- | Command | Description |
139
- |---------|-------------|
140
- | `init` | Initialize new data files from schemas |
141
- | `list` | List local data files |
142
- | `query` | Query backend API for published data |
143
- | `publish` | Publish data to backend |
144
- | `update` | Update local file fields |
145
- | `validate` | Validate data consistency |
146
- | `format` | Format data files |
147
- | `populate` | Execute provider populate scripts |
137
+ | Command | Description |
138
+ | ---------- | -------------------------------------- |
139
+ | `init` | Initialize new data files from schemas |
140
+ | `list` | List local data files |
141
+ | `query` | Query backend API for published data |
142
+ | `publish` | Publish data to backend |
143
+ | `update` | Update local file fields |
144
+ | `validate` | Validate data consistency |
145
+ | `format` | Format data files |
146
+ | `populate` | Execute provider populate scripts |
148
147
 
149
148
  Run `unitysvc_services --help` or see [CLI Reference](https://unitysvc-services.readthedocs.io/en/latest/cli-reference/) for complete documentation.
150
149
 
151
150
  ## Documentation
152
151
 
153
- - **[Getting Started](https://unitysvc-services.readthedocs.io/en/latest/getting-started/)** - Installation and first steps
154
- - **[Data Structure](https://unitysvc-services.readthedocs.io/en/latest/data-structure/)** - File organization rules
155
- - **[Workflows](https://unitysvc-services.readthedocs.io/en/latest/workflows/)** - Manual and automated patterns
156
- - **[CLI Reference](https://unitysvc-services.readthedocs.io/en/latest/cli-reference/)** - All commands and options
157
- - **[File Schemas](https://unitysvc-services.readthedocs.io/en/latest/file-schemas/)** - Schema specifications
158
- - **[Python API](https://unitysvc-services.readthedocs.io/en/latest/api-reference/)** - Programmatic usage
152
+ - **[Getting Started](https://unitysvc-services.readthedocs.io/en/latest/getting-started/)** - Installation and first steps
153
+ - **[Data Structure](https://unitysvc-services.readthedocs.io/en/latest/data-structure/)** - File organization rules
154
+ - **[Workflows](https://unitysvc-services.readthedocs.io/en/latest/workflows/)** - Manual and automated patterns
155
+ - **[CLI Reference](https://unitysvc-services.readthedocs.io/en/latest/cli-reference/)** - All commands and options
156
+ - **[File Schemas](https://unitysvc-services.readthedocs.io/en/latest/file-schemas/)** - Schema specifications
157
+ - **[Python API](https://unitysvc-services.readthedocs.io/en/latest/api-reference/)** - Programmatic usage
159
158
 
160
159
  ## Links
161
160
 
162
- - **PyPI**: https://pypi.org/project/unitysvc-services/
163
- - **Documentation**: https://unitysvc-services.readthedocs.io
164
- - **Source Code**: https://github.com/unitysvc/unitysvc-services
165
- - **Issue Tracker**: https://github.com/unitysvc/unitysvc-services/issues
161
+ - **PyPI**: https://pypi.org/project/unitysvc-services/
162
+ - **Documentation**: https://unitysvc-services.readthedocs.io
163
+ - **Source Code**: https://github.com/unitysvc/unitysvc-services
164
+ - **Issue Tracker**: https://github.com/unitysvc/unitysvc-services/issues
166
165
 
167
166
  ## License
168
167