fastapi-spawn 0.4.9__tar.gz → 0.4.12__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 (70) hide show
  1. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/PKG-INFO +42 -8
  2. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/README.md +41 -7
  3. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/__init__.py +1 -1
  4. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/cli.py +20 -4
  5. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/constants.py +6 -2
  6. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/generator.py +2 -1
  7. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/auth/sso.py.j2 +48 -3
  8. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/env.j2 +21 -0
  9. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/env_example.j2 +41 -0
  10. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/pyproject.toml.j2 +4 -0
  11. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/pyproject.toml +1 -1
  12. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/.gitignore +0 -0
  13. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/LICENSE +0 -0
  14. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/config.py +0 -0
  15. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/interactive.py +0 -0
  16. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/alembic/alembic.ini.j2 +0 -0
  17. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/alembic/env.py.j2 +0 -0
  18. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/__init__.py.j2 +0 -0
  19. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/deps.py.j2 +0 -0
  20. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/graphql.py.j2 +0 -0
  21. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/auth/router.py.j2 +0 -0
  22. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/health/router.py.j2 +0 -0
  23. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/payments/router.py.j2 +0 -0
  24. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/router.py.j2 +0 -0
  25. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/streaming/router.py.j2 +0 -0
  26. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/api/v1/ws/router.py.j2 +0 -0
  27. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/ai.py.j2 +0 -0
  28. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/config.py.j2 +0 -0
  29. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/email.py.j2 +0 -0
  30. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/exceptions.py.j2 +0 -0
  31. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/logger.py.j2 +0 -0
  32. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/logging.py.j2 +0 -0
  33. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/monitoring.py.j2 +0 -0
  34. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/notifications.py.j2 +0 -0
  35. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/ocr.py.j2 +0 -0
  36. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/search.py.j2 +0 -0
  37. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/security.py.j2 +0 -0
  38. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/storage.py.j2 +0 -0
  39. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/vector_db.py.j2 +0 -0
  40. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/core/ws_manager.py.j2 +0 -0
  41. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/db/session.py.j2 +0 -0
  42. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/frontend/index.html.j2 +0 -0
  43. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/main.py.j2 +0 -0
  44. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/middleware/__init__.py.j2 +0 -0
  45. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/middleware/rate_limit.py.j2 +0 -0
  46. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/app/middleware/request_logger.py.j2 +0 -0
  47. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/Makefile.j2 +0 -0
  48. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/README.md.j2 +0 -0
  49. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/gitignore.j2 +0 -0
  50. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/base/pre_commit.j2 +0 -0
  51. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/ci/github/publish.yml.j2 +0 -0
  52. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/ci/github/tests.yml.j2 +0 -0
  53. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/ci/gitlab/gitlab-ci.yml.j2 +0 -0
  54. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/db/seed.py.j2 +0 -0
  55. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/docker/Dockerfile.j2 +0 -0
  56. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/docker/docker-compose.yml.j2 +0 -0
  57. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/docker/dockerignore.j2 +0 -0
  58. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/infra/docker/docker-compose.prod.yml.j2 +0 -0
  59. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/infra/helm/Chart.yaml.j2 +0 -0
  60. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/infra/helm/values.yaml.j2 +0 -0
  61. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/infra/terraform/main.tf.j2 +0 -0
  62. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/infra/terraform/variables.tf.j2 +0 -0
  63. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/root/main.py.j2 +0 -0
  64. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/tasks/arq_worker.py.j2 +0 -0
  65. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/tasks/celery_app.py.j2 +0 -0
  66. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/tasks/sample_tasks.py.j2 +0 -0
  67. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/tests/conftest.py.j2 +0 -0
  68. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/templates/tests/test_health.py.j2 +0 -0
  69. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/utils.py +0 -0
  70. {fastapi_spawn-0.4.9 → fastapi_spawn-0.4.12}/fastapi_spawn/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-spawn
3
- Version: 0.4.9
3
+ Version: 0.4.12
4
4
  Summary: A powerful CLI tool to scaffold production-ready FastAPI projects with flexible database, auth, broker, and deployment options.
5
5
  Project-URL: Homepage, https://github.com/Bishwajitgarai/fastapi-spawn
