@elaraai/e3-cloud-cli 0.0.0-stage → 1.0.90

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 (71) hide show
  1. package/LICENSE.md +54 -0
  2. package/README.md +433 -2
  3. package/dist/src/app-source.d.ts +16 -0
  4. package/dist/src/app-source.d.ts.map +1 -0
  5. package/dist/src/app-source.js +112 -0
  6. package/dist/src/app-source.js.map +1 -0
  7. package/dist/src/cli.d.ts +7 -0
  8. package/dist/src/cli.d.ts.map +1 -0
  9. package/dist/src/cli.js +472 -0
  10. package/dist/src/cli.js.map +1 -0
  11. package/dist/src/commands/app.d.ts +28 -0
  12. package/dist/src/commands/app.d.ts.map +1 -0
  13. package/dist/src/commands/app.js +286 -0
  14. package/dist/src/commands/app.js.map +1 -0
  15. package/dist/src/commands/compute.d.ts +16 -0
  16. package/dist/src/commands/compute.d.ts.map +1 -0
  17. package/dist/src/commands/compute.js +110 -0
  18. package/dist/src/commands/compute.js.map +1 -0
  19. package/dist/src/commands/feedback.d.ts +27 -0
  20. package/dist/src/commands/feedback.d.ts.map +1 -0
  21. package/dist/src/commands/feedback.js +197 -0
  22. package/dist/src/commands/feedback.js.map +1 -0
  23. package/dist/src/commands/records.d.ts +42 -0
  24. package/dist/src/commands/records.d.ts.map +1 -0
  25. package/dist/src/commands/records.js +301 -0
  26. package/dist/src/commands/records.js.map +1 -0
  27. package/dist/src/commands/release.d.ts +39 -0
  28. package/dist/src/commands/release.d.ts.map +1 -0
  29. package/dist/src/commands/release.js +219 -0
  30. package/dist/src/commands/release.js.map +1 -0
  31. package/dist/src/commands/role.d.ts +24 -0
  32. package/dist/src/commands/role.d.ts.map +1 -0
  33. package/dist/src/commands/role.js +94 -0
  34. package/dist/src/commands/role.js.map +1 -0
  35. package/dist/src/commands/schedule.d.ts +18 -0
  36. package/dist/src/commands/schedule.d.ts.map +1 -0
  37. package/dist/src/commands/schedule.js +128 -0
  38. package/dist/src/commands/schedule.js.map +1 -0
  39. package/dist/src/commands/secrets.d.ts +15 -0
  40. package/dist/src/commands/secrets.d.ts.map +1 -0
  41. package/dist/src/commands/secrets.js +82 -0
  42. package/dist/src/commands/secrets.js.map +1 -0
  43. package/dist/src/commands/staging.d.ts +36 -0
  44. package/dist/src/commands/staging.d.ts.map +1 -0
  45. package/dist/src/commands/staging.js +98 -0
  46. package/dist/src/commands/staging.js.map +1 -0
  47. package/dist/src/commands/timeout.d.ts +16 -0
  48. package/dist/src/commands/timeout.d.ts.map +1 -0
  49. package/dist/src/commands/timeout.js +124 -0
  50. package/dist/src/commands/timeout.js.map +1 -0
  51. package/dist/src/commands/user-settings.d.ts +15 -0
  52. package/dist/src/commands/user-settings.d.ts.map +1 -0
  53. package/dist/src/commands/user-settings.js +74 -0
  54. package/dist/src/commands/user-settings.js.map +1 -0
  55. package/dist/src/commands/user.d.ts +26 -0
  56. package/dist/src/commands/user.d.ts.map +1 -0
  57. package/dist/src/commands/user.js +206 -0
  58. package/dist/src/commands/user.js.map +1 -0
  59. package/dist/src/commands/whoami.d.ts +6 -0
  60. package/dist/src/commands/whoami.d.ts.map +1 -0
  61. package/dist/src/commands/whoami.js +38 -0
  62. package/dist/src/commands/whoami.js.map +1 -0
  63. package/dist/src/credentials.d.ts +100 -0
  64. package/dist/src/credentials.d.ts.map +1 -0
  65. package/dist/src/credentials.js +164 -0
  66. package/dist/src/credentials.js.map +1 -0
  67. package/dist/src/utils.d.ts +38 -0
  68. package/dist/src/utils.d.ts.map +1 -0
  69. package/dist/src/utils.js +73 -0
  70. package/dist/src/utils.js.map +1 -0
  71. package/package.json +32 -3
