@knpkv/alchemy-console 0.4.2 → 0.5.1

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 (60) hide show
  1. package/README.md +117 -15
  2. package/dist/api.d.ts +87 -16
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +7 -0
  5. package/dist/api.js.map +1 -1
  6. package/dist/client/assets/{index-CHwWf6VU.css → index-D5bP19PT.css} +1 -1
  7. package/dist/client/assets/index-D9T2ytki.js +58 -0
  8. package/dist/client/index.html +2 -2
  9. package/dist/main.js +2 -1
  10. package/dist/main.js.map +1 -1
  11. package/dist/plan.d.ts +109 -0
  12. package/dist/plan.d.ts.map +1 -0
  13. package/dist/plan.js +40 -0
  14. package/dist/plan.js.map +1 -0
  15. package/dist/presentation/PlanView.d.ts +10 -0
  16. package/dist/presentation/PlanView.d.ts.map +1 -0
  17. package/dist/presentation/PlanView.js +70 -0
  18. package/dist/presentation/PlanView.js.map +1 -0
  19. package/dist/presentation/StackDetailView.d.ts +4 -1
  20. package/dist/presentation/StackDetailView.d.ts.map +1 -1
  21. package/dist/presentation/StackDetailView.js +9 -3
  22. package/dist/presentation/StackDetailView.js.map +1 -1
  23. package/dist/presentation/detail-model.d.ts +1 -1
  24. package/dist/presentation/detail-model.d.ts.map +1 -1
  25. package/dist/server/Catalog.d.ts +1 -0
  26. package/dist/server/Catalog.d.ts.map +1 -1
  27. package/dist/server/Catalog.js +7 -1
  28. package/dist/server/Catalog.js.map +1 -1
  29. package/dist/server/HttpApplication.d.ts +2 -1
  30. package/dist/server/HttpApplication.d.ts.map +1 -1
  31. package/dist/server/HttpApplication.js +3 -1
  32. package/dist/server/HttpApplication.js.map +1 -1
  33. package/dist/server/Launch.d.ts +1 -1
  34. package/dist/server/Launch.d.ts.map +1 -1
  35. package/dist/server/PlanReader.d.ts +19 -0
  36. package/dist/server/PlanReader.d.ts.map +1 -0
  37. package/dist/server/PlanReader.js +202 -0
  38. package/dist/server/PlanReader.js.map +1 -0
  39. package/dist/server/Server.d.ts +1 -1
  40. package/dist/server/Server.d.ts.map +1 -1
  41. package/dist/server/plan/archive.d.ts +10 -0
  42. package/dist/server/plan/archive.d.ts.map +1 -0
  43. package/dist/server/plan/archive.js +62 -0
  44. package/dist/server/plan/archive.js.map +1 -0
  45. package/dist/server/plan/github.d.ts +106 -0
  46. package/dist/server/plan/github.d.ts.map +1 -0
  47. package/dist/server/plan/github.js +157 -0
  48. package/dist/server/plan/github.js.map +1 -0
  49. package/dist/server/plan/receipt.d.ts +153 -0
  50. package/dist/server/plan/receipt.d.ts.map +1 -0
  51. package/dist/server/plan/receipt.js +112 -0
  52. package/dist/server/plan/receipt.js.map +1 -0
  53. package/dist/views/index.js +547 -264
  54. package/dist/views/style.css +1 -1
  55. package/dist/views.d.ts +3 -0
  56. package/dist/views.d.ts.map +1 -1
  57. package/dist/views.js +1 -0
  58. package/dist/views.js.map +1 -1
  59. package/package.json +3 -3
  60. package/dist/client/assets/index-DbklFcSg.js +0 -58
package/README.md CHANGED
@@ -12,23 +12,24 @@ The browser shows stacks grouped by app, with desktop columns and compact phone
12
12
  rows. Read again starts a fresh discovery request and clears the previous rows.
13
13
  Loading, empty, incomplete discovery and owner sign-in failures are explicit.
14
14
  Missing metadata reads Unknown; zero resources remains zero. No polling, cached