6
6
  Project-URL: Documentation, https://github.com/Bishwajitgarai/fastapi-spawn#readme
@@ -381,6 +381,10 @@ SMTP_SSL=false
381
381
  # ── AWS SES ──────────────────────────────────────────────────────────────
382
382
  SES_FROM_EMAIL=noreply@example.com # uses AWS_* credentials above
383
383
 
384
+ # ── Resend ───────────────────────────────────────────────────────────────
385
+ RESEND_API_KEY=re_placeholder
386
+ RESEND_FROM_EMAIL=noreply@example.com
387
+
384
388
  # ── Slack ────────────────────────────────────────────────────────────────
385
389
  SLACK_WEBHOOK_URL=https://hooks.slack.com/services/CHANGE_ME
386
390
 
@@ -402,6 +406,31 @@ ELASTICSEARCH_HOST=localhost
402
406
  ELASTICSEARCH_PORT=9200
403
407
  ELASTICSEARCH_API_KEY=
404
408
  # → assembled as: http://HOST:PORT
409
+
410
+ # ── OpenSearch ───────────────────────────────────────────────────────────
411
+ OPENSEARCH_HOST=localhost
412
+ OPENSEARCH_PORT=9200
413
+ OPENSEARCH_USER=admin
414
+ OPENSEARCH_PASSWORD=admin
415
+
416
+ # ── Vespa ────────────────────────────────────────────────────────────────
417
+ VESPA_ENDPOINT=http://localhost:8080
418
+
419
+ # ── Extras (Stripe, SSO, Meilisearch) ────────────────────────────────────
420
+ STRIPE_API_KEY=sk_test_placeholder
421
+ STRIPE_WEBHOOK_SECRET=whsec_placeholder
422
+
423
+ GOOGLE_CLIENT_ID=placeholder
424
+ GOOGLE_CLIENT_SECRET=placeholder
425
+
426
+ GITHUB_CLIENT_ID=placeholder
427
+ GITHUB_CLIENT_SECRET=placeholder
428
+
429
+ MICROSOFT_CLIENT_ID=placeholder
430
+ MICROSOFT_CLIENT_SECRET=placeholder
431
+
432
+ MEILISEARCH_HOST=http://localhost:7700
433
+ MEILISEARCH_API_KEY=masterKey
405
434
  ```
406
435
 
407
436
  > All variables are assembled into connection URLs inside `app/core/config.py` via `@property`. Your code always reads from structured fields — never a fragile connection string.
@@ -450,12 +479,12 @@ Did you generate a minimal project and now realize you need WebSockets, AWS S3,
450
479
  fastapi-spawn add [FEATURE]
451
480
  ```
452
481
 
453
- ### How it works:
454
- 1. **Generates the Module**: It creates the necessary file (e.g., `app/core/ai.py` or `app/api/v1/ws/router.py`) tailored to your project structure.
455
- 2. **Environment Variables**: It prompts you with the exact environment variables you need to append to your `.env` and `config.py`.
456
- 3. **Integration Guide**: It outputs a step-by-step UI snippet telling you *exactly* where to import and mount the new feature in your `main.py` or `router.py`.
482
+ Or you can add them at creation time with the `--extra` flag:
483
+ ```bash
484
+ fastapi-spawn new my_app --extra stripe --extra sso --extra seed
485
+ ```
457
486
 
458
- ### All Possibilities you can `add`:
487
+ ### All Possibilities you can `add` or `--extra`:
459
488
 
460
489
  You can run any of the following commands inside an existing project:
461
490
 
@@ -474,11 +503,16 @@ fastapi-spawn add qdrant # Qdrant vector DB
474
503
  fastapi-spawn add chroma # ChromaDB local vector DB
475
504
  fastapi-spawn add pinecone # Pinecone cloud vector DB
476
505
  fastapi-spawn add meilisearch # Meilisearch typo-tolerant search
506
+ fastapi-spawn add opensearch # OpenSearch vector & text search
507
+ fastapi-spawn add vespa # Vespa big data serving engine
477
508
  fastapi-spawn add ocr # PDF & OCR data extraction pipeline
478
509
 
479
510
  # Payments & Identity
480
511
  fastapi-spawn add stripe # Stripe payments & webhooks
481
- fastapi-spawn add sso # FastAPI SSO (Google/GitHub login)
512
+ fastapi-spawn add sso # FastAPI SSO (Google, GitHub, Microsoft)
513
+ fastapi-spawn add sso-google # FastAPI SSO (Google only)
514
+ fastapi-spawn add sso-github # FastAPI SSO (GitHub only)
515
+ fastapi-spawn add sso-microsoft # FastAPI SSO (Microsoft only)
482
516
 
483
517
  # Messaging & Async Workers
484
518
  fastapi-spawn add celery # Celery worker + tasks/
@@ -490,7 +524,7 @@ fastapi-spawn add sse # Server-Sent Events streaming
490
524
  fastapi-spawn add s3 # AWS S3 / MinIO storage
491
525
  fastapi-spawn add graphql # Strawberry GraphQL schema
492
526
  fastapi-spawn add alembic # Alembic async migrations
493
- fastapi-spawn add seed # Faker database seeding script
527
+ fastapi-spawn add seed # Faker database seeding script (Users, Posts, Comments)
494
528
  fastapi-spawn add resend # Resend modern email client
495
529
  fastapi-spawn add sentry # Sentry APM integration
496
530
  fastapi-spawn add prometheus # Prometheus metrics
@@ -340,6 +340,10 @@ SMTP_SSL=false
340
340
  # ── AWS SES ──────────────────────────────────────────────────────────────
341
341
  SES_FROM_EMAIL=noreply@example.com # uses AWS_* credentials above
342
342
 
343
+ # ── Resend ───────────────────────────────────────────────────────────────
344
+ RESEND_API_KEY=re_placeholder
345
+ RESEND_FROM_EMAIL=noreply@example.com
346
+
343
347
  # ── Slack ────────────────────────────────────────────────────────────────
344
348
  SLACK_WEBHOOK_URL=https://hooks.slack.com/services/CHANGE_ME
345
349
 
@@ -361,6 +365,31 @@ ELASTICSEARCH_HOST=localhost
361
365
  ELASTICSEARCH_PORT=9200
362
366
  ELASTICSEARCH_API_KEY=
363
367
  # → assembled as: http://HOST:PORT
368
+
369
+ # ── OpenSearch ───────────────────────────────────────────────────────────
370
+ OPENSEARCH_HOST=localhost
371
+ OPENSEARCH_PORT=9200
372
+ OPENSEARCH_USER=admin
373
+ OPENSEARCH_PASSWORD=admin
374
+
375
+ # ── Vespa ────────────────────────────────────────────────────────────────
376
+ VESPA_ENDPOINT=http://localhost:8080
377
+
378
+ # ── Extras (Stripe, SSO, Meilisearch) ────────────────────────────────────
379
+ STRIPE_API_KEY=sk_test_placeholder
380
+ STRIPE_WEBHOOK_SECRET=whsec_placeholder
381
+
382
+ GOOGLE_CLIENT_ID=placeholder
383
+ GOOGLE_CLIENT_SECRET=placeholder
384
+
385
+ GITHUB_CLIENT_ID=placeholder
386
+ GITHUB_CLIENT_SECRET=placeholder
387
+
388
+ MICROSOFT_CLIENT_ID=placeholder
389
+ MICROSOFT_CLIENT_SECRET=placeholder
390
+
391
+ MEILISEARCH_HOST=http://localhost:7700
392
+ MEILISEARCH_API_KEY=masterKey
364
393
  ```
365
394
 
366
395
  > All variables are assembled into connection URLs inside `app/core/config.py` via `@property`. Your code always reads from structured fields — never a fragile connection string.
@@ -409,12 +438,12 @@ Did you generate a minimal project and now realize you need WebSockets, AWS S3,
409
438
  fastapi-spawn add [FEATURE]
410
439
  ```
411
440
 
412
- ### How it works:
413
- 1. **Generates the Module**: It creates the necessary file (e.g., `app/core/ai.py` or `app/api/v1/ws/router.py`) tailored to your project structure.
414
- 2. **Environment Variables**: It prompts you with the exact environment variables you need to append to your `.env` and `config.py`.
415
- 3. **Integration Guide**: It outputs a step-by-step UI snippet telling you *exactly* where to import and mount the new feature in your `main.py` or `router.py`.
441
+ Or you can add them at creation time with the `--extra` flag:
442
+ ```bash
443
+ fastapi-spawn new my_app --extra stripe --extra sso --extra seed
444
+ ```
416
445
 