package/LICENSE.md ADDED
@@ -0,0 +1,54 @@
1
+ # Business Source License 1.1
2
+
3
+ Copyright (c) 2025 Elara AI Pty Ltd
4
+
5
+ ## License
6
+
7
+ **Licensor:** Elara AI Pty Ltd
8
+
9
+ **Licensed Work:** @elaraai/e3-cloud-cli
10
+
11
+ **Change Date:** Four years from the date of each release
12
+
13
+ **Change License:** AGPL-3.0
14
+
15
+ ## Terms
16
+
17
+ The Licensed Work is provided under the terms of the Business Source License 1.1 as detailed below.
18
+
19
+ ### Grant of Rights
20
+
21
+ The Licensor grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work.
22
+
23
+ ### Production Use Limitation
24
+
25
+ **"Production Use"** means any use by or on behalf of a for-profit entity, other than for evaluation, testing, or development purposes.
26
+
27
+ Production Use requires a separate commercial license from the Licensor.
28
+
29
+ ### Change Date
30
+
31
+ On the Change Date (four years after each release), the Licensed Work will be made available under the Change License (AGPL-3.0).
32
+
33
+ ### No Warranty
34
+
35
+ THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. THE LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
36
+
37
+ ### Package-Specific Licenses
38
+
39
+ Individual packages within this repository may have different licensing terms. See the LICENSE.md file in each package directory for details.
40
+
41
+ ## Commercial Licensing
42
+
43
+ To obtain a commercial license for Production Use, contact:
44
+
45
+ **Email:** support@elara.ai
46
+ **Website:** https://elaraai.com
47
+
48
+ ## Governing Law
49
+
50
+ This license is governed by the laws of New South Wales, Australia.
51
+
52
+ ---
53
+
54
+ *Elara AI Pty Ltd*
package/README.md CHANGED
@@ -1,3 +1,434 @@
1
- # Temporary Holding Version
1
+ # @elaraai/e3-cloud-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ CLI tool for e3 cloud management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @elaraai/e3-cloud-cli
9
+ ```
10
+
11
+ The version is the @elaraai lockstep: use the CLI of the e3 release your
12
+ deployment runs.
13
+
14
+ ## Usage
15
+
16
+ ### Prerequisites
17
+
18
+ Login using the e3 CLI first (credentials are shared):
19
+
20
+ ```bash
21
+ e3 auth login https://e3.example.com
22
+ ```
23
+
24
+ ### Commands
25
+
26
+ #### Check current identity
27
+
28
+ ```bash
29
+ # Use first stored credential
30
+ e3-cloud whoami
31
+
32
+ # Or specify server explicitly
33
+ e3-cloud whoami https://e3.example.com
34
+ ```
35
+
36
+ Output:
37
+ ```
38
+ sub: abc123-def456
39
+ email: alice@example.com
40
+ name: Alice Smith
41
+ admin: true
42
+ ```
43
+
44
+ #### List repository users
45
+
46
+ ```bash
47
+ e3-cloud user list https://e3.example.com/repos/my-repo
48
+ ```
49
+
50
+ Output:
51
+ ```
52
+ USER ID EMAIL ROLE ADDED
53
+ abc123-def456 alice@example.com owner 2025-01-29T10:00:00
54
+ xyz789-uvw012 bob@example.com user: Rostering, Finance 2025-01-30T14:30:00
55
+ (not signed in) dana@example.com user: Rostering 2025-01-31T09:15:00
56
+ ```
57
+
58
+ People added who have not signed in yet are listed too: their roles are given at their first sign-in.
59
+
60
+ #### Add a person to a repository, or change their role
61
+
62
+ A repository has owners and users. A user holds business roles, each granting apps (every page of each, or some), and reaches only what those pages bind.
63
+
64
+ ```bash
65
+ # Add a user holding business roles (the repository's, or the built-in 'All apps')
66
+ e3-cloud user add https://e3.example.com/repos/my-repo charlie@example.com --roles 'Rostering,Finance'
67
+
68
+ # A user holding no role yet
69
+ e3-cloud user add https://e3.example.com/repos/my-repo charlie@example.com
70
+
71
+ # Add as owner
72
+ e3-cloud user add https://e3.example.com/repos/my-repo charlie@example.com --role owner
73
+ ```
74
+
75
+ Someone who has never signed in can be added with roles: they are invited, and get the roles at their first sign-in. Adding them again changes the roles they will get.
76
+
77
+ #### Business roles
78
+
79
+ ```bash
80
+ # List a repository's roles, and what each grants (owner or admin)
81
+ e3-cloud role list https://e3.example.com/repos/my-repo
82
+
83
+ # Write a role whole: every page of an app (workspace/app), or some (workspace/app:page,page)
84
+ e3-cloud role set https://e3.example.com/repos/my-repo Rostering --grant production/workforce:shifts,roster --grant production/reports
85
+
86
+ # Show one, and remove one no one holds
87
+ e3-cloud role show https://e3.example.com/repos/my-repo Rostering
88
+ e3-cloud role rm https://e3.example.com/repos/my-repo Rostering
89
+ ```
90
+
91
+ #### Remove a user from a repository
92
+
93
+ ```bash
94
+ # Someone with access, or the invitation of someone not signed in yet
95
+ e3-cloud user remove https://e3.example.com/repos/my-repo charlie@example.com
96
+ ```
97
+
98
+ #### Set a workspace schedule
99
+
100
+ ```bash
101
+ # Run daily at 2 AM, forcing specific tasks
102
+ e3-cloud schedule set https://e3.example.com/repos/acme/workspaces/main \
103
+ --cron "0 2 * * *" \
104
+ --force-tasks "input-orders,load-products" \
105
+ --description "Nightly data refresh"
106
+
107
+ # Force tasks matching a regex (resolves against deployed task list)
108
+ e3-cloud schedule set https://e3.example.com/repos/acme/workspaces/main \
109
+ --cron "0 2 * * *" \
110
+ --force-regex "input.*" \
111
+ --description "Nightly data refresh"
112
+
113
+ # Set with explicit timezone
114
+ e3-cloud schedule set https://e3.example.com/repos/acme/workspaces/main \
115
+ --cron "0 14 * * 1-5" \
116
+ --force-tasks "load-orders" \
117
+ --timezone "America/New_York" \
118
+ --description "Weekday 2 PM ET refresh"
119
+
120
+ # Disable without removing
121
+ e3-cloud schedule set https://e3.example.com/repos/acme/workspaces/main \
122
+ --enabled false
123
+ ```
124
+
125
+ #### View a workspace schedule
126
+
127
+ ```bash
128
+ e3-cloud schedule get https://e3.example.com/repos/acme/workspaces/main
129
+ ```
130
+
131
+ #### Remove a workspace schedule
132
+
133
+ ```bash
134
+ e3-cloud schedule remove https://e3.example.com/repos/acme/workspaces/main
135
+ ```
136
+
137
+ #### List all schedules for a repository
138
+
139
+ ```bash
140
+ e3-cloud schedule list https://e3.example.com/repos/acme
141
+ ```
142
+
143
+ #### Set compute size for a task
144
+
145
+ ```bash
146
+ # Set a single task to the medium container size
147
+ e3-cloud compute set https://e3.example.com/repos/acme/workspaces/main "my-task" --size medium
148
+
149
+ # Set all tasks matching a regex pattern
150
+ e3-cloud compute set https://e3.example.com/repos/acme/workspaces/main "load_.*" --size large --regex
151
+
152
+ # Reset a task back to serverless
153
+ e3-cloud compute set https://e3.example.com/repos/acme/workspaces/main "my-task" --size serverless
154
+ ```
155
+
156
+ Valid sizes: `serverless` (default, a serverless function), `small` (2 vCPU / 8 GB), `medium` (4 vCPU / 16 GB), `large` (8 vCPU / 32 GB), `xlarge` (16 vCPU / 64 GB).
157
+
158
+ #### View compute size for a task
159
+
160
+ ```bash
161
+ e3-cloud compute get https://e3.example.com/repos/acme/workspaces/main "my-task"
162
+ ```
163
+
164
+ #### List all compute configs for a workspace
165
+
166
+ ```bash
167
+ e3-cloud compute list https://e3.example.com/repos/acme/workspaces/main
168
+ ```
169
+
170
+ #### Remove compute config for a task
171
+
172
+ ```bash
173
+ # Remove a single task config (reverts to serverless)
174
+ e3-cloud compute remove https://e3.example.com/repos/acme/workspaces/main "my-task"
175
+
176
+ # Remove by regex pattern
177
+ e3-cloud compute remove https://e3.example.com/repos/acme/workspaces/main "load_.*" --regex
178
+ ```
179
+
180
+ #### Set timeout for a task
181
+
182
+ ```bash
183
+ # Set timeout in minutes
184
+ e3-cloud timeout set https://e3.example.com/repos/acme/workspaces/main "my-task" --timeout 120
185
+
186
+ # Set timeout in hours
187
+ e3-cloud timeout set https://e3.example.com/repos/acme/workspaces/main "my-task" --timeout 2h
188
+
189
+ # Set timeout in days
190
+ e3-cloud timeout set https://e3.example.com/repos/acme/workspaces/main "my-task" --timeout 1d
191
+
192
+ # Set timeout for multiple tasks by regex
193
+ e3-cloud timeout set https://e3.example.com/repos/acme/workspaces/main "load_.*" --timeout 4h --regex
194
+ ```
195
+
196
+ Valid range: 1 minute to 30 days (43200 minutes). Accepts: minutes (e.g., `120`), hours (e.g., `2h`), days (e.g., `1d`).
197
+
198
+ #### View timeout for a task
199
+
200
+ ```bash
201
+ e3-cloud timeout get https://e3.example.com/repos/acme/workspaces/main "my-task"
202
+ ```
203
+
204
+ #### List all timeout configs for a workspace
205
+
206
+ ```bash
207
+ e3-cloud timeout list https://e3.example.com/repos/acme/workspaces/main
208
+ ```
209
+
210
+ #### Remove timeout config for a task
211
+
212
+ ```bash
213
+ # Remove a single task timeout (reverts to default)
214
+ e3-cloud timeout remove https://e3.example.com/repos/acme/workspaces/main "my-task"
215
+
216
+ # Remove by regex pattern
217
+ e3-cloud timeout remove https://e3.example.com/repos/acme/workspaces/main "load_.*" --regex
218
+ ```
219
+
220
+ #### Manage repo secrets
221
+
222
+ Per-repo credentials for tasks (SQL passwords, API keys). **Write-only**:
223
+ values can be set and deleted but never read back — `list` shows names and
224
+ modification times only. Task code reads them at runtime with
225
+ `Env.get("NAME")` (east-node-std); only the NAME appears in East IR, and the
226
+ platform injects the value into the runner's environment at execution time.
227
+ Rotation takes effect on the next task run without invalidating caches.
228
+
229
+ ```bash
230
+ # Set a secret — value from stdin (keeps it out of shell history) or --value
231
+ printf %s "$PG_PASSWORD" | e3-cloud secrets set https://e3.example.com/repos/acme PG_PASSWORD
232
+
233
+ # Names + last-modified only; values are never shown
234
+ e3-cloud secrets list https://e3.example.com/repos/acme
235
+
236
+ # Delete
237
+ e3-cloud secrets rm https://e3.example.com/repos/acme PG_PASSWORD
238
+ ```
239
+
240
+ Names must be uppercase env-var shaped (`[A-Z_][A-Z0-9_]*`); runtime/platform
241
+ names (`PATH`, `LD_*`, `NODE_*`, `AWS_*`, `E3_*`, …) are reserved. `list` can
242
+ lag a set/rm by a few seconds; task-time injection is not affected.
243
+
244
+ #### Record history, rollback & backups
245
+
246
+ Managing `e3.record` state, the system of record. The
247
+ durable audit index records who/what/when for every committed mutation and
248
+ **survives compaction and GC**; rollback/restore append audited
249
+ `$rollback`/`$restore` commits (history is never rewritten; downstream tasks
250
+ re-run; a keyed retry after a rollback is answered, not applied twice) and are
251
+ refused, with the reason, past a migration or across a type change; a backup
252
+ names the record's state, which the platform keeps while the backup exists —
253
+ through compaction and garbage collection. Base mutations stay on the e3 CLI
254
+ (`e3 mutate` / `e3 history` / `e3 compact` — compaction now takes an automatic
255
+ safety backup first). Rollback, restore and backup management need the repo
256
+ owner (or platform admin) role.
257
+
258
+ ```bash
259
+ # Records in a workspace, with head commit + backup counts
260
+ e3-cloud records list https://e3.example.com/repos/acme main
261
+
262
+ # Durable audit, newest first (page with --before from the 'More:' line)
263
+ e3-cloud records history https://e3.example.com/repos/acme main orders
264
+
265
+ # Value at a version (East literal to stdout, the first 100 rows of a large
266
+ # record; -o writes the whole value as beast2, downloaded by segments)
267
+ e3-cloud records show https://e3.example.com/repos/acme main orders <commit>
268
+
269
+ # Roll back to a historical commit (appends $rollback; confirmation prompt)
270
+ e3-cloud records rollback https://e3.example.com/repos/acme main orders <commit>
271
+
272
+ # Backups: take, list, restore, download the value (a beast2 file) for offline keeping, delete
273
+ e3-cloud records backup https://e3.example.com/repos/acme main orders --note "before cutover"
274
+ e3-cloud records backups https://e3.example.com/repos/acme main orders
275
+ e3-cloud records restore https://e3.example.com/repos/acme main orders <backupId>
276
+ e3-cloud records backup-pull https://e3.example.com/repos/acme main orders <backupId> -o orders.beast2
277
+ e3-cloud records backup-rm https://e3.example.com/repos/acme main orders <backupId>
278
+ ```
279
+
280
+ #### Feedback
281
+
282
+ Notes users send about a part of a workspace's pages, numbered `FB-<n>` per
283
+ workspace. A note is named `12` or `FB-12`.
284
+
285
+ ```bash
286
+ # Turn a workspace's feedback on or off (owner or admin); its notes are kept when off
287
+ e3-cloud feedback enable https://e3.example.com/repos/my-repo/workspaces/main
288
+ e3-cloud feedback disable https://e3.example.com/repos/my-repo/workspaces/main
289
+
290
+ # The workspace's open notes, newest first, with its counts (owner or admin);
291
+ # page with --cursor from the 'More:' line; --mine lists your own instead
292
+ e3-cloud feedback list https://e3.example.com/repos/my-repo/workspaces/main
293
+ e3-cloud feedback list https://e3.example.com/repos/my-repo/workspaces/main --status closed --limit 50
294
+ e3-cloud feedback list https://e3.example.com/repos/my-repo/workspaces/main --mine
295
+
296
+ # One note whole: who sent it when, the page, the part, the datasets behind the
297
+ # view; --screenshot saves its screenshot (owner or admin, or its sender)
298
+ e3-cloud feedback show https://e3.example.com/repos/my-repo/workspaces/main FB-12 --screenshot fb-12.webp
299
+
300
+ # Close and reopen (owner or admin)
301
+ e3-cloud feedback close https://e3.example.com/repos/my-repo/workspaces/main 12
302
+ e3-cloud feedback reopen https://e3.example.com/repos/my-repo/workspaces/main 12
303
+ ```
304
+
305
+ #### Apps
306
+
307
+ Pages and menus built with `@elaraai/e3-cloud-ui`, each its own deployable in
308
+ a workspace. `build` makes a bundle of an app's source: the app, and
309
+ the package it was built against. The source's default export is the app
310
+ (`export default App('ops', { … })`); it is bundled with esbuild (TSX under
311
+ the nearest tsconfig.json, east-ui's JSX without one) and built by the
312
+ project's own `@elaraai/e3-cloud-ui`.
313
+
314
+ ```bash
315
+ # Build an app into a bundle (default dist/<app>.app)
316
+ e3-cloud app build src/apps/ops.tsx -o dist/ops.app
317
+
318
+ # Deploy (owner or admin): the bundle's package is imported first when the
319
+ # repository lacks its version; then the app is checked against it and, when
320
+ # the workspace runs it, is live at once. A refusal prints every problem and
321
+ # exits non-zero; --dry-run checks and changes nothing
322
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging dist/ops.app --dry-run
323
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging dist/ops.app
324
+
325
+ # Several apps built against one package, together; or straight from source
326
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging dist/ops.app dist/exec.app
327
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging --from-source src/apps/ops.tsx
328
+
329
+ # Stage a bundle built with the platform's next e3, for the platform deploy that moves to it
330
+ e3-cloud app deploy https://e3.example.com/repos/my-repo production dist/ops.app --for-platform 1.0.86
331
+
332
+ # What is deployed: every workspace's apps, or one's; an app's kept versions (owner or admin)
333
+ e3-cloud app list https://e3.example.com/repos/my-repo
334
+ e3-cloud app list https://e3.example.com/repos/my-repo staging
335
+ e3-cloud app versions https://e3.example.com/repos/my-repo staging ops
336
+
337
+ # Every app of the deployment, and which needs a bundle built with the platform's e3 (admin)
338
+ e3-cloud app list-all https://e3.example.com
339
+
340
+ # Remove an app and its versions (owner or admin)
341
+ e3-cloud app remove https://e3.example.com/repos/my-repo staging ops
342
+
343
+ # An admin's override of a workspace's protection: warns first, and its history records it as forced
344
+ e3-cloud app deploy https://e3.example.com/repos/my-repo production dist/ops.app --force
345
+ e3-cloud app remove https://e3.example.com/repos/my-repo production ops --force
346
+ ```
347
+
348
+ A protected workspace, one with a staging (below, Staging), refuses an app
349
+ deploy (a dry run, and a bundle for the next e3, too) and an app's removal:
350
+ it changes only by a release from its staging. Only an admin forces one past
351
+ it, with `--force`.
352
+
353
+ A deploy whose package the workspace does not run deploys the package first,
354
+ as a deploy job that keeps the inputs people set and starts no run; the
355
+ CLI waits for the job, and the apps go live as it completes.
356
+
357
+ **Developing an app** is done in the cloud, not locally: deploy each change
358
+ to a workspace of your own, a staging say (`--from-source` builds and
359
+ deploys in one step; `--dry-run` checks it against the workspace's package
360
+ and changes nothing), and open the app in the console there. A protected
361
+ workspace refuses a deploy: develop against its staging, and release.
362
+
363
+ ```bash
364
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging --from-source src/apps/ops.tsx --dry-run
365
+ e3-cloud app deploy https://e3.example.com/repos/my-repo staging --from-source src/apps/ops.tsx
366
+ ```
367
+
368
+ #### Staging
369
+
370
+ A workspace's staging is where changes are tried before they reach the
371
+ workspace people use. Adding one **protects** that workspace, as a protected
372
+ branch is protected: its package and apps then change only by a release from
373
+ its staging, or a rollback. One staging to a workspace, and no staging has one
374
+ of its own.
375
+
376
+ ```bash
377
+ # What adding it would do, and nothing more; then add it: a copy of production as it is now, data included
378
+ e3-cloud staging add https://e3.example.com/repos/acme production staging --plan
379
+ e3-cloud staging add https://e3.example.com/repos/acme production staging
380
+
381
+ # A workspace there: as it stands, or replaced whole by the copy (never unasked)
382
+ e3-cloud staging add https://e3.example.com/repos/acme production uat --as-is
383
+ e3-cloud staging add https://e3.example.com/repos/acme production uat --replace
384
+
385
+ # Each staging, and what it protects
386
+ e3-cloud staging list https://e3.example.com/repos/acme
387
+
388
+ # Stop it (admins alone): production is unprotected, nothing is deleted, its history records who stopped it
389
+ e3-cloud staging stop https://e3.example.com/repos/acme production
390
+ ```
391
+
392
+ A protected workspace refuses, naming its staging, e3's deploy (`e3 workspace
393
+ deploy`), an app deploy or removal (unless an admin forces it), a copy onto it,
394
+ and its removal or its staging's. What people do with its data goes on:
395
+ inputs set, records changed, runs, schedules.
396
+
397
+ #### Releases, rollback and history
398
+
399
+ ```bash
400
+ # The plan, and nothing more: package, apps, the next e3's bundles, records, inputs, carry, checks, forced changes it undoes
401
+ e3-cloud release https://e3.example.com/repos/acme staging production --plan
402
+
403
+ # Release staging to production: the plan is printed first, then the release
404
+ # runs; one that deploys its package waits for its deploy job
405
+ e3-cloud release https://e3.example.com/repos/acme staging production \
406
+ --carry inputs/mappings records/notes
407
+
408
+ # Remove production's apps that staging lacks (else the release is refused)
409
+ e3-cloud release https://e3.example.com/repos/acme staging production --remove-apps
410
+
411
+ # A workspace's history, newest first, each entry's id beneath it
412
+ e3-cloud history https://e3.example.com/repos/acme production
413
+
414
+ # Roll back: to the newest entry that differs from what production runs, or to one named
415
+ e3-cloud rollback https://e3.example.com/repos/acme production --plan
416
+ e3-cloud rollback https://e3.example.com/repos/acme production 2026-10-12T14:02:11.000Z#…
417
+ ```
418
+
419
+ A release (owner or admin) gives the target exactly the package and app
420
+ versions the source runs, by hash, with the bundles it has staged for the
421
+ platform's next e3. Only the target's staging releases to it, and a release
422
+ that would change nothing is refused. The target keeps the inputs people set
423
+ in it and migrates its records as a deploy does; `--carry` copies inputs, and
424
+ records new in the release, from the source by reference. No dataflow run
425
+ starts. A refused plan prints its problems and exits 1, changing nothing; the
426
+ plan names any change an admin forced onto the target since its last release,
427
+ which the release undoes. A rollback releases an entry of the history again,
428
+ its package and apps exactly; a record migrated forward may refuse to go back,
429
+ and the plan says so. A rollback stays open on a protected workspace.
430
+
431
+ ## License
432
+
433
+ [BSL 1.1](./LICENSE.md). Production use needs a commercial license from Elara
434
+ AI Pty Ltd. Each release becomes AGPL-3.0 four years after it is released.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import type { AppBundle } from '@elaraai/e3-cloud-ui/types';
6
+ /**
7
+ * Builds the app a source file's default export defines into a bundle.
8
+ *
9
+ * @param file - The source: a module whose default export is `App(...)`
10
+ * @returns The bundle: the app, and its package's zip
11
+ * @throws {Error} When the source does not bundle or run, its default export
12
+ * is no app, the project has no `@elaraai/e3-cloud-ui`, or the build refuses
13
+ * the app (`AppBuildError`, naming each problem)
14
+ */
15
+ export declare function buildAppFromSource(file: string): Promise<AppBundle>;
16
+ //# sourceMappingURL=app-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-source.d.ts","sourceRoot":"","sources":["../../src/app-source.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AA4E5D;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CASzE"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Builds an app from its source: `e3-cloud app build` and `app deploy
7
+ * --from-source`, as e3's CLI loads a package for `e3 workspace deploy
8
+ * --from-source`. esbuild bundles the entry (multi-file TypeScript and TSX,
9
+ * with the nearest tsconfig.json), leaving every `@elaraai/*` import to the
10
+ * project's own packages; the bundle is imported from under the project's
11
+ * `node_modules`, and its default export must be an app (`App(...)` of
12
+ * `@elaraai/e3-cloud-ui`). The app is built by the project's own
13
+ * `@elaraai/e3-cloud-ui`, the one its source imports, so the app, its pages
14
+ * and its package are of the modules the build reads them with.
15
+ */
16
+ import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
17
+ import { createRequire } from 'node:module';
18
+ import { dirname, join, parse, resolve } from 'node:path';
19
+ import { pathToFileURL } from 'node:url';
20
+ /** Whether a tsconfig.json is in a directory or one above it. */
21
+ function hasTsconfig(from) {
22
+ for (let dir = from;; dir = dirname(dir)) {
23
+ if (existsSync(join(dir, 'tsconfig.json')))
24
+ return true;
25
+ if (dir === parse(dir).root)
26
+ return false;
27
+ }
28
+ }
29
+ /**
30
+ * The source's entry, resolved, and the project's `@elaraai/e3-cloud-ui`.
31
+ *
32
+ * @throws {Error} When the source does not exist, or its project has no `@elaraai/e3-cloud-ui`
33
+ */
34
+ function resolveSource(file, entry = '@elaraai/e3-cloud-ui') {
35
+ const path = resolve(file);
36
+ if (!existsSync(path))
37
+ throw new Error(`${file} does not exist`);
38
+ try {
39
+ return { path, cloudUiEntry: createRequire(path).resolve(entry) };
40
+ }
41
+ catch {
42
+ throw new Error(`${file}'s project has no ${entry}: an app is built with the version its source imports (npm install @elaraai/e3-cloud-ui)`);
43
+ }
44
+ }
45
+ /** esbuild's options for a source: one ES module, every `@elaraai/*` import left to the project. */
46
+ function bundleOptions(path) {
47
+ return {
48
+ entryPoints: [path],
49
+ bundle: true,
50
+ platform: 'node',
51
+ format: 'esm',
52
+ write: false,
53
+ external: ['@elaraai/*'],
54
+ logLevel: 'silent',
55
+ // Without a tsconfig.json to say so, TSX is east-ui's
56
+ ...(!hasTsconfig(dirname(path)) && { jsx: 'automatic', jsxImportSource: '@elaraai/east-ui' }),
57
+ };
58
+ }
59
+ /**
60
+ * Builds the app a bundle of its source defines: the bundle is imported from
61
+ * under the project's `node_modules`, and its default export built by the
62
+ * project's `@elaraai/e3-cloud-ui`.
63
+ */
64
+ async function buildBundled(file, path, cloudUiEntry, code) {
65
+ // Under the project's node_modules, so its @elaraai/* imports resolve to the project's packages
66
+ const cache = join(dirname(path), 'node_modules', '.cache', 'e3-cloud');
67
+ mkdirSync(cache, { recursive: true });
68
+ const bundle = join(cache, `app-${process.pid}-${Date.now()}.mjs`);
69
+ let exported;
70
+ try {
71
+ writeFileSync(bundle, code);
72
+ const module = await import(`${pathToFileURL(bundle).href}?t=${Date.now()}`);
73
+ exported = module.default;
74
+ }
75
+ catch (err) {
76
+ throw new Error(`${file} did not run: ${err instanceof Error ? err.message : String(err)}`);
77
+ }
78
+ finally {
79
+ try {
80
+ unlinkSync(bundle);
81
+ }
82
+ catch {
83
+ // Ignore cleanup errors
84
+ }
85
+ }
86
+ if (typeof exported !== 'object' || exported === null || exported.kind !== 'app') {
87
+ throw new Error(`${file}'s default export must be an app:\n\n export default App('ops', { package, title, home, menu, pages });\n`);
88
+ }
89
+ const ui = await import(pathToFileURL(cloudUiEntry).href);
90
+ return ui.buildApp(exported);
91
+ }
92
+ /**
93
+ * Builds the app a source file's default export defines into a bundle.
94
+ *
95
+ * @param file - The source: a module whose default export is `App(...)`
96
+ * @returns The bundle: the app, and its package's zip
97
+ * @throws {Error} When the source does not bundle or run, its default export
98
+ * is no app, the project has no `@elaraai/e3-cloud-ui`, or the build refuses
99
+ * the app (`AppBuildError`, naming each problem)
100
+ */
101
+ export async function buildAppFromSource(file) {
102
+ const { path, cloudUiEntry } = resolveSource(file);
103
+ const esbuild = await import('esbuild');
104
+ const result = await esbuild.build(bundleOptions(path)).catch((err) => {
105
+ throw new Error(`${file} does not bundle: ${err instanceof Error ? err.message : String(err)}`);
106
+ });
107
+ const code = result.outputFiles?.[0]?.text;
108
+ if (code === undefined)
109
+ throw new Error(`esbuild produced no output for ${file}`);
110
+ return buildBundled(file, path, cloudUiEntry, code);
111
+ }
112
+ //# sourceMappingURL=app-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-source.js","sourceRoot":"","sources":["../../src/app-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) 2025 Elara AI Pty Ltd
4
+ * Licensed under BSL 1.1. See LICENSE for details.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG"}