15
- rows, plan, apply or destroy runs. Stage names and known resource counts open the
15
+ rows, local plan, apply or destroy runs. Stage names and known resource counts open the
16
16
  stack UI. Resources lists actual returned resource metadata; State groups the
17
17
  same resources by their returned construct parent and exact type. Resource rows
18
18
  open identity and dependency details. Outputs distinguishes Hidden values, proven
19
- empty state and unavailable formats. No raw JSON click target, Plan tab or Preview
20
- changes action is present.
19
+ empty state and unavailable formats. Plan shows the latest plan infrastructure CI already published. No raw JSON or
20
+ Preview changes action is present.
21
21
 
22
22
  The standalone wrapper shows Alchemy console, the actual local listener address
23
23
  and owner session status. It adds no Relay host inventory or shell navigation.
24
24
 
25
25
  Configuration is read at startup:
26
26
 
27
- | Variable | Default | Boundary |
28
- | ---------------------- | ---------------------------------------------- | ------------------------------------- |
29
- | `ALCHEMY_CONSOLE_ROOT` | `Work/dev` under the user's home | Server-private project discovery path |
30
- | `AWS_CONFIG_FILE` | `.aws/config` under the user's home | Server-private SSO configuration path |
31
- | `ALCHEMY_CONSOLE_HOME` | `.cache/alchemy-console` under the user's home | Server-private control directory |
27
+ | Variable | Default | Boundary |
28
+ | -------------------------- | ---------------------------------------------- | -------------------------------------- |
29
+ | `ALCHEMY_CONSOLE_ROOT` | `Work/dev` under the user's home | Server-private project discovery path |
30
+ | `AWS_CONFIG_FILE` | `.aws/config` under the user's home | Server-private SSO configuration path |
31
+ | `ALCHEMY_CONSOLE_HOME` | `.cache/alchemy-console` under the user's home | Server-private control directory |
32
+ | `ALCHEMY_CONSOLE_CI_TOKEN` | Unconfigured | Server-private read-only Actions token |
32
33
 
33
34
  Login reuse is per port. A reused server keeps its startup configuration. The
34
35
  control directory must be owned by the current user with mode `0700`; each
@@ -40,7 +41,7 @@ POSIX ownership and Unix sockets.
40
41
  ## Authenticated API
41
42
 
42
43
  The client-safe contracts are exported from `@knpkv/alchemy-console/api` and may be
43
- used with Effect's `HttpApiClient`. Both endpoints require the process's owner
44
+ used with Effect's `HttpApiClient`. All endpoints require the process's owner
44
45
  cookie, and all responses are private and uncacheable:
45
46
 
46
47
  The cookie name includes the bound listener port, so sessions on different ports
@@ -49,10 +50,11 @@ Cookies still share the loopback host and travel across ports; the name separate
49
50
  sessions and does not provide port confidentiality. The API middleware resolves
50
51
  the name at runtime rather than declaring a fixed OpenAPI cookie scheme.
51
52
 
52
- | Route | Result |
53
- | --------------------- | ------------------------------------------------------ |
54
- | `GET /api/stacks` | Stack summaries and explicit local/S3 discovery issues |
55
- | `GET /api/stacks/:id` | Current normalized resource state for a listed stack |
53
+ | Route | Result |
54
+ | -------------------------- | -------------------------------------------------------- |
55
+ | `GET /api/stacks` | Stack summaries and explicit local/S3 discovery issues |
56
+ | `GET /api/stacks/:id` | Current normalized resource state for a listed stack |
57
+ | `GET /api/stacks/:id/plan` | Latest verified CI plan or an explicit unavailable state |
56
58
 
57
59
  Listing runs discovery on demand, without polling or schedules. IDs are random,
58
60
  process-scoped identifiers with no encoded locator. They remain stable across
@@ -78,16 +80,116 @@ remain in the server and HttpOnly cookie. Every unsafe API method is refused,
78
80
  including apply and destroy. Reads reject foreign origins and cross-site browser
79
81
  requests. Listener and request Host are restricted to the bound loopback address.
80
82
 