417
- ### All Possibilities you can `add`:
446
+ ### All Possibilities you can `add` or `--extra`:
418
447
 
419
448
  You can run any of the following commands inside an existing project:
420
449
 
@@ -433,11 +462,16 @@ fastapi-spawn add qdrant # Qdrant vector DB
433
462
  fastapi-spawn add chroma # ChromaDB local vector DB
434
463
  fastapi-spawn add pinecone # Pinecone cloud vector DB
435
464
  fastapi-spawn add meilisearch # Meilisearch typo-tolerant search
465
+ fastapi-spawn add opensearch # OpenSearch vector & text search
466
+ fastapi-spawn add vespa # Vespa big data serving engine
436
467
  fastapi-spawn add ocr # PDF & OCR data extraction pipeline
437
468
 
438
469
  # Payments & Identity
439
470
  fastapi-spawn add stripe # Stripe payments & webhooks
440
- fastapi-spawn add sso # FastAPI SSO (Google/GitHub login)
471
+ fastapi-spawn add sso # FastAPI SSO (Google, GitHub, Microsoft)
472
+ fastapi-spawn add sso-google # FastAPI SSO (Google only)
473
+ fastapi-spawn add sso-github # FastAPI SSO (GitHub only)
474
+ fastapi-spawn add sso-microsoft # FastAPI SSO (Microsoft only)
441
475
 
442
476
  # Messaging & Async Workers
443
477
  fastapi-spawn add celery # Celery worker + tasks/
@@ -449,7 +483,7 @@ fastapi-spawn add sse # Server-Sent Events streaming
449
483
  fastapi-spawn add s3 # AWS S3 / MinIO storage
450
484
  fastapi-spawn add graphql # Strawberry GraphQL schema
451
485
  fastapi-spawn add alembic # Alembic async migrations
452
- fastapi-spawn add seed # Faker database seeding script
486
+ fastapi-spawn add seed # Faker database seeding script (Users, Posts, Comments)
453
487
  fastapi-spawn add resend # Resend modern email client
454
488
  fastapi-spawn add sentry # Sentry APM integration
455
489
  fastapi-spawn add prometheus # Prometheus metrics
@@ -1,6 +1,6 @@
1
1
  """fastapi-spawn — Production-ready FastAPI project scaffolding CLI."""
2
2
 
3
- __version__ = "0.4.9"
3
+ __version__ = "0.4.12"
4
4
  __author__ = "Bishwajit Garai"
5
5
  __email__ = "bishwajitgarai@gmail.com"
6
6
  __license__ = "MIT"
@@ -62,6 +62,14 @@ def version_callback(value: bool) -> None:
62
62
  raise typer.Exit()
63
63
 
64
64
 
65
+ @app.command("help", help="Show this help message and exit.")
66
+ def show_help(ctx: typer.Context) -> None:
67
+ """Print the global CLI help."""
68
+ # We leverage Click's internal help formatting to render the same as --help
69
+ rprint(ctx.parent.get_help())
70
+
71
+
72
+
65
73
  # ── `new` command ──────────────────────────────────────────────────────────────
66
74
 
67
75
  @app.command("new", help="Create a new FastAPI project.")
@@ -278,8 +286,6 @@ _ADDABLE_FEATURES = {
278
286
  "opentelemetry": "OpenTelemetry distributed tracing",
279
287
  "sendgrid": "SendGrid email",
280
288
  "smtp": "SMTP email (fastapi-mail)",
281
- "ses": "AWS SES email",
282
- "resend": "Resend email client (modern React/HTML emails)",
283
289
  "slack": "Slack webhook notifications",
284
290
  "discord": "Discord webhook notifications",
285
291
  "qdrant": "Qdrant vector database",
@@ -287,11 +293,16 @@ _ADDABLE_FEATURES = {
287
293
  "pinecone": "Pinecone managed vector database",
288
294
  "elasticsearch": "Elasticsearch KNN search",
289
295
  "meilisearch": "Meilisearch ultra-fast typo-tolerant search",
296
+ "opensearch": "OpenSearch vector and text search",
297
+ "vespa": "Vespa big data serving engine",
290
298
  "websockets": "WebSocket connection manager + endpoints",
291
299
  "sse": "Server-Sent Events (SSE) streaming endpoint",
292
300
  "graphql": "Strawberry GraphQL schema + subscriptions",
293
301
  "stripe": "Stripe payments & webhook signature validation",
294
- "sso": "FastAPI SSO (Login with Google / GitHub)",
302
+ "sso": "FastAPI SSO (Google, GitHub, Microsoft)",
303
+ "sso-google": "FastAPI SSO (Google only)",
304
+ "sso-github": "FastAPI SSO (GitHub only)",
305
+ "sso-microsoft": "FastAPI SSO (Microsoft only)",
295
306
  "seed": "Database seeding script using Faker",
296
307
  "ocr": "PDF & OCR data pipeline (PyMuPDF / Tesseract)",
297
308
  "docker": "Dockerfile + docker-compose.yml",
@@ -356,11 +367,16 @@ def _feature_guidance(feature: str, _project_dir: Path) -> None:
356
367
  "pinecone": ["Add dep: pinecone-client>=3.2.0", "Create app/core/vector_db.py", "Add to .env: PINECONE_API_KEY, PINECONE_INDEX_NAME"],
357
368
  "elasticsearch": ["Add dep: elasticsearch[async]>=8.13.0", "Create app/core/vector_db.py (kNN search)", "Add to .env: ELASTICSEARCH_HOST, ELASTICSEARCH_PORT, ELASTICSEARCH_API_KEY"],
358
369
  "meilisearch": ["Add dep: meilisearch>=0.30.0", "Create app/core/search.py (Meilisearch client)", "Add to .env: MEILISEARCH_HOST=http://localhost:7700, MEILISEARCH_API_KEY"],
370
+ "opensearch": ["Add dep: opensearch-py[async]>=2.5.0", "Create app/core/search.py (OpenSearch client)", "Add to .env: OPENSEARCH_HOST, OPENSEARCH_PORT, OPENSEARCH_USER, OPENSEARCH_PASSWORD"],
371
+ "vespa": ["Add dep: pyvespa>=0.40.0", "Create app/core/search.py (Vespa client)", "Add to .env: VESPA_ENDPOINT"],
359
372
  "websockets":["No extra dep (built into FastAPI)", "Create app/core/ws_manager.py (ConnectionManager)", "Create app/api/v1/ws/router.py — /ws/connect, /ws/connect/{room_id}"],
360
373
  "sse": ["Add dep: sse-starlette>=2.1.0", "Create app/api/v1/streaming/router.py", "Return EventSourceResponse(async_generator)"],
361
374
  "graphql": ["Add dep: strawberry-graphql[fastapi]>=0.227.0", "Create app/api/graphql.py (Query + Mutation + Subscription)", "Mount: app.include_router(graphql_router, prefix='/graphql')"],
362
375
  "stripe": ["Add dep: stripe>=9.0.0", "Create app/api/v1/payments/router.py (webhook endpoint)", "Add to .env: STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET"],
363
- "sso": ["Add dep: fastapi-sso>=0.14.0", "Create app/api/v1/auth/sso.py (GoogleSSO / GithubSSO)", "Add to .env: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET"],
376
+ "sso": ["Add dep: fastapi-sso>=0.14.0", "Create app/api/v1/auth/sso.py (Google/Github/Microsoft SSO)", "Add to .env: GOOGLE_CLIENT_ID, GITHUB_CLIENT_ID, etc."],
377
+ "sso-google": ["1. Use 'fastapi-spawn new temp_app --extra sso-google' and copy the resulting sso.py"],
378
+ "sso-github": ["1. Use 'fastapi-spawn new temp_app --extra sso-github' and copy the resulting sso.py"],
379
+ "sso-microsoft": ["1. Use 'fastapi-spawn new temp_app --extra sso-microsoft' and copy the resulting sso.py"],
364
380
  "seed": ["Add dep: faker>=25.0.0", "Create db/seed.py (generate 100 mock users/posts)", "Run: uv run python db/seed.py"],
365
381
  "ocr": ["Add deps: pymupdf>=1.24.0, pytesseract>=0.3.10", "Create app/core/ocr.py (PDF parsing pipeline)", "Install system deps: sudo apt install tesseract-ocr"],
366
382
  "docker": ["Create Dockerfile (multi-stage, uv-based)", "Create docker-compose.yml with all selected services", "Create .dockerignore"],
@@ -128,6 +128,8 @@ class VectorDB(str, Enum):
128
128
  pinecone = "pinecone"
129
129
  supabase = "supabase" # pgvector on Supabase
130
130
  elasticsearch = "elasticsearch"
131
+ opensearch = "opensearch"
132
+ vespa = "vespa"
131
133
  none = "none"
132
134
 
133
135
 
@@ -256,8 +258,10 @@ VECTOR_DB_LABELS = {
256
258
  VectorDB.qdrant: "Qdrant — local Docker or Qdrant Cloud",
257
259
  VectorDB.chroma: "ChromaDB — local open-source vector DB",
258
260
  VectorDB.pinecone: "Pinecone — managed cloud",
259
- VectorDB.supabase: "Supabase pgvector",
260
- VectorDB.elasticsearch: "Elasticsearch — kNN search",
261
+ VectorDB.supabase: "Supabase (pgvector)",
262
+ VectorDB.elasticsearch: "Elasticsearch",
263
+ VectorDB.opensearch: "OpenSearch",
264
+ VectorDB.vespa: "Vespa",
261
265
  VectorDB.none: "No vector database",
262
266
  }
263
267
 
@@ -216,7 +216,8 @@ class ProjectGenerator:
216
216
  self._render_to(v1 / "payments" / "router.py", "app/api/v1/payments/router.py.j2")
217
217
  self._render_to(v1 / "payments" / "__init__.py", "app/__init__.py.j2")
218
218
 
219
- if "sso" in extras:
219
+ has_sso = any(e.startswith("sso") for e in extras)
220
+ if has_sso:
220
221
  (v1 / "auth").mkdir(parents=True, exist_ok=True)
221
222
  self._render_to(v1 / "auth" / "sso.py", "app/api/v1/auth/sso.py.j2")
222
223
 
@@ -1,10 +1,11 @@
1
1
  from fastapi import APIRouter, Request, HTTPException
2
- from fastapi_sso.sso.google import GoogleSSO
3
- from fastapi_sso.sso.github import GithubSSO
4
2
  from app.core.config import settings
5
3
 
6
4
  router = APIRouter(prefix="/sso", tags=["auth"])
7
5
 
6
+ {% if "sso-google" in extras or "sso" in extras %}
7
+ from fastapi_sso.sso.google import GoogleSSO
8
+
8
9
  # Requires GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in .env
9
10
  google_sso = GoogleSSO(
10
11
  client_id=getattr(settings, "GOOGLE_CLIENT_ID", "placeholder"),
@@ -27,7 +28,6 @@ async def google_callback(request: Request):
27
28
  if not user:
28
29
  raise HTTPException(status_code=400, detail="Failed to login via Google")
29
30
 
30
- # TODO: Create or update user in database, then generate and return JWT
31
31
  return {
32
32
  "id": user.id,
33
33
  "email": user.email,
@@ -36,6 +36,10 @@ async def google_callback(request: Request):
36
36
  "picture": user.picture,
37
37
  "provider": "google"
38
38
  }
39
+ {% endif %}
40
+
41
+ {% if "sso-github" in extras or "sso" in extras %}
42
+ from fastapi_sso.sso.github import GithubSSO
39
43
 
40
44
  # --- GitHub SSO ---
41
45
 
@@ -69,3 +73,44 @@ async def github_callback(request: Request):
69
73
  "picture": getattr(user, "picture", None),
70
74
  "provider": "github"
71
75
  }
76
+ {% endif %}
77
+
78
+ {% if "sso-microsoft" in extras or "sso" in extras %}
79
+ from fastapi_sso.sso.microsoft import MicrosoftSSO
80
+
81
+ # --- Microsoft SSO ---
82
+
83
+ # Requires MICROSOFT_CLIENT_ID and MICROSOFT_CLIENT_SECRET in .env
84
+ microsoft_sso = MicrosoftSSO(
85
+ client_id=getattr(settings, "MICROSOFT_CLIENT_ID", "placeholder"),
86
+ client_secret=getattr(settings, "MICROSOFT_CLIENT_SECRET", "placeholder"),
87
+ tenant="common", # Or your specific tenant ID
88
+ redirect_uri="http://localhost:8000/api/v1/auth/sso/microsoft/callback",
89
+ allow_insecure_http=True, # Set to False in production
90
+ )
91
+
92
+ @router.get("/microsoft/login")
93
+ async def microsoft_login():
94
+ """Redirects the user to the Microsoft login page."""
95
+ with microsoft_sso:
96
+ return await microsoft_sso.get_login_redirect()
97
+
98
+ @router.get("/microsoft/callback")
99
+ async def microsoft_callback(request: Request):
100
+ """Process login response from Microsoft and return user info."""
101
+ with microsoft_sso:
102
+ user = await microsoft_sso.verify_and_process(request)
103
+ if not user:
104
+ raise HTTPException(status_code=400, detail="Failed to login via Microsoft")
105
+
106
+ return {
107
+ "id": user.id,
108
+ "email": user.email,
109
+ "first_name": getattr(user, "first_name", None),
110
+ "last_name": getattr(user, "last_name", None),
111
+ "picture": getattr(user, "picture", None),
112
+ "provider": "microsoft"
113
+ }
114
+ {% endif %}
115
+
116
+
@@ -80,3 +80,24 @@ OPENAI_BASE_URL= # leave blank for api.openai.com; set fo
80
80
  ANTHROPIC_API_KEY=sk-ant-placeholder
81
81
  ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
82
82
  {% endif %}
83
+ {% if extras %}
84
+ {% if "stripe" in extras %}
85
+ # Stripe
86
+ STRIPE_API_KEY=sk_test_placeholder
87
+ STRIPE_WEBHOOK_SECRET=whsec_placeholder
88
+ {% endif %}
89
+ {% if "sso" in extras or "sso-google" in extras or "sso-github" in extras or "sso-microsoft" in extras %}
90
+ # SSO (Google, GitHub, Microsoft)
91
+ GOOGLE_CLIENT_ID=placeholder
92
+ GOOGLE_CLIENT_SECRET=placeholder
93
+ GITHUB_CLIENT_ID=placeholder
94
+ GITHUB_CLIENT_SECRET=placeholder
95
+ MICROSOFT_CLIENT_ID=placeholder
96
+ MICROSOFT_CLIENT_SECRET=placeholder
97
+ {% endif %}
98
+ {% if "meilisearch" in extras %}
99
+ # Meilisearch
100
+ MEILISEARCH_HOST=http://localhost:7700
101
+ MEILISEARCH_API_KEY=masterKey
102
+ {% endif %}
103
+ {% endif %}
@@ -229,11 +229,16 @@ SMTP_SSL=false
229
229
  {% elif email == "ses" %}
230
230
  # AWS SES (active) — uses AWS_* credentials above
231
231
  SES_FROM_EMAIL=noreply@example.com
232
+ {% elif email == "resend" %}
233
+ # Resend (active)
234
+ RESEND_API_KEY=re_placeholder
235
+ RESEND_FROM_EMAIL=noreply@example.com
232
236
  {% else %}
233
237
  # Email — uncomment the provider you need:
234
238
  # SendGrid: SENDGRID_API_KEY=SG.placeholder | SENDGRID_FROM_EMAIL=noreply@example.com
235
239
  # SMTP: SMTP_HOST=smtp.gmail.com | SMTP_PORT=587 | SMTP_USER=... | SMTP_PASSWORD=... | SMTP_FROM_EMAIL=... | SMTP_STARTTLS=true | SMTP_SSL=false
236
240
  # AWS SES: SES_FROM_EMAIL=noreply@example.com (uses AWS_* credentials)
241
+ # Resend: RESEND_API_KEY=re_placeholder | RESEND_FROM_EMAIL=noreply@example.com
237
242
  {% endif %}
238
243
 
239
244
  # =============================================================================
@@ -273,6 +278,15 @@ PINECONE_INDEX_NAME={{ slug }}-index
273
278
  ELASTICSEARCH_HOST=localhost
274
279
  ELASTICSEARCH_PORT=9200
275
280
  ELASTICSEARCH_API_KEY=
281
+ {% elif vector_db == "opensearch" %}
282
+ # OpenSearch (active)
283
+ OPENSEARCH_HOST=localhost
284
+ OPENSEARCH_PORT=9200
285
+ OPENSEARCH_USER=admin
286
+ OPENSEARCH_PASSWORD=admin
287
+ {% elif vector_db == "vespa" %}
288
+ # Vespa (active)
289
+ VESPA_ENDPOINT=http://localhost:8080
276
290
  {% else %}
277
291
  # Vector DB — uncomment the provider you need:
278
292
  # Qdrant: QDRANT_HOST=localhost | QDRANT_PORT=6333 | QDRANT_API_KEY= (blank for local)
@@ -280,6 +294,8 @@ ELASTICSEARCH_API_KEY=
280
294
  # Pinecone: PINECONE_API_KEY=CHANGE_ME | PINECONE_INDEX_NAME={{ slug }}-index
281
295
  # Supabase: uses SUPABASE_URL / SUPABASE_KEY above
282
296
  # Elasticsearch: ELASTICSEARCH_HOST=localhost | ELASTICSEARCH_PORT=9200 | ELASTICSEARCH_API_KEY=
297
+ # OpenSearch: OPENSEARCH_HOST=localhost | OPENSEARCH_PORT=9200 | OPENSEARCH_USER=admin | OPENSEARCH_PASSWORD=admin
298
+ # Vespa: VESPA_ENDPOINT=http://localhost:8080
283
299
  {% endif %}
284
300
 
285
301
  # =============================================================================
@@ -298,3 +314,28 @@ DD_SITE=datadoghq.com
298
314
  # Datadog: DD_API_KEY=CHANGE_ME | DD_SITE=datadoghq.com
299
315
  # OpenTelemetry: OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317 (set in compose)
300
316
  {% endif %}
317
+
318
+ # =============================================================================
319
+ # EXTRAS (Payments, SSO, Search)
320
+ # =============================================================================
321
+ {% if extras %}
322
+ {% if "stripe" in extras %}
323
+ # Stripe (active)
324
+ STRIPE_API_KEY=sk_test_placeholder
325
+ STRIPE_WEBHOOK_SECRET=whsec_placeholder
326
+ {% endif %}
327
+ {% if "sso" in extras or "sso-google" in extras or "sso-github" in extras or "sso-microsoft" in extras %}
328
+ # SSO - Google, GitHub, Microsoft (active)
329
+ GOOGLE_CLIENT_ID=placeholder
330
+ GOOGLE_CLIENT_SECRET=placeholder
331
+ GITHUB_CLIENT_ID=placeholder
332
+ GITHUB_CLIENT_SECRET=placeholder
333
+ MICROSOFT_CLIENT_ID=placeholder
334
+ MICROSOFT_CLIENT_SECRET=placeholder
335
+ {% endif %}
336
+ {% if "meilisearch" in extras %}
337
+ # Meilisearch (active)
338
+ MEILISEARCH_HOST=http://localhost:7700
339
+ MEILISEARCH_API_KEY=masterKey
340
+ {% endif %}
341
+ {% endif %}
@@ -111,6 +111,10 @@ dependencies = [
111
111
  "supabase>=2.4.0",
112
112
  {% elif vector_db == "elasticsearch" %}
113
113
  "elasticsearch[async]>=8.13.0",
114
+ {% elif vector_db == "opensearch" %}
115
+ "opensearch-py[async]>=2.5.0",
116
+ {% elif vector_db == "vespa" %}
117
+ "pyvespa>=0.40.0",
114
118
  {% endif %}
115
119
 
116
120
  {% if has_websockets %}
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fastapi-spawn"
7
- version = "0.4.9"
7
+ version = "0.4.12"
8
8
  description = "A powerful CLI tool to scaffold production-ready FastAPI projects with flexible database, auth, broker, and deployment options."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes