interlaced 2.8.6__tar.gz → 2.8.7__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 (209) hide show
  1. {interlaced-2.8.6/src/interlaced.egg-info → interlaced-2.8.7}/PKG-INFO +1 -1
  2. {interlaced-2.8.6 → interlaced-2.8.7}/pyproject.toml +1 -1
  3. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/operate.py +3 -2
  4. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/app.py +4 -3
  5. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/lifespan.py +53 -8
  6. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/models.py +7 -1
  7. {interlaced-2.8.6 → interlaced-2.8.7/src/interlaced.egg-info}/PKG-INFO +1 -1
  8. {interlaced-2.8.6 → interlaced-2.8.7}/LICENSE +0 -0
  9. {interlaced-2.8.6 → interlaced-2.8.7}/MANIFEST.in +0 -0
  10. {interlaced-2.8.6 → interlaced-2.8.7}/README.md +0 -0
  11. {interlaced-2.8.6 → interlaced-2.8.7}/setup.cfg +0 -0
  12. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/__init__.py +0 -0
  13. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cdc/__init__.py +0 -0
  14. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cdc/decode.py +0 -0
  15. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cdc/publish.py +0 -0
  16. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cdc/slot.py +0 -0
  17. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/checks/__init__.py +0 -0
  18. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/checks/builtin.py +0 -0
  19. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/checks/runner.py +0 -0
  20. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/checks/spec.py +0 -0
  21. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/__init__.py +0 -0
  22. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/build.py +0 -0
  23. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/inspect.py +0 -0
  24. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/main.py +0 -0
  25. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/cli/support.py +0 -0
  26. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/config/__init__.py +0 -0
  27. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/config/config.py +0 -0
  28. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/connections.py +0 -0
  29. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/contracts.py +0 -0
  30. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/dsl/__init__.py +0 -0
  31. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/dsl/decorators.py +0 -0
  32. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/dsl/discovery.py +0 -0
  33. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/dsl/dynamic.py +0 -0
  34. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/dsl/sql_config.py +0 -0
  35. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/__init__.py +0 -0
  36. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/adbc.py +0 -0
  37. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/base.py +0 -0
  38. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/bigquery.py +0 -0
  39. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/duckdb.py +0 -0
  40. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/postgres.py +0 -0
  41. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/quack.py +0 -0
  42. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/redshift.py +0 -0
  43. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/registry.py +0 -0
  44. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/snowflake.py +0 -0
  45. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/engines/spark.py +0 -0
  46. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/exceptions.py +0 -0
  47. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/graph/__init__.py +0 -0
  48. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/graph/column_lineage.py +0 -0
  49. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/graph/dag.py +0 -0
  50. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/graph/project.py +0 -0
  51. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/graph/selectors.py +0 -0
  52. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/inputs.py +0 -0
  53. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/inspect.py +0 -0
  54. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/__init__.py +0 -0
  55. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/canonicalize.py +0 -0
  56. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/dialect.py +0 -0
  57. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/fingerprint.py +0 -0
  58. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/layout.py +0 -0
  59. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/macros.py +0 -0
  60. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/relation.py +0 -0
  61. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/ir/vars.py +0 -0
  62. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/mcp_server.py +0 -0
  63. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/__init__.py +0 -0
  64. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/changes.py +0 -0
  65. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/ddl.py +0 -0
  66. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/drift.py +0 -0
  67. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/reconcile.py +0 -0
  68. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/physical/spec.py +0 -0
  69. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/__init__.py +0 -0
  70. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/annotate.py +0 -0
  71. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/apply.py +0 -0
  72. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/backfill.py +0 -0
  73. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/comment.py +0 -0
  74. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/delivery.py +0 -0
  75. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/differ.py +0 -0
  76. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/files.py +0 -0
  77. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/fit.py +0 -0
  78. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/orchestrate.py +0 -0
  79. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/payload.py +0 -0
  80. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/plan.py +0 -0
  81. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/resolve.py +0 -0
  82. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/result.py +0 -0
  83. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/run.py +0 -0
  84. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/schedule.py +0 -0
  85. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/table_diff.py +0 -0
  86. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/plan/transfer.py +0 -0
  87. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/project.py +0 -0
  88. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/py.typed +0 -0
  89. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/query.py +0 -0
  90. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/runtime/__init__.py +0 -0
  91. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/runtime/handles.py +0 -0
  92. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/runtime/python_model.py +0 -0
  93. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scaffold.py +0 -0
  94. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/__init__.py +0 -0
  95. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/completion.py +0 -0
  96. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/daemon.py +0 -0
  97. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/engine.py +0 -0
  98. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/triggers.py +0 -0
  99. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/scheduler/worker.py +0 -0
  100. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/__init__.py +0 -0
  101. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/auth.py +0 -0
  102. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/present.py +0 -0
  103. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/__init__.py +0 -0
  104. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/admin.py +0 -0
  105. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/catalog.py +0 -0
  106. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/environments.py +0 -0
  107. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/plan.py +0 -0
  108. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/runs.py +0 -0
  109. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/routes/streams.py +0 -0
  110. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/types.py +0 -0
  111. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/app.css +0 -0
  112. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/favicon.svg +0 -0
  113. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/index.html +0 -0
  114. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/api.js +0 -0
  115. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/app.js +0 -0
  116. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/dag.js +0 -0
  117. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/timeline.js +0 -0
  118. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/ui.js +0 -0
  119. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/checks.js +0 -0
  120. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/environments.js +0 -0
  121. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/lineage.js +0 -0
  122. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/models.js +0 -0
  123. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/overview.js +0 -0
  124. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/plan.js +0 -0
  125. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/query.js +0 -0
  126. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/runs.js +0 -0
  127. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/streams.js +0 -0
  128. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/service/ui/js/views/system.js +0 -0
  129. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/sinks.py +0 -0
  130. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/sources/__init__.py +0 -0
  131. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/sources/auth.py +0 -0
  132. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/sources/rest.py +0 -0
  133. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/__init__.py +0 -0
  134. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/advisory.py +0 -0
  135. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/beat.py +0 -0
  136. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/cdc.py +0 -0
  137. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/checks.py +0 -0
  138. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/codec.py +0 -0
  139. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/conn.py +0 -0
  140. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/events.py +0 -0
  141. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/interval.py +0 -0
  142. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/janitor.py +0 -0
  143. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/keys.py +0 -0
  144. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/locks.py +0 -0
  145. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/pg.py +0 -0
  146. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/queue.py +0 -0
  147. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/schema.py +0 -0
  148. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/snapshot.py +0 -0
  149. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/snapshots.py +0 -0
  150. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/store.py +0 -0
  151. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/state/triggers.py +0 -0
  152. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/__init__.py +0 -0
  153. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/append.py +0 -0
  154. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/base.py +0 -0
  155. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/full_merge.py +0 -0
  156. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/hash_merge.py +0 -0
  157. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/incremental.py +0 -0
  158. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/merge.py +0 -0
  159. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/replace.py +0 -0
  160. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/replace_in_place.py +0 -0
  161. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/scd.py +0 -0
  162. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/strategies/view.py +0 -0
  163. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/streaming/__init__.py +0 -0
  164. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/streaming/log.py +0 -0
  165. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/streaming/materializer.py +0 -0
  166. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/streaming/schema.py +0 -0
  167. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/README.md +0 -0
  168. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/docker-compose.yml +0 -0
  169. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/init/seed.sql +0 -0
  170. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/interlace.yaml +0 -0
  171. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/models/orders.sql +0 -0
  172. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/models/orders_by_status.sql +0 -0
  173. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/models/orders_stream.py +0 -0
  174. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/push.py +0 -0
  175. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/cdc/template.yaml +0 -0
  176. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/README.md +0 -0
  177. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/generate.py +0 -0
  178. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/interlace.yaml +0 -0
  179. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/models/events.py +0 -0
  180. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/models/events_by_minute.sql +0 -0
  181. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/models/events_by_type.sql +0 -0
  182. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/models/top_users.sql +0 -0
  183. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/models/user_spend.sql +0 -0
  184. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/events/template.yaml +0 -0
  185. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/github/README.md +0 -0
  186. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/github/interlace.yaml +0 -0
  187. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/github/models/github_issues.py +0 -0
  188. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/github/models/issues_by_state.sql +0 -0
  189. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/github/template.yaml +0 -0
  190. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/README.md +0 -0
  191. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/docker-compose.yml +0 -0
  192. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/init/seed.sql +0 -0
  193. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/interlace.yaml +0 -0
  194. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/models/orders.py +0 -0
  195. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/models/orders_by_status.sql +0 -0
  196. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/postgres/template.yaml +0 -0
  197. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/README.md +0 -0
  198. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/interlace.yaml +0 -0
  199. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/models/enriched_events.py +0 -0
  200. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/models/event_summary.sql +0 -0
  201. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/models/raw_events.sql +0 -0
  202. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/templates/quickstart/template.yaml +0 -0
  203. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/testing/__init__.py +0 -0
  204. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlace/testing/golden.py +0 -0
  205. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlaced.egg-info/SOURCES.txt +0 -0
  206. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlaced.egg-info/dependency_links.txt +0 -0
  207. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlaced.egg-info/entry_points.txt +0 -0
  208. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlaced.egg-info/requires.txt +0 -0
  209. {interlaced-2.8.6 → interlaced-2.8.7}/src/interlaced.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: interlaced
3
- Version: 2.8.6
3
+ Version: 2.8.7
4
4
  Summary: Python and SQL models in one DAG. Transformation, orchestration and durable streaming in one process, on DuckDB and Postgres.
5
5
  Author-email: Mark <mark@interlace.sh>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "interlaced"
7
- version = "2.8.6"
7
+ version = "2.8.7"
8
8
  description = "Python and SQL models in one DAG. Transformation, orchestration and durable streaming in one process, on DuckDB and Postgres."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -288,7 +288,7 @@ def serve(
288
288
  apply_on_start: bool = typer.Option(
289
289
  True,
290
290
  "--apply/--no-apply",
291
- help="Apply the project once at startup. --no-apply serves the warehouse as it is.",
291
+ help="Apply once at startup, while the API is already listening. --no-apply serves the warehouse as it is.",
292
292
  ),
293
293
  allow_open: bool = typer.Option(
294
294
  False,
@@ -299,7 +299,8 @@ def serve(
299
299
  """Run the interlace daemon: HTTP API + scheduler in one process (requires the `service` extra).
300
300
 
301
301
  Use --no-scheduler for an API-only process (run `interlace scheduler` separately).
302
- The project is applied once before the loops start; pass --no-apply to skip that.
302
+ The API listens immediately. The project is applied once at startup, before the
303
+ scheduler loop; pass --no-apply to skip that. Writes return 503 until the apply finishes.
303
304
  A `cdc:` block in the project config is read here: each Postgres slot appends into its stream.
304
305
  """
305
306
  try:
@@ -19,7 +19,7 @@ from litestar.static_files import create_static_files_router
19
19
  from interlace import __version__
20
20
  from interlace.exceptions import BreakingPlanError, LockError
21
21
  from interlace.service.auth import auth_guard
22
- from interlace.service.lifespan import project_lifespan
22
+ from interlace.service.lifespan import project_lifespan, startup_guard
23
23
  from interlace.service.routes.admin import (
24
24
  delete_apikey,
25
25
  get_apikeys,
@@ -90,7 +90,8 @@ def create_app(
90
90
  ``scheduler=True`` makes this the combined daemon: the HTTP API plus a
91
91
  background scheduler loop (tick triggers, drain the run queue) in one
92
92
  process — the default for ``interlace serve``. ``apply_on_start`` applies the
93
- project once before the loops start; the ``serve`` command turns it on.
93
+ project once while the API is already accepting connections; writes get
94
+ 503 until that apply finishes. The ``serve`` command turns it on.
94
95
  ``quack`` (a
95
96
  ``quack:<host>:<port>`` URI) additionally serves the warehouse over the
96
97
  quack protocol so other processes — CLI runs, ad-hoc DuckDB clients —
@@ -220,7 +221,7 @@ def create_app(
220
221
  stream_events,
221
222
  ],
222
223
  lifespan=[lifespan],
223
- guards=[auth_guard],
224
+ guards=[auth_guard, startup_guard],
224
225
  openapi_config=OpenAPIConfig(
225
226
  title="interlace",
226
227
  version=__version__,
@@ -17,7 +17,9 @@ from pathlib import Path
17
17
  from typing import cast
18
18
 
19
19
  from litestar import Litestar
20
- from litestar.exceptions import ImproperlyConfiguredException
20
+ from litestar.connection import ASGIConnection
21
+ from litestar.exceptions import ImproperlyConfiguredException, ServiceUnavailableException
22
+ from litestar.handlers.base import BaseRouteHandler
21
23
 
22
24
  from interlace.graph.column_lineage import column_lineage
23
25
  from interlace.project import Project
@@ -38,6 +40,21 @@ from interlace.streaming.materializer import (
38
40
  )
39
41
 
40
42
 
43
+ async def startup_guard(connection: ASGIConnection, _route_handler: BaseRouteHandler) -> None:
44
+ """Refuse writes until the startup apply has finished.
45
+
46
+ The socket is open while that apply runs, so a client gets this response
47
+ instead of a refused connection. Reads stay available.
48
+ """
49
+ status = getattr(connection.app.state, "startup_status", "ok")
50
+ if status == "ok" or connection.scope.get("method", "GET") in ("GET", "HEAD", "OPTIONS"):
51
+ return
52
+ if status == "starting":
53
+ raise ServiceUnavailableException(detail="startup apply is still running")
54
+ detail = getattr(connection.app.state, "startup_error", "") or "startup apply failed"
55
+ raise ServiceUnavailableException(detail=detail)
56
+
57
+
41
58
  def project_lifespan( # noqa: C901
42
59
  root: Path | str,
43
60
  environment: str,
@@ -140,6 +157,10 @@ def project_lifespan( # noqa: C901
140
157
 
141
158
  if streams:
142
159
  app.state.flush_wanted.set() # catch up anything durable but unflushed at last shutdown
160
+ # "starting" until the first apply finishes. The socket opens at the yield
161
+ # below, so clients reach /health instead of a refused connection.
162
+ app.state.startup_status = "starting" if apply_on_start else "ok"
163
+ app.state.startup_error = ""
143
164
 
144
165
  async def shutdown_watch() -> None:
145
166
  """End every open SSE stream the moment uvicorn begins shutting down.
@@ -159,16 +180,36 @@ def project_lifespan( # noqa: C901
159
180
  with contextlib.suppress(asyncio.QueueFull):
160
181
  subscriber.put_nowait(None)
161
182
 
162
- if apply_on_start:
163
- await startup_apply(app.state)
183
+ flusher_task: asyncio.Task[None] | None = None
184
+ loop_task: asyncio.Task[None] | None = None
185
+ cdc_task: asyncio.Task[None] | None = None
186
+
187
+ async def open_service() -> None:
188
+ """Apply first, then the loops. The listen socket is already open."""
189
+ nonlocal flusher_task, loop_task, cdc_task
190
+ try:
191
+ if apply_on_start:
192
+ logger.info("startup apply running; the API is accepting connections")
193
+ await startup_apply(app.state)
194
+ app.state.startup_status = "ok"
195
+ except Exception as exc:
196
+ app.state.startup_status = "error"
197
+ app.state.startup_error = str(exc)
198
+ logger.exception("startup apply failed")
199
+ server = getattr(app.state, "uvicorn_server", None)
200
+ if server is not None:
201
+ server.should_exit = True
202
+ return
203
+ if streams:
204
+ flusher_task = asyncio.create_task(flusher_loop(app.state, flush_interval=stream_flush_interval))
205
+ if scheduler:
206
+ loop_task = asyncio.create_task(scheduler_loop(app.state, interval=scheduler_interval))
207
+ if project.config.cdc:
208
+ cdc_task = asyncio.create_task(cdc_loop(app.state))
164
209
 
165
210
  tail_task = asyncio.create_task(event_tail())
166
- flusher_task = (
167
- asyncio.create_task(flusher_loop(app.state, flush_interval=stream_flush_interval)) if streams else None
168
- )
169
- loop_task = asyncio.create_task(scheduler_loop(app.state, interval=scheduler_interval)) if scheduler else None
170
- cdc_task = asyncio.create_task(cdc_loop(app.state)) if project.config.cdc else None
171
211
  watch_task = asyncio.create_task(shutdown_watch())
212
+ service_task = asyncio.create_task(open_service())
172
213
  try:
173
214
  yield
174
215
  finally:
@@ -183,6 +224,10 @@ def project_lifespan( # noqa: C901
183
224
  for subscriber in list(app.state.sse_subscribers):
184
225
  with contextlib.suppress(asyncio.QueueFull):
185
226
  subscriber.put_nowait(None)
227
+ # Stop the opener first so it cannot start a loop after this snapshot.
228
+ service_task.cancel()
229
+ with contextlib.suppress(asyncio.CancelledError, Exception):
230
+ await service_task
186
231
  for task in (cdc_task, loop_task, flusher_task, tail_task, watch_task):
187
232
  if task is not None:
188
233
  task.cancel()
@@ -33,7 +33,13 @@ from interlace.service.types import (
33
33
 
34
34
  @get("/health")
35
35
  async def health(state: State) -> dict[str, str]:
36
- return {"status": "ok", "version": __version__, "environment": state.environment}
36
+ status = getattr(state, "startup_status", "ok")
37
+ body = {"status": status, "version": __version__, "environment": state.environment}
38
+ if status == "starting":
39
+ body["detail"] = "startup apply is still running"
40
+ elif status == "error":
41
+ body["detail"] = getattr(state, "startup_error", "") or "startup apply failed"
42
+ return body
37
43
 
38
44
 
39
45
  @get("/", include_in_schema=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: interlaced
3
- Version: 2.8.6
3
+ Version: 2.8.7
4
4
  Summary: Python and SQL models in one DAG. Transformation, orchestration and durable streaming in one process, on DuckDB and Postgres.
5
5
  Author-email: Mark <mark@interlace.sh>
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes