@treeseed/sdk 0.4.8 → 0.4.10

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 (73) hide show
  1. package/README.md +1 -1
  2. package/dist/control-plane-client.d.ts +45 -0
  3. package/dist/control-plane-client.js +229 -0
  4. package/dist/control-plane.d.ts +94 -0
  5. package/dist/control-plane.js +125 -0
  6. package/dist/d1-store.d.ts +56 -1
  7. package/dist/d1-store.js +132 -0
  8. package/dist/dispatch.d.ts +4 -0
  9. package/dist/dispatch.js +180 -0
  10. package/dist/index.d.ts +14 -2
  11. package/dist/index.js +94 -4
  12. package/dist/operations/services/config-runtime.d.ts +10 -0
  13. package/dist/operations/services/config-runtime.js +62 -4
  14. package/dist/operations/services/deploy.d.ts +95 -3
  15. package/dist/operations/services/deploy.js +351 -10
  16. package/dist/operations/services/github-automation.d.ts +37 -1
  17. package/dist/operations/services/github-automation.js +71 -14
  18. package/dist/operations/services/project-platform.d.ts +835 -0
  19. package/dist/operations/services/project-platform.js +782 -0
  20. package/dist/operations/services/railway-deploy.d.ts +113 -18
  21. package/dist/operations/services/railway-deploy.js +357 -8
  22. package/dist/operations/services/runtime-tools.d.ts +25 -1
  23. package/dist/operations/services/runtime-tools.js +66 -5
  24. package/dist/operations/services/template-registry.d.ts +1 -1
  25. package/dist/operations/services/template-registry.js +17 -3
  26. package/dist/platform/books-data.d.ts +3 -4
  27. package/dist/platform/books-data.js +30 -4
  28. package/dist/platform/contracts.d.ts +56 -4
  29. package/dist/platform/deploy-config.js +109 -4
  30. package/dist/platform/deploy-runtime.d.ts +2 -0
  31. package/dist/platform/deploy-runtime.js +9 -1
  32. package/dist/platform/env.yaml +677 -0
  33. package/dist/platform/environment.js +57 -2
  34. package/dist/platform/plugin.d.ts +8 -0
  35. package/dist/platform/plugins/constants.d.ts +2 -0
  36. package/dist/platform/plugins/constants.js +2 -0
  37. package/dist/platform/plugins/runtime.d.ts +2 -0
  38. package/dist/platform/plugins/runtime.js +9 -1
  39. package/dist/platform/plugins.d.ts +1 -1
  40. package/dist/platform/plugins.js +4 -0
  41. package/dist/platform/published-content-pipeline.d.ts +84 -0
  42. package/dist/platform/published-content-pipeline.js +543 -0
  43. package/dist/platform/published-content.d.ts +223 -0
  44. package/dist/platform/published-content.js +588 -0
  45. package/dist/platform/tenant/runtime-config.d.ts +1 -1
  46. package/dist/platform/tenant/runtime-config.js +34 -1
  47. package/dist/platform/tenant-config.d.ts +2 -1
  48. package/dist/platform/tenant-config.js +17 -1
  49. package/dist/platform/utils/site-config-schema.js +104 -0
  50. package/dist/plugin-default.d.ts +2 -0
  51. package/dist/plugin-default.js +2 -0
  52. package/dist/remote.d.ts +65 -9
  53. package/dist/remote.js +104 -28
  54. package/dist/scripts/check-build-warnings.js +50 -0
  55. package/dist/scripts/config-treeseed.js +7 -0
  56. package/dist/scripts/tenant-workflow-action.js +71 -0
  57. package/dist/sdk-dispatch.d.ts +12 -0
  58. package/dist/sdk-dispatch.js +142 -0
  59. package/dist/sdk-types.d.ts +579 -7
  60. package/dist/sdk-types.js +53 -1
  61. package/dist/sdk.d.ts +17 -1
  62. package/dist/sdk.js +109 -0
  63. package/dist/stores/operational-store.d.ts +22 -2
  64. package/dist/stores/operational-store.js +235 -0
  65. package/dist/template-catalog.js +8 -1
  66. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +20 -0
  67. package/dist/types/cloudflare.d.ts +23 -0
  68. package/dist/workflow/operations.d.ts +12 -3
  69. package/dist/workflow/policy.d.ts +1 -1
  70. package/dist/workflow-state.js +2 -1
  71. package/package.json +7 -2
  72. package/templates/github/deploy.workflow.yml +442 -0
  73. package/templates/github/hosted-project.workflow.yml +77 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.4.8",
3
+ "version": "0.4.10",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -20,7 +20,8 @@
20
20
  "files": [
21
21
  "README.md",
22
22
  "dist",
23
- "scripts/verify-driver.mjs"
23
+ "scripts/verify-driver.mjs",
24
+ "templates"
24
25
  ],
25
26
  "publishConfig": {
26
27
  "access": "public"
@@ -133,6 +134,10 @@
133
134
  "types": "./dist/platform/books-data.d.ts",
134
135
  "default": "./dist/platform/books-data.js"
135
136
  },
137
+ "./platform/published-content": {
138
+ "types": "./dist/platform/published-content.d.ts",
139
+ "default": "./dist/platform/published-content.js"
140
+ },
136
141
  "./platform/book-export": {
137
142
  "types": "./dist/platform/book-export.d.ts",
138
143
  "default": "./dist/platform/book-export.js"
@@ -0,0 +1,442 @@
1
+ name: Treeseed Deploy
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - staging
7
+ - main
8
+ tags:
9
+ - 'v*'
10
+ workflow_dispatch:
11
+ inputs:
12
+ environment:
13
+ description: Target environment
14
+ required: true
15
+ default: staging
16
+ type: choice
17
+ options:
18
+ - staging
19
+ - prod
20
+ action_kind:
21
+ description: Workflow action to perform
22
+ required: true
23
+ default: deploy_code
24
+ type: choice
25
+ options:
26
+ - provision
27
+ - deploy_code
28
+ - publish_content
29
+ - monitor
30
+ project_id:
31
+ description: Treeseed project id for control-plane reporting
32
+ required: false
33
+ type: string
34
+ preview_id:
35
+ description: Optional preview overlay id for editorial publishes
36
+ required: false
37
+ type: string
38
+
39
+ jobs:
40
+ classify:
41
+ runs-on: ubuntu-latest
42
+ outputs:
43
+ scope: ${{ steps.classify.outputs.scope }}
44
+ code_changed: ${{ steps.classify.outputs.code_changed }}
45
+ content_changed: ${{ steps.classify.outputs.content_changed }}
46
+ release_tag: ${{ steps.classify.outputs.release_tag }}
47
+ workflow_action: ${{ steps.classify.outputs.workflow_action }}
48
+ preview_id: ${{ steps.classify.outputs.preview_id }}
49
+ steps:
50
+ - name: Checkout
51
+ uses: actions/checkout@v4
52
+ with:
53
+ fetch-depth: 0
54
+
55
+ - name: Classify changes
56
+ id: classify
57
+ shell: bash
58
+ run: |
59
+ set -euo pipefail
60
+
61
+ if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
62
+ scope="${{ inputs.environment }}"
63
+ workflow_action="${{ inputs.action_kind }}"
64
+ release_tag="false"
65
+ code_changed=$([[ "${workflow_action}" == "deploy_code" ]] && echo "true" || echo "false")
66
+ content_changed=$([[ "${workflow_action}" == "publish_content" ]] && echo "true" || echo "false")
67
+ preview_id="${{ inputs.preview_id }}"
68
+ else
69
+ ref_name="${GITHUB_REF_NAME}"
70
+ ref_type="${GITHUB_REF_TYPE}"
71
+ before_sha="${{ github.event.before }}"
72
+ head_sha="${GITHUB_SHA}"
73
+ workflow_action="auto"
74
+ preview_id="staging-${GITHUB_SHA}"
75
+
76
+ if [[ "${ref_type}" == "tag" ]]; then
77
+ scope="prod"
78
+ release_tag="true"
79
+ compare_ref="$(git rev-list --parents -n 1 "${head_sha}" | awk '{print $2}')"
80
+ elif [[ "${ref_name}" == "main" ]]; then
81
+ scope="prod"
82
+ release_tag="false"
83
+ compare_ref="${before_sha}"
84
+ else
85
+ scope="staging"
86
+ release_tag="false"
87
+ compare_ref="${before_sha}"
88
+ fi
89
+
90
+ if [[ -z "${compare_ref}" || "${compare_ref}" == "0000000000000000000000000000000000000000" ]]; then
91
+ compare_ref="$(git rev-list --max-count=1 "${head_sha}^" 2>/dev/null || true)"
92
+ fi
93
+
94
+ code_changed="false"
95
+ content_changed="false"
96
+
97
+ if [[ -n "${compare_ref}" ]]; then
98
+ while IFS= read -r path; do
99
+ [[ -z "${path}" ]] && continue
100
+ case "${path}" in
101
+ src/content/*|content/*|books/*|docs/*|public/books/*|migrations/*)
102
+ content_changed="true"
103
+ ;;
104
+ *)
105
+ code_changed="true"
106
+ ;;
107
+ esac
108
+ done < <(git diff --name-only "${compare_ref}" "${head_sha}")
109
+ else
110
+ code_changed="true"
111
+ fi
112
+ fi
113
+
114
+ {
115
+ echo "scope=${scope}"
116
+ echo "code_changed=${code_changed}"
117
+ echo "content_changed=${content_changed}"
118
+ echo "release_tag=${release_tag}"
119
+ echo "workflow_action=${workflow_action}"
120
+ echo "preview_id=${preview_id}"
121
+ } >> "${GITHUB_OUTPUT}"
122
+
123
+ verify:
124
+ runs-on: ubuntu-latest
125
+ needs: classify
126
+ if: |
127
+ needs.classify.outputs.workflow_action == 'deploy_code' ||
128
+ needs.classify.outputs.workflow_action == 'publish_content' ||
129
+ needs.classify.outputs.code_changed == 'true' ||
130
+ needs.classify.outputs.content_changed == 'true' ||
131
+ needs.classify.outputs.release_tag == 'true'
132
+ permissions:
133
+ contents: read
134
+ steps:
135
+ - name: Checkout
136
+ uses: actions/checkout@v4
137
+
138
+ - name: Setup Node
139
+ uses: actions/setup-node@v4
140
+ with:
141
+ node-version: 22
142
+ cache: npm
143
+ cache-dependency-path: __CACHE_DEPENDENCY_PATH__
144
+
145
+ - name: Install dependencies
146
+ run: npm ci
147
+
148
+ - name: Verify workspace
149
+ shell: bash
150
+ run: |
151
+ set -euo pipefail
152
+ npm run verify:local 2>&1 | tee verify.log
153
+ if test -f ./packages/sdk/scripts/check-build-warnings.mjs; then
154
+ node ./packages/sdk/scripts/check-build-warnings.mjs verify.log
155
+ elif test -f ./node_modules/@treeseed/sdk/dist/scripts/check-build-warnings.js; then
156
+ node ./node_modules/@treeseed/sdk/dist/scripts/check-build-warnings.js verify.log
157
+ else
158
+ echo "Unable to resolve @treeseed/sdk warning scanner entrypoint."
159
+ exit 1
160
+ fi
161
+ __WORKING_DIRECTORY_BLOCK__
162
+
163
+ provision:
164
+ runs-on: ubuntu-latest
165
+ needs:
166
+ - classify
167
+ - verify
168
+ if: |
169
+ needs.classify.outputs.workflow_action == 'provision' ||
170
+ needs.classify.outputs.workflow_action == 'deploy_code' ||
171
+ needs.classify.outputs.workflow_action == 'publish_content' ||
172
+ needs.classify.outputs.workflow_action == 'monitor' ||
173
+ needs.classify.outputs.code_changed == 'true' ||
174
+ needs.classify.outputs.content_changed == 'true' ||
175
+ needs.classify.outputs.release_tag == 'true'
176
+ permissions:
177
+ contents: read
178
+ deployments: write
179
+ environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
180
+ env:
181
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
182
+ CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
183
+ TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
184
+ TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
185
+ TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
186
+ TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
187
+ TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
188
+ TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
189
+ TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
190
+ TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
191
+ TREESEED_SMTP_HOST: ${{ secrets.TREESEED_SMTP_HOST }}
192
+ TREESEED_SMTP_PORT: ${{ secrets.TREESEED_SMTP_PORT }}
193
+ TREESEED_SMTP_USERNAME: ${{ secrets.TREESEED_SMTP_USERNAME }}
194
+ TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
195
+ TREESEED_SMTP_FROM: ${{ secrets.TREESEED_SMTP_FROM }}
196
+ TREESEED_SMTP_REPLY_TO: ${{ secrets.TREESEED_SMTP_REPLY_TO }}
197
+ RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
198
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
199
+ TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
200
+ TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
201
+ TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
202
+ TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
203
+ TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
204
+ TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
205
+ TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
206
+ TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
207
+ TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
208
+ TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
209
+ TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
210
+ TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
211
+ TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
212
+ TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
213
+ TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
214
+ TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
215
+ TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
216
+ TREESEED_WORKFLOW_ACTION: provision
217
+ TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
218
+ TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
219
+ TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
220
+ steps:
221
+ - name: Checkout
222
+ uses: actions/checkout@v4
223
+
224
+ - name: Setup Node
225
+ uses: actions/setup-node@v4
226
+ with:
227
+ node-version: 22
228
+ cache: npm
229
+ cache-dependency-path: __CACHE_DEPENDENCY_PATH__
230
+
231
+ - name: Install dependencies
232
+ run: npm ci
233
+
234
+ - name: Provision Treeseed platform
235
+ shell: bash
236
+ run: |
237
+ __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
238
+ __WORKING_DIRECTORY_BLOCK__
239
+
240
+ deploy-code:
241
+ runs-on: ubuntu-latest
242
+ needs:
243
+ - classify
244
+ - verify
245
+ - provision
246
+ permissions:
247
+ contents: read
248
+ deployments: write
249
+ if: |
250
+ needs.classify.outputs.workflow_action == 'deploy_code' ||
251
+ needs.classify.outputs.code_changed == 'true' ||
252
+ needs.classify.outputs.release_tag == 'true'
253
+ environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
254
+ env:
255
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
256
+ CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
257
+ TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
258
+ TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
259
+ TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
260
+ TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
261
+ TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
262
+ TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
263
+ TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
264
+ TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
265
+ TREESEED_SMTP_HOST: ${{ secrets.TREESEED_SMTP_HOST }}
266
+ TREESEED_SMTP_PORT: ${{ secrets.TREESEED_SMTP_PORT }}
267
+ TREESEED_SMTP_USERNAME: ${{ secrets.TREESEED_SMTP_USERNAME }}
268
+ TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
269
+ TREESEED_SMTP_FROM: ${{ secrets.TREESEED_SMTP_FROM }}
270
+ TREESEED_SMTP_REPLY_TO: ${{ secrets.TREESEED_SMTP_REPLY_TO }}
271
+ RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
272
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
273
+ TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
274
+ TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
275
+ TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
276
+ TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
277
+ TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
278
+ TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
279
+ TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
280
+ TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
281
+ TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
282
+ TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
283
+ TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
284
+ TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
285
+ TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
286
+ TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
287
+ TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
288
+ TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
289
+ TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
290
+ TREESEED_WORKFLOW_ACTION: deploy_code
291
+ TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
292
+ TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
293
+ TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
294
+ steps:
295
+ - name: Checkout
296
+ uses: actions/checkout@v4
297
+
298
+ - name: Setup Node
299
+ uses: actions/setup-node@v4
300
+ with:
301
+ node-version: 22
302
+ cache: npm
303
+ cache-dependency-path: __CACHE_DEPENDENCY_PATH__
304
+
305
+ - name: Install dependencies
306
+ run: npm ci
307
+
308
+ - name: Deploy Treeseed platform
309
+ shell: bash
310
+ run: |
311
+ __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
312
+ __WORKING_DIRECTORY_BLOCK__
313
+
314
+ publish-content:
315
+ runs-on: ubuntu-latest
316
+ needs:
317
+ - classify
318
+ - verify
319
+ - provision
320
+ - deploy-code
321
+ permissions:
322
+ contents: read
323
+ deployments: write
324
+ if: |
325
+ (needs.classify.outputs.workflow_action == 'publish_content' ||
326
+ needs.classify.outputs.content_changed == 'true') &&
327
+ (needs['deploy-code'].result == 'success' || needs['deploy-code'].result == 'skipped')
328
+ environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
329
+ env:
330
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
331
+ CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
332
+ TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
333
+ TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
334
+ TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
335
+ TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
336
+ TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
337
+ TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
338
+ TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
339
+ TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
340
+ TREESEED_SMTP_HOST: ${{ secrets.TREESEED_SMTP_HOST }}
341
+ TREESEED_SMTP_PORT: ${{ secrets.TREESEED_SMTP_PORT }}
342
+ TREESEED_SMTP_USERNAME: ${{ secrets.TREESEED_SMTP_USERNAME }}
343
+ TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
344
+ TREESEED_SMTP_FROM: ${{ secrets.TREESEED_SMTP_FROM }}
345
+ TREESEED_SMTP_REPLY_TO: ${{ secrets.TREESEED_SMTP_REPLY_TO }}
346
+ RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
347
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
348
+ TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
349
+ TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
350
+ TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
351
+ TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
352
+ TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
353
+ TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
354
+ TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
355
+ TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
356
+ TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
357
+ TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
358
+ TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
359
+ TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
360
+ TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
361
+ TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
362
+ TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
363
+ TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
364
+ TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
365
+ TREESEED_WORKFLOW_ACTION: publish_content
366
+ TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
367
+ TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
368
+ TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
369
+ steps:
370
+ - name: Checkout
371
+ uses: actions/checkout@v4
372
+
373
+ - name: Setup Node
374
+ uses: actions/setup-node@v4
375
+ with:
376
+ node-version: 22
377
+ cache: npm
378
+ cache-dependency-path: __CACHE_DEPENDENCY_PATH__
379
+
380
+ - name: Install dependencies
381
+ run: npm ci
382
+
383
+ - name: Publish Treeseed content
384
+ shell: bash
385
+ run: |
386
+ __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
387
+ __WORKING_DIRECTORY_BLOCK__
388
+
389
+ monitor:
390
+ runs-on: ubuntu-latest
391
+ needs:
392
+ - classify
393
+ - provision
394
+ - deploy-code
395
+ - publish-content
396
+ if: |
397
+ (needs.classify.outputs.workflow_action == 'monitor' ||
398
+ needs.classify.outputs.code_changed == 'true' ||
399
+ needs.classify.outputs.content_changed == 'true' ||
400
+ needs.classify.outputs.release_tag == 'true') &&
401
+ (needs['deploy-code'].result == 'success' || needs['deploy-code'].result == 'skipped') &&
402
+ (needs['publish-content'].result == 'success' || needs['publish-content'].result == 'skipped')
403
+ permissions:
404
+ contents: read
405
+ deployments: write
406
+ environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
407
+ env:
408
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
409
+ CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
410
+ TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
411
+ TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
412
+ RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
413
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
414
+ TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
415
+ TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
416
+ TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
417
+ TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
418
+ TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
419
+ TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
420
+ TREESEED_WORKFLOW_ACTION: monitor
421
+ TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
422
+ TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
423
+ TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
424
+ steps:
425
+ - name: Checkout
426
+ uses: actions/checkout@v4
427
+
428
+ - name: Setup Node
429
+ uses: actions/setup-node@v4
430
+ with:
431
+ node-version: 22
432
+ cache: npm
433
+ cache-dependency-path: __CACHE_DEPENDENCY_PATH__
434
+
435
+ - name: Install dependencies
436
+ run: npm ci
437
+
438
+ - name: Report Treeseed deployment state
439
+ shell: bash
440
+ run: |
441
+ __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
442
+ __WORKING_DIRECTORY_BLOCK__
@@ -0,0 +1,77 @@
1
+ name: Treeseed Hosted Project Orchestration
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tenant_repository:
7
+ description: GitHub owner/name for the hosted project repository
8
+ required: true
9
+ type: string
10
+ tenant_ref:
11
+ description: Branch or tag to dispatch in the tenant repository
12
+ required: true
13
+ type: string
14
+ workflow_file:
15
+ description: Workflow file to dispatch in the tenant repository
16
+ required: false
17
+ default: deploy.yml
18
+ type: string
19
+ project_id:
20
+ description: Treeseed project id recorded in the market control plane
21
+ required: false
22
+ type: string
23
+ environment:
24
+ description: Target environment
25
+ required: true
26
+ default: staging
27
+ type: choice
28
+ options:
29
+ - staging
30
+ - prod
31
+ action_kind:
32
+ description: Requested orchestration action
33
+ required: true
34
+ default: deploy_code
35
+ type: choice
36
+ options:
37
+ - provision
38
+ - deploy_code
39
+ - publish_content
40
+ - monitor
41
+
42
+ jobs:
43
+ dispatch:
44
+ runs-on: ubuntu-latest
45
+ permissions:
46
+ contents: read
47
+ actions: write
48
+ steps:
49
+ - name: Checkout
50
+ uses: actions/checkout@v4
51
+
52
+ - name: Dispatch tenant workflow
53
+ env:
54
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55
+ TENANT_REPOSITORY: ${{ inputs.tenant_repository }}
56
+ TENANT_REF: ${{ inputs.tenant_ref }}
57
+ WORKFLOW_FILE: ${{ inputs.workflow_file }}
58
+ PROJECT_ID: ${{ inputs.project_id }}
59
+ ENVIRONMENT: ${{ inputs.environment }}
60
+ ACTION_KIND: ${{ inputs.action_kind }}
61
+ shell: bash
62
+ run: |
63
+ set -euo pipefail
64
+
65
+ gh api \
66
+ --method POST \
67
+ "/repos/${TENANT_REPOSITORY}/actions/workflows/${WORKFLOW_FILE}/dispatches" \
68
+ -f "ref=${TENANT_REF}" \
69
+ -f "inputs[project_id]=${PROJECT_ID}" \
70
+ -f "inputs[environment]=${ENVIRONMENT}" \
71
+ -f "inputs[action_kind]=${ACTION_KIND}"
72
+
73
+ - name: Emit orchestration summary
74
+ run: |
75
+ echo "Dispatched ${inputs.workflow_file} in ${inputs.tenant_repository}@${inputs.tenant_ref}"
76
+ echo "Action: ${inputs.action_kind}"
77
+ echo "Environment: ${inputs.environment}"