83
+ ## CI plans
84
+
85
+ The console never imports or executes stack code. It reads the `plan.json`
86
+ publication from infrastructure CI in `knpkv/infra`. Only `site/prod` and
87
+ `aws-org/org` map to that repository's `site` and `aws-org` stacks. Other app/stage
88
+ pairs show Not connected.
89
+
90
+ Set `ALCHEMY_CONSOLE_CI_TOKEN` on the server to a dedicated fine-grained token with
91
+ Actions read access to that repository. The token is held in redacted server
92
+ configuration; no host `gh` token is discovered. The current main comparison uses
93
+ the newest main push workflow run's SHA, the latest main commit seen by CI.
94
+ It does not query Git references or require Contents access. If no main push run
95
+ is visible, only the age rule applies. This comparison does not prove the current
96
+ Git branch tip.
97
+
98
+ The reader selects the newest non-expired matching artifact and verifies the
99
+ receipt and provenance inputs listed below. Both archive and expanded
100
+ JSON must be below 1 MB. API metadata has a separate 2 MiB per-response cap to
101
+ accommodate full 100-row pages before schema projection. Metadata pagination stops
102
+ at ten pages and the whole read has a 30-second timeout. ZIP inspection and decompression stay in memory. No
103
+ payload is logged or extracted to disk.
104
+
105
+ A publication becomes stale after 24 hours or when its base differs from the
106
+ latest main commit seen by CI. A newer failed stack run can retain the verified
107
+ last publication with a stale notice. The latest attempt must have run the selected
108
+ stack’s `Native read-only plan` step. Attempts are ordered by `run_started_at`,
109
+ then run ID and attempt number, descending; `updated_at` does not decide order.
110
+ A successful job that skipped that step, or
111
+ a newer attempt for another stack, does not replace the selected stack’s attempt. Expired, unverified, unconnected and
112
+ unavailable states have no rows. Infra CI not publishing is distinct from a
113
+ stack's first publication. Only a CI transport failure offers Retry, which reads
114
+ again and never executes a plan. Owner-session failures return to the console's
115
+ sign-in/error state instead of pretending CI refused access.
116
+ Fixed repository/workflow discovery returning 404 is treated as refused CI access;
117
+ the response cannot distinguish denied access from a removed configured workflow.
118
+ Missing individual runs/artifacts and HTTP 429/5xx remain retryable transport failures.
119
+
120
+ ### Canonical receipt and identity boundaries
121
+
122
+ The persisted representation is the UTF-8 JSON receipt in the single regular
123
+ `plan.json` ZIP member of an Actions artifact named `infra-plan-<stack>-<head>`.
124
+ The server reads the artifact from the private `knpkv/infra` repository; that
125
+ repository name also appears in authenticated-client run URLs. Its entire
126
+ downloaded ZIP byte sequence is SHA-256 hashed and compared with the Actions
127
+ artifact's `sha256:<hex>` digest before decompression and exact-key receipt decoding.
128
+
129
+ Only `native.semantic` uses canonical semantic hashing: recursively sort object
130
+ keys, preserve array order, serialize with compact `JSON.stringify`, encode UTF-8,
131
+ then SHA-256 to lowercase hex and compare with `native.digest`. This is not a hash
132
+ of the whole receipt. The surrounding receipt identities are protected by the ZIP
133
+ digest and the separate provenance checks in this table.
134
+
135
+ | Input | Binding or validation | Boundary |
136
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
137
+ | Repository IDs | Producer/publisher `repository.id` and `head_repository.id`, artifact `workflow_run.repository_id` and `head_repository_id`, and main-CI repository IDs must equal `1288997422`. | Server-private API coordinates and pins. |
138
+ | Workflow identities | Active workflow definitions have exact paths `.github/workflows/infra.yml` and `.github/workflows/infra-publish.yml`; run `workflow_id` must match the respective definition ID. Run paths require the exact filename, with an optional validated `@ref`. Publisher refs are main; producer refs may also match its head branch or a recorded PR merge ref. | Server-private IDs, paths and refs. |
139
+ | Actor identities | Both producer/publisher `actor.id` and `triggering_actor.id` must equal `833092`. | Server-private numeric pins; no actor names are projected. |
140
+ | Producer run | Receipt `producerRunId` retrieves the run; its `id`, event `pull_request`, completed/success state, positive `run_attempt` and `run_started_at` identify the current reported attempt. Start time orders attempts; it is not a semantic-hash input. | Run ID can cross only within an allowlisted failed-run URL; attempt/start metadata remains server-private. |
141
+ | Producer job and step | Exactly one `<stack> / native` job must match the run's attempt and complete successfully; exactly one `Native read-only plan` step must have started and completed successfully. Job `id` is a positive API identity, not a receipt-pinned value. Schema 1 persists neither producer job ID nor producer attempt number. | Server-private job/attempt/step metadata. |
142
+ | Publisher run | Artifact `workflow_run.id` selects the run lookup; receipt `runId` equals the fetched run ID. Event is `workflow_run`, branch is `main`, state is completed/success, and `head_sha` equals both receipt `base` and artifact `workflow_run.head_sha`. | Run ID crosses within the allowlisted publication URL; branch/event/status and attempt metadata remain server-private. |
143
+ | Publisher job/attempt | Receipt `publisherJobId` equals a successful completed `<stack> / publish` job's immutable `id`; its `run_attempt` equals the current publisher attempt. Attempt number is API metadata, not a separate persisted receipt field. | Server-private job ID and attempt. |
144
+ | Publication artifact | API artifact `id` selects the download; `name` supplies the full head suffix bound to receipt `head`. `workflow_run.head_branch` must be `main`; run ID/SHA bind through the publisher row. Download length equals `size_in_bytes`; SHA-256 equals `digest`. `expired` and `expires_at` govern selection; `created_at` supplies publication age, not attempt order. | Artifact IDs, name, full digest and expiry metadata remain server-private. Only normalized `publishedAt` / `ageDays` cross owner HTTP. |
145
+ | PR/revisions | Receipt `pr`, `head`, `base` match the producer's `pull_requests[].number`, `head.sha`, `base.sha`; producer `head_sha` also equals receipt `head`. | Authenticated client sees PR number and seven-character head/base SHAs. Full revisions remain server-private. |
146
+ | Referenced workflow | Producer `referenced_workflows` must contain path `knpkv/infra/.github/workflows/_infra-plan.yml@main` or `@refs/heads/main`, ref `refs/heads/main`, and SHA equal to receipt `base`. | Server-private path/ref/full SHA; only the short base projection crosses. |
147
+ | Tools | Receipt `toolsSha` equals `base`; `toolsDigest` must be a 64-character lowercase hex hash. The console does not independently recompute `toolsDigest`. | Server-private tool identity/hash; only the separate short base projection crosses. |
148
+ | Raw artifact descriptor | Receipt `rawArtifactId` is positive; `rawArtifactDigest` has `sha256:<64 lowercase hex>` shape. The console does not fetch or rehash this raw artifact. These are not the publication artifact's ID/digest above. | Server-private descriptor, never an owner HTTP field. |
149
+ | Receipt assurance | `assurance` equals `untrusted-native-data/trusted-publication`. | Server-private receipt marker. |
150
+ | Schemas/stack/stage | Receipt `schema` and `native.schema` equal `1`. Receipt `stack`, `native.stack` and `native.semantic.stack` equal the selected mapped stack. Native/semantic stages agree: `site/prod` uses semantic schema `alchemy-beta77/ci-native-v1`; `aws-org/org` uses `alchemy-beta81/ci-native-v1`. `native.statePuts` equals `0`. | Schema/assurance markers stay server-private. Selected app/stage already cross as authenticated stack metadata. |
151
+ | Semantic impact | `native.semantic.impact` contains the selected stack, has one or two allowed stack names and no duplicates. | Server-private semantic-hash input. |
152
+ | Semantic resource identities | `native.semantic.rows[].fqn` / `type` exactly match the unique pins: `Site` → `Cloudflare.Worker`; `Platform`, `Sandbox` → `AWS.Organizations.OrganizationalUnit`; `Dev1Placement`, `DevPlacement`, `Dev2Placement`, `InfraPlacement` → `Org.AccountPlacement`. Site has one row; organization has six. | These semantic-hash inputs cross owner HTTP as normalized `fqn` / `resourceType`. |
153
+ | Semantic actions | `native.semantic.rows[].action` is `noop` or `update`; `native.hasChanges` agrees with the presence of an update. | Action crosses owner HTTP; the receipt boolean remains server-private. |
154
+ | Semantic property names | `native.semantic.rows[].changedKeys` has at most 32 names matching `^[A-Za-z][A-Za-z0-9_.-]{0,63}$`. | Names cross owner HTTP. Property values do not. |
155
+ | Semantic value hashes/mode | `native.semantic.rows[].props`, `attr`, `bindings` are lowercase 64-character hex hashes; `mode` is `live`. | Server-private semantic-hash inputs; no original values are stored in this receipt. |
156
+ | Semantic content/build/output | `native.semantic.contentDigest`, `output`, site `artifacts["Site/build"]` and `assetHashes.Site` are lowercase 64-character hex hashes. Organization `artifacts` is empty and has no `assetHashes` field. All are included in semantic hashing. | Server-private hashes/build keys; never projected or independently recomputed by this reader. |
157
+ | Semantic digest | `native.digest` equals the recomputed canonical semantic SHA-256. | Full digest remains server-private; only its first/last four hex characters cross owner HTTP. |
158
+ | Latest main commit seen by CI | The newest main push run must have the pinned repository IDs, `head_branch: main`, `event: push` and a valid `head_sha`. That SHA is compared with receipt `base` only for staleness. | Server-private comparison input; only normalized `stale: base` crosses. |
159
+
160
+ Every canonical semantic field above, including its schema/stack/stage, participates
161
+ in the semantic hash. Run/job/artifact metadata and surrounding receipt fields do
162
+ not. A valid ZIP digest authenticates receipt bytes against Actions metadata; it
163
+ does not strengthen shape-only fields into independently verified identities.
164
+ Tokens, signed download URLs, raw provider secrets and backend locators are never
165
+ durable receipt fields. Tokens and download URLs stay in the server transport.
166
+
167
+ The normalized authenticated client-visible projection contains PR number, short
168
+ head/base SHAs, publication time, safe GitHub run link, short semantic digest,
169
+ resource identity/type/action and bounded property names. These fields may cross
170
+ owner HTTP, but must not enter public or unauthenticated routes, browser storage
171
+ or telemetry. The token, signed artifact URLs, artifact/job IDs, full receipt
172
+ hashes, raw ZIP and unprojected semantic hash inputs remain server-private. Property values,
173
+ provider credentials and backend locators never enter this projection.
174
+
175
+ CI publication authenticates the source of the data, not the behavior of PR code.
176
+ The console does not certify CI's no-write or secret-access policy. No real CI
177
+ artifact is used by this feature's tests; all reader and browser states use
178
+ synthetic fixtures.
179
+
81
180
  ## Browser views
82
181
 
83
- Import `StackListView`, `StackDetailView` and `ResourceDetailView` from `@knpkv/alchemy-console/views` and its stylesheet from
182
+ Import `StackListView`, `StackDetailView`, `PlanView` and `ResourceDetailView` from `@knpkv/alchemy-console/views` and its stylesheet from
84
183
  `@knpkv/alchemy-console/views/style.css`. Mount them inside a Rly style/theme boundary.
85
184
  Views consumers supply the optional React, React DOM and Rly peers; the standalone
86
185
  browser shell already bundles them.
87
186
  The application supplies normalized presentation data, a product label, host
88
187
  sign-in instruction, read actions and real UI destinations. `StackListView` accepts
89
188
  optional `stackHref`; without a destination, stages and counts remain text.
90
- `StackDetailView` has controlled Resources/Outputs/State tabs and `resourceHref`.
189
+ `StackDetailView` has controlled Resources/Outputs/State/Plan tabs and `resourceHref`. Supply
190
+ `planState` and `onReadPlanAgain` for CI reading; without `planState`, Plan shows
191
+ Not connected. `PlanView` accepts the same controlled state and a read-only
192
+ `onReadAgain` callback.
91
193
  `ResourceDetailView` accepts `stackHref` and `resourceHref`. Views fetch nothing,
92
194
  read no configuration and persist no data. The standalone detail wrapper adds
93
195
  breadcrumbs and Read again outside the referenced module content. Phone list
package/dist/api.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /** Client-safe contracts. IDs and metadata cross only the authenticated owner API, never public telemetry. */
2
2
  import { Schema } from "effect";
3
3
  import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware } from "effect/http-api";
4
+ export { PlanRow, PlanSource, PlanState, PublishedPlan } from "./plan.js";
4
5
  /** Random, process-scoped identity; contains no encoded provider locator. Not persisted by the server. */
5
6
  export declare const StackId: Schema.String;
6
7
  export type StackId = typeof StackId.Type;
@@ -90,21 +91,7 @@ declare const OwnerAuth_base: HttpApiMiddleware.ServiceClass<OwnerAuth, "@knpkv/
90
91
  /** The server resolves its listener-specific cookie name at request time. */
91
92
  export declare class OwnerAuth extends OwnerAuth_base {
92
93
  }
93
- declare const AlchemyConsoleApi_base: HttpApi.HttpApi<"AlchemyConsoleApi", HttpApiGroup.HttpApiGroup<"stacks", HttpApiEndpoint.HttpApiEndpoint<"list", "GET", "/api/stacks", never, never, never, never, Schema.toCodecJson<Schema.Struct<{
94
- readonly stacks: Schema.$Array<Schema.Struct<{
95
- readonly id: Schema.String;
96
- readonly app: Schema.NonEmptyString;
97
- readonly stage: Schema.NonEmptyString;
98
- readonly backend: Schema.Literals<readonly ["local", "s3"]>;
99
- readonly alchemyVersion: Schema.NullOr<Schema.String>;
100
- readonly lastDeploy: Schema.NullOr<Schema.String>;
101
- readonly resourceCount: Schema.NullOr<Schema.Int>;
102
- }>>;
103
- readonly issues: Schema.$Array<Schema.Struct<{
104
- readonly source: Schema.Literals<readonly ["local", "s3"]>;
105
- readonly reason: Schema.Literals<readonly ["io", "invalid-state", "invalid-lockfile", "unsupported-version", "limit", "outside-root", "invalid-config", "authentication", "denied", "not-found", "provider", "invalid-response", "invalid-source"]>;
106
- }>>;
107
- }>>, Schema.toCodecJson<typeof CatalogReadError>, OwnerAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"get", "GET", "/api/stacks/:id", Schema.toCodecStringTree<Schema.Struct<{
94
+ declare const AlchemyConsoleApi_base: HttpApi.HttpApi<"AlchemyConsoleApi", HttpApiGroup.HttpApiGroup<"stacks", HttpApiEndpoint.HttpApiEndpoint<"get", "GET", "/api/stacks/:id", Schema.toCodecStringTree<Schema.Struct<{
108
95
  readonly id: Schema.String;
109
96
  }>>, never, never, never, Schema.toCodecJson<Schema.Struct<{
110
97
  readonly id: Schema.String;
@@ -133,8 +120,92 @@ declare const AlchemyConsoleApi_base: HttpApi.HttpApi<"AlchemyConsoleApi", HttpA
133
120
  readonly description: Schema.Null;
134
121
  }>>>;
135
122
  }>;
123
+ }>>, Schema.toCodecJson<typeof CatalogReadError | typeof StackNotFound>, OwnerAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"list", "GET", "/api/stacks", never, never, never, never, Schema.toCodecJson<Schema.Struct<{
124
+ readonly stacks: Schema.$Array<Schema.Struct<{
125
+ readonly id: Schema.String;
126
+ readonly app: Schema.NonEmptyString;
127
+ readonly stage: Schema.NonEmptyString;
128
+ readonly backend: Schema.Literals<readonly ["local", "s3"]>;
129
+ readonly alchemyVersion: Schema.NullOr<Schema.String>;
130
+ readonly lastDeploy: Schema.NullOr<Schema.String>;
131
+ readonly resourceCount: Schema.NullOr<Schema.Int>;
132
+ }>>;
133
+ readonly issues: Schema.$Array<Schema.Struct<{
134
+ readonly source: Schema.Literals<readonly ["local", "s3"]>;
135
+ readonly reason: Schema.Literals<readonly ["io", "invalid-state", "invalid-lockfile", "unsupported-version", "limit", "outside-root", "invalid-config", "authentication", "denied", "not-found", "provider", "invalid-response", "invalid-source"]>;
136
+ }>>;
137
+ }>>, Schema.toCodecJson<typeof CatalogReadError>, OwnerAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"plan", "GET", "/api/stacks/:id/plan", Schema.toCodecStringTree<Schema.Struct<{
138
+ readonly id: Schema.String;
139
+ }>>, never, never, never, Schema.toCodecJson<Schema.TaggedUnion<{
140
+ readonly Expired: Schema.TaggedStruct<"Expired", {
141
+ readonly source: Schema.NullOr<Schema.Struct<{
142
+ readonly pr: Schema.NullOr<Schema.Int>;
143
+ readonly head: Schema.String;
144
+ readonly base: Schema.NullOr<Schema.String>;
145
+ readonly publishedAt: Schema.String;
146
+ readonly ageDays: Schema.Int;
147
+ readonly runHref: Schema.String;
148
+ }>>;
149
+ }>;
150
+ readonly Failed: Schema.TaggedStruct<"Failed", {
151
+ readonly runHref: Schema.String;
152
+ readonly lastPublished: Schema.NullOr<Schema.Struct<{
153
+ readonly source: Schema.Struct<{
154
+ readonly pr: Schema.NullOr<Schema.Int>;
155
+ readonly head: Schema.String;
156
+ readonly base: Schema.NullOr<Schema.String>;
157
+ readonly publishedAt: Schema.String;
158
+ readonly ageDays: Schema.Int;
159
+ readonly runHref: Schema.String;
160
+ }>;
161
+ readonly digest: Schema.String;
162
+ readonly rows: Schema.$Array<Schema.Struct<{
163
+ readonly fqn: Schema.NonEmptyString;
164
+ readonly resourceType: Schema.NonEmptyString;
165
+ readonly action: Schema.Literals<readonly ["noop", "update"]>;
166
+ readonly changedKeys: Schema.$Array<Schema.String>;
167
+ }>>;
168
+ readonly stale: Schema.NullOr<Schema.Literals<readonly ["age", "base", "failed"]>>;
169
+ }>>;
170
+ }>;
171
+ readonly Loading: Schema.TaggedStruct<"Loading", {}>;
172
+ readonly NotConnected: Schema.TaggedStruct<"NotConnected", {}>;
173
+ readonly NotPublished: Schema.TaggedStruct<"NotPublished", {}>;
174
+ readonly NotPublishing: Schema.TaggedStruct<"NotPublishing", {}>;
175
+ readonly Ready: Schema.TaggedStruct<"Ready", {
176
+ readonly plan: Schema.Struct<{
177
+ readonly source: Schema.Struct<{
178
+ readonly pr: Schema.NullOr<Schema.Int>;
179
+ readonly head: Schema.String;
180
+ readonly base: Schema.NullOr<Schema.String>;
181
+ readonly publishedAt: Schema.String;
182
+ readonly ageDays: Schema.Int;
183
+ readonly runHref: Schema.String;
184
+ }>;
185
+ readonly digest: Schema.String;
186
+ readonly rows: Schema.$Array<Schema.Struct<{
187
+ readonly fqn: Schema.NonEmptyString;
188
+ readonly resourceType: Schema.NonEmptyString;
189
+ readonly action: Schema.Literals<readonly ["noop", "update"]>;
190
+ readonly changedKeys: Schema.$Array<Schema.String>;
191
+ }>>;
192
+ readonly stale: Schema.NullOr<Schema.Literals<readonly ["age", "base", "failed"]>>;
193
+ }>;
194
+ }>;
195
+ readonly Refused: Schema.TaggedStruct<"Refused", {}>;
196
+ readonly Unreachable: Schema.TaggedStruct<"Unreachable", {}>;
197
+ readonly Unverified: Schema.TaggedStruct<"Unverified", {
198
+ readonly reason: Schema.Literals<readonly ["metadata", "provenance", "archive", "digest", "receipt"]>;
199
+ readonly source: Schema.NullOr<Schema.Struct<{
200
+ readonly pr: Schema.NullOr<Schema.Int>;
201
+ readonly head: Schema.String;
202
+ readonly base: Schema.NullOr<Schema.String>;
203
+ readonly publishedAt: Schema.String;
204
+ readonly ageDays: Schema.Int;
205
+ readonly runHref: Schema.String;
206
+ }>>;
207
+ }>;
136
208
  }>>, Schema.toCodecJson<typeof CatalogReadError | typeof StackNotFound>, OwnerAuth, never>, false>>;
137
209
  export declare class AlchemyConsoleApi extends AlchemyConsoleApi_base {
138
210
  }
139
- export {};
140
211
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAG3F,0GAA0G;AAC1G,eAAO,MAAM,OAAO,eAAuC,CAAA;AAC3D,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,eAAO,MAAM,mBAAmB,oOAc9B,CAAA;AAEF,eAAO,MAAM,cAAc;;;EAGzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD,eAAO,MAAM,YAAY;;;;;;;;EAQvB,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAEnD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;EAA8F,CAAA;AACpH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAC7C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAoD,CAAA;AAC5E,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;;;;AAEjD,qBAAa,gBAAiB,SAAQ,qBAEZ;CAAG;;AAE7B,qBAAa,aAAc,SAAQ,kBAAgF;CAAG;;AAEtH,qBAAa,YAAa,SAAQ,iBAA8E;CAAG;;AAEnH,qBAAa,SAAU,SAAQ,cAAwE;CAAG;;;;;;;;;AAE1G,6EAA6E;AAC7E,qBAAa,SAAU,SAAQ,cAE7B;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWL,qBAAa,iBAAkB,SAAQ,sBAAmE;CAAG"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAI3F,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEzE,0GAA0G;AAC1G,eAAO,MAAM,OAAO,eAAuC,CAAA;AAC3D,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,eAAO,MAAM,mBAAmB,oOAc9B,CAAA;AAEF,eAAO,MAAM,cAAc;;;EAGzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD,eAAO,MAAM,YAAY;;;;;;;;EAQvB,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAEnD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;EAA8F,CAAA;AACpH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAC7C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAoD,CAAA;AAC5E,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;;;;AAEjD,qBAAa,gBAAiB,SAAQ,qBAEZ;CAAG;;AAE7B,qBAAa,aAAc,SAAQ,kBAAgF;CAAG;;AAEtH,qBAAa,YAAa,SAAQ,iBAA8E;CAAG;;AAEnH,qBAAa,SAAU,SAAQ,cAAwE;CAAG;;;;;;;;;AAE1G,6EAA6E;AAC7E,qBAAa,SAAU,SAAQ,cAE7B;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBL,qBAAa,iBAAkB,SAAQ,sBAAmE;CAAG"}
package/dist/api.js CHANGED
@@ -1,7 +1,9 @@
1
1
  /** Client-safe contracts. IDs and metadata cross only the authenticated owner API, never public telemetry. */
2
2
  import { Schema } from "effect";
3
3
  import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware } from "effect/http-api";
4
+ import { PlanState } from "./plan.js";
4
5
  import { StackState } from "./schema.js";
6
+ export { PlanRow, PlanSource, PlanState, PublishedPlan } from "./plan.js";
5
7
  /** Random, process-scoped identity; contains no encoded provider locator. Not persisted by the server. */
6
8
  export const StackId = Schema.String.check(Schema.isUUID());
7
9
  export const SourceFailureReason = Schema.Literals([
@@ -55,6 +57,11 @@ const stacks = HttpApiGroup.make("stacks")
55
57
  params: Schema.Struct({ id: StackId }),
56
58
  success: StackDetail,
57
59
  error: [StackNotFound, CatalogReadError]
60
+ }))
61
+ .add(HttpApiEndpoint.get("plan", "/stacks/:id/plan", {
62
+ params: Schema.Struct({ id: StackId }),
63
+ success: PlanState,
64
+ error: [StackNotFound, CatalogReadError]
58
65
  }))
59
66
  .prefix("/api");
60
67
  export class AlchemyConsoleApi extends HttpApi.make("AlchemyConsoleApi").add(stacks).middleware(OwnerAuth) {
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}