@knpkv/alchemy-console 0.1.0 → 0.2.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 (51) hide show
  1. package/README.md +71 -4
  2. package/dist/api.d.ts +126 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +62 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/client/bootstrap.js +2834 -0
  7. package/dist/main.d.ts +3 -0
  8. package/dist/main.d.ts.map +1 -0
  9. package/dist/main.js +39 -0
  10. package/dist/main.js.map +1 -0
  11. package/dist/s3-live.d.ts +7 -2
  12. package/dist/s3-live.d.ts.map +1 -1
  13. package/dist/s3-live.js +3 -2
  14. package/dist/s3-live.js.map +1 -1
  15. package/dist/server/Bootstrap.d.ts +4 -0
  16. package/dist/server/Bootstrap.d.ts.map +1 -0
  17. package/dist/server/Bootstrap.js +12 -0
  18. package/dist/server/Bootstrap.js.map +1 -0
  19. package/dist/server/Catalog.d.ts +27 -0
  20. package/dist/server/Catalog.d.ts.map +1 -0
  21. package/dist/server/Catalog.js +83 -0
  22. package/dist/server/Catalog.js.map +1 -0
  23. package/dist/server/Config.d.ts +17 -0
  24. package/dist/server/Config.d.ts.map +1 -0
  25. package/dist/server/Config.js +23 -0
  26. package/dist/server/Config.js.map +1 -0
  27. package/dist/server/ControlSocket.d.ts +19 -0
  28. package/dist/server/ControlSocket.d.ts.map +1 -0
  29. package/dist/server/ControlSocket.js +147 -0
  30. package/dist/server/ControlSocket.js.map +1 -0
  31. package/dist/server/HttpApplication.d.ts +7 -0
  32. package/dist/server/HttpApplication.d.ts.map +1 -0
  33. package/dist/server/HttpApplication.js +46 -0
  34. package/dist/server/HttpApplication.js.map +1 -0
  35. package/dist/server/Launch.d.ts +7 -0
  36. package/dist/server/Launch.d.ts.map +1 -0
  37. package/dist/server/Launch.js +17 -0
  38. package/dist/server/Launch.js.map +1 -0
  39. package/dist/server/OwnerSession.d.ts +9 -0
  40. package/dist/server/OwnerSession.d.ts.map +1 -0
  41. package/dist/server/OwnerSession.js +27 -0
  42. package/dist/server/OwnerSession.js.map +1 -0
  43. package/dist/server/Server.d.ts +6 -0
  44. package/dist/server/Server.d.ts.map +1 -0
  45. package/dist/server/Server.js +22 -0
  46. package/dist/server/Server.js.map +1 -0
  47. package/dist/server/Sources.d.ts +12 -0
  48. package/dist/server/Sources.d.ts.map +1 -0
  49. package/dist/server/Sources.js +118 -0
  50. package/dist/server/Sources.js.map +1 -0
  51. package/package.json +17 -6
package/dist/main.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
package/dist/main.js ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ /** Loopback executable boundary: no-arg/login reuse or start; serve stays foreground and print-only. */
3
+ import { NodeRuntime, NodeServices } from "@effect/platform-node";
4
+ import { browserLaunch, BrowserOpener } from "@knpkv/browser-pairing/launch";
5
+ import { Effect, Layer, Schema } from "effect";
6
+ import { Command, Flag } from "effect/cli";
7
+ import { FetchHttpClient } from "effect/http";
8
+ import { homedir } from "node:os";
9
+ import process from "node:process";
10
+ import { Catalog } from "./server/Catalog.js";
11
+ import { loadConfig, Port, readPackageVersion, StartupError } from "./server/Config.js";
12
+ import { runConsole } from "./server/Launch.js";
13
+ import { sourceLayer } from "./server/Sources.js";
14
+ import { ssoCredentialsLayer } from "./sso-credentials.js";
15
+ const home = homedir();
16
+ const uid = process.geteuid?.() ?? -1;
17
+ const observations = {
18
+ browser: process.env.BROWSER,
19
+ ci: process.env.CI,
20
+ interactive: process.stdout.isTTY === true
21
+ };
22
+ const flags = {
23
+ port: Flag.Int("port").pipe(Flag.withDefault(3114)),
24
+ noOpen: Flag.Boolean("no-open").pipe(Flag.withDefault(false))
25
+ };
26
+ const run = Effect.fn("AlchemyConsole.run")(function* (port, noOpen, printOnly) {
27
+ yield* Schema.decodeUnknownEffect(Port)(port).pipe(Effect.mapError(() => new StartupError({ reason: "invalid-port" })));
28
+ const config = yield* loadConfig(home).pipe(Effect.mapError(() => new StartupError({ reason: "config" })));
29
+ const options = { directory: config.directory, port, uid };
30
+ return yield* runConsole(options, browserLaunch({ ...observations, noOpen }), printOnly);
31
+ });
32
+ const login = Command.make("login", flags, ({ noOpen, port }) => run(port, noOpen, false));
33
+ const serve = Command.make("serve", flags, ({ noOpen, port }) => run(port, noOpen, true));
34
+ const command = Command.make("alchemy-console", flags, ({ noOpen, port }) => run(port, noOpen, false)).pipe(Command.withDescription("Read-only Alchemy stack API on loopback"), Command.withSubcommands([login, serve]));
35
+ const sources = Layer.unwrap(loadConfig(home).pipe(Effect.mapError(() => new StartupError({ reason: "config" })), Effect.map(sourceLayer))).pipe(Layer.provide(FetchHttpClient.layer), Layer.provide(ssoCredentialsLayer()));
36
+ const services = Layer.merge(Catalog.layer.pipe(Layer.provide(sources)), BrowserOpener.layer).pipe(Layer.provideMerge(NodeServices.layer));
37
+ const cli = readPackageVersion().pipe(Effect.flatMap((version) => Command.run(command, { version })));
38
+ NodeRuntime.runMain(cli.pipe(Effect.withTracerEnabled(false), Effect.provide(services)));
39
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
package/dist/s3-live.d.ts CHANGED
@@ -1,8 +1,13 @@
1
- import { Layer } from "effect";
1
+ import { Effect, Layer } from "effect";
2
2
  import * as HttpClient from "effect/http/HttpClient";
3
3
  import type { SsoProfile } from "./profiles.js";
4
- import { S3Reader } from "./s3-reader.js";
4
+ import { type S3Bucket, S3Reader, S3ReadError, type VersionCursor } from "./s3-reader.js";
5
5
  import { SsoCredentials } from "./sso-credentials.js";
6
6
  /** Independent read-only adapter. ExpectedBucketOwner binds requests to the selected SSO account. */
7
+ export declare const makeS3Reader: (profile: SsoProfile) => Effect.Effect<{
8
+ readonly buckets: (cursor: string | null) => Effect.Effect<import("./s3-reader.js").S3BucketPage, S3ReadError>;
9
+ readonly versions: (bucket: S3Bucket, prefix: string, cursor: VersionCursor | null) => Effect.Effect<import("./s3-reader.js").S3VersionPage, S3ReadError>;
10
+ readonly resource: (bucket: S3Bucket, key: string, versionId: string) => Effect.Effect<import("./schema.ts").ResourceSummary | null, S3ReadError | import("./schema.ts").StateReadError>;
11
+ }, never, HttpClient.HttpClient | SsoCredentials>;
7
12
  export declare const s3ReaderLayer: (profile: SsoProfile) => Layer.Layer<S3Reader, never, HttpClient.HttpClient | SsoCredentials>;
8
13
  //# sourceMappingURL=s3-live.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"s3-live.d.ts","sourceRoot":"","sources":["../src/s3-live.ts"],"names":[],"mappings":"AAcA,OAAO,EAAU,KAAK,EAAa,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAiB,QAAQ,EAAmD,MAAM,gBAAgB,CAAA;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAsBrD,qGAAqG;AACrG,eAAO,MAAM,aAAa,YAAa,UAAU,yEAqH9C,CAAA"}
1
+ {"version":3,"file":"s3-live.d.ts","sourceRoot":"","sources":["../src/s3-live.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAa,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,KAAK,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAsBrD,qGAAqG;AACrG,eAAO,MAAM,YAAY;;;;iDAiHvB,CAAA;AAEF,eAAO,MAAM,aAAa,YAAa,UAAU,yEAAkD,CAAA"}
package/dist/s3-live.js CHANGED
@@ -22,7 +22,7 @@ const providerError = (error) => {
22
22
  return new S3ReadError({ reason: "provider" });
23
23
  };
24
24
  /** Independent read-only adapter. ExpectedBucketOwner binds requests to the selected SSO account. */
25
- export const s3ReaderLayer = (profile) => Layer.effect(S3Reader, Effect.gen(function* () {
25
+ export const makeS3Reader = Effect.fn("AlchemyConsole.makeS3Reader")(function* (profile) {
26
26
  const client = yield* HttpClient.HttpClient;
27
27
  const sso = yield* SsoCredentials;
28
28
  const call = Effect.fn("AlchemyConsole.callS3")(function* (effect, region) {
@@ -107,5 +107,6 @@ export const s3ReaderLayer = (profile) => Layer.effect(S3Reader, Effect.gen(func
107
107
  return yield* decodeResource(text);
108
108
  })
109
109
  });
110
- }));
110
+ });
111
+ export const s3ReaderLayer = (profile) => Layer.effect(S3Reader, makeS3Reader(profile));
111
112
  //# sourceMappingURL=s3-live.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"s3-live.js","sourceRoot":"","sources":["../src/s3-live.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"s3-live.js","sourceRoot":"","sources":["../src/s3-live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAA;AACpD,OAAO,EAEL,SAAS,EAET,WAAW,EAGX,kBAAkB,EAGnB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AAEpD,OAAO,EAAiB,QAAQ,EAAE,WAAW,EAAsC,MAAM,gBAAgB,CAAA;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAI3C,MAAM,aAAa,GAAG,CAAC,KAAsB,EAAe,EAAE;IAC5D,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;IAC1E,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,uBAAuB,EAAE,CAAC;QAC9D,OAAO,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC9C,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;IACjH,IACE,CAAC,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,oBAAoB,EAAE,uBAAuB,CAAC,CAAC,QAAQ,CAC/G,GAAG,CACJ,EACD,CAAC;QACD,OAAO,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;IACtD,CAAC;IACD,OAAO,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAA;AAChD,CAAC,CAAA;AAED,qGAAqG;AACrG,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,EAAC,OAAmB;IAChG,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAA;IAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,cAAc,CAAA;IACjC,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EACvD,MAAgE,EAChE,MAAc;QAEd,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC/C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAC/D,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EACrD,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC;QACpD,2EAA2E;QAC3E,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAChE,MAAM,CAAC,aAAa,CAAC;YACnB,QAAQ,EAAE,YAAY;YACtB,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;SACnE,CAAC,EACF,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAC/B,CAAA;IACH,CAAC,CAAC,CAAA;IACF,OAAO,QAAQ,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC,CAAC,QAAQ,CAAC,EAAC,MAAqB;YAChF,MAAM,OAAO,GAAuB,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;YACxD,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAA;YACvD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;YAC9D,MAAM,OAAO,GAAoB,EAAE,CAAA;YACnC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACxC,IACE,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;oBAC1F,MAAM,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;oBAChC,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAA;gBAC/D,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI,EAAE,CAAA;QAC1D,CAAC,CAAC;QACF,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAC5D,MAAgB,EAChB,MAAc,EACd,MAA4B;YAE5B,MAAM,OAAO,GAA8B;gBACzC,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,mBAAmB,EAAE,OAAO,CAAC,OAAO;gBACpC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI;aACd,CAAA;YACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,CAAA;gBAC9B,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI;oBAAE,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,SAAS,CAAA;YAC3E,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;YACpE,MAAM,QAAQ,GAAqB,EAAE,CAAA;YACrC,MAAM,MAAM,GAAgF;gBAC1F,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;gBAC7C,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aAClD,CAAA;YACD,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;gBACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,IACE,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS;wBAC5E,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EACxD,CAAC;wBACD,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAA;oBAC/D,CAAC;oBACD,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;gBAC1F,CAAC;YACH,CAAC;YACD,IACE,IAAI,CAAC,WAAW,KAAK,SAAS;gBAC9B,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,EAC3F,CAAC;gBACD,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAC/D,CAAC;YACD,OAAO;gBACL,QAAQ;gBACR,IAAI,EAAE,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC;oBAC/B;wBACE,GAAG,EAAE,IAAI,CAAC,aAAa,IAAI,EAAE;wBAC7B,SAAS,EAAE,IAAI,CAAC,mBAAmB,IAAI,IAAI;qBAC5C,CAAC,CAAC;oBACH,IAAI;aACP,CAAA;QACH,CAAC,CAAC;QACF,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC,CACjD,QAAQ,CAAC,EAAC,MAAgB,EAAE,GAAW,EAAE,SAAiB;YACxD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,IAAI,CACxB,SAAS,CAAC;gBACR,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,mBAAmB,EAAE,OAAO,CAAC,OAAO;gBACpC,GAAG,EAAE,GAAG;gBACR,SAAS,EAAE,SAAS;aACrB,CAAC,EACF,MAAM,CAAC,MAAM,CACd,CAAA;YACD,IACE,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EACvG,CAAC;gBACD,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAC/D,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,IAAI,CACvE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CACnG,EACD,MAAM,CAAC,aAAa,CAAC;gBACnB,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;aACnE,CAAC,CACH,CAAA;YACD,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;QACpC,CAAC,CACF;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAmB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { Layer, Path } from "effect";
2
+ import { HttpRouter } from "effect/http";
3
+ export declare const BootstrapRoutes: Layer.Layer<never, import("effect/PlatformError").BadArgument | import("effect/PlatformError").PlatformError, import("effect/FileSystem").FileSystem | import("effect/http/HttpPlatform").HttpPlatform | HttpRouter.HttpRouter | Path.Path>;
4
+ //# sourceMappingURL=Bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bootstrap.d.ts","sourceRoot":"","sources":["../../src/server/Bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAwC,MAAM,aAAa,CAAA;AAM9E,eAAO,MAAM,eAAe,6OAU3B,CAAA"}
@@ -0,0 +1,12 @@
1
+ import { Effect, Layer, Path } from "effect";
2
+ import { HttpRouter, HttpServerResponse, HttpStaticServer } from "effect/http";
3
+ /** Auth handoff only. The design-backed stack UI will replace the JSON navigation in a later PR. */
4
+ const document = `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Alchemy console</title><body><main><p id="status">Signing in…</p><noscript>Enable JavaScript to sign in.</noscript></main><script type="module" src="/bootstrap.js"></script></body></html>`;
5
+ export const BootstrapRoutes = Layer.mergeAll(HttpRouter.add("GET", "/", HttpServerResponse.html(document)), HttpRouter.add("GET", "/favicon.ico", HttpServerResponse.empty({ status: 204 })), Layer.unwrap(Effect.gen(function* () {
6
+ const path = yield* Path.Path;
7
+ return HttpStaticServer.layer({
8
+ root: yield* path.fromFileUrl(new URL("../../dist/client", import.meta.url)),
9
+ cacheControl: "no-store"
10
+ });
11
+ })));
12
+ //# sourceMappingURL=Bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bootstrap.js","sourceRoot":"","sources":["../../src/server/Bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9E,oGAAoG;AACpG,MAAM,QAAQ,GACZ,4SAA4S,CAAA;AAE9S,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAC3C,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAC7D,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAChF,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;IAC7B,OAAO,gBAAgB,CAAC,KAAK,CAAC;QAC5B,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,mBAAmB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5E,YAAY,EAAE,UAAU;KACzB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAC,CACJ,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { Context, Crypto, Effect, Layer } from "effect";
2
+ import { CatalogReadError, StackNotFound, StackSummary } from "../api.js";
3
+ import type { DiscoveryIssue, StackDetail, StackId, StackList } from "../api.js";
4
+ import { type StackState } from "../schema.js";
5
+ /** Server-private locator identity and read closure. Never serialize or retain in logs or browser storage. */
6
+ export interface DiscoveredStack {
7
+ readonly key: string;
8
+ readonly summary: Omit<StackSummary, "id">;
9
+ readonly read: Effect.Effect<StackState, CatalogReadError>;
10
+ }
11
+ declare const StackSource_base: Context.ServiceClass<StackSource, "@knpkv/alchemy-console/StackSource", {
12
+ readonly discover: Effect.Effect<{
13
+ readonly stacks: ReadonlyArray<DiscoveredStack>;
14
+ readonly issues: ReadonlyArray<DiscoveryIssue>;
15
+ }, CatalogReadError>;
16
+ }>;
17
+ export declare class StackSource extends StackSource_base {
18
+ }
19
+ declare const Catalog_base: Context.ServiceClass<Catalog, "@knpkv/alchemy-console/Catalog", {
20
+ readonly list: Effect.Effect<StackList, CatalogReadError>;
21
+ readonly get: (id: StackId) => Effect.Effect<StackDetail, StackNotFound | CatalogReadError>;
22
+ }>;
23
+ export declare class Catalog extends Catalog_base {
24
+ static readonly layer: Layer.Layer<Catalog, never, Crypto.Crypto | StackSource>;
25
+ }
26
+ export {};
27
+ //# sourceMappingURL=Catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Catalog.d.ts","sourceRoot":"","sources":["../../src/server/Catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAA0B,MAAM,QAAQ,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAChF,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAEpE,8GAA8G;AAC9G,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;CAC3D;;uBAGoB,MAAM,CAAC,MAAM,CAAC;QAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;QAC/C,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;KAC/C,EAAE,gBAAgB,CAAC;;AAJtB,qBAAa,WAAY,SAAQ,gBAKS;CAAG;;mBAG5B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,gBAAgB,CAAC;kBAC3C,CAAC,EAAE,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,GAAG,gBAAgB,CAAC;;AAF7F,qBAAa,OAAQ,SAAQ,YAGS;IACpC,MAAM,CAAC,QAAQ,CAAC,KAAK,2DAqEpB;CACF"}
@@ -0,0 +1,83 @@
1
+ import { Context, Crypto, Effect, Layer, Ref, Schema, Semaphore } from "effect";
2
+ import { CatalogReadError, StackNotFound, StackSummary } from "../api.js";
3
+ import {} from "../schema.js";
4
+ export class StackSource extends Context.Service()("@knpkv/alchemy-console/StackSource") {
5
+ }
6
+ export class Catalog extends Context.Service()("@knpkv/alchemy-console/Catalog") {
7
+ static layer = Layer.effect(Catalog, Effect.gen(function* () {
8
+ const source = yield* StackSource;
9
+ const cryptoService = yield* Crypto.Crypto;
10
+ const entries = yield* Ref.make(new Map());
11
+ const lock = yield* Semaphore.make(1);
12
+ const list = Effect.fn("AlchemyConsole.catalogList")(function* () {
13
+ const discovered = yield* source.discover;
14
+ if (discovered.stacks.length > 1000 || discovered.issues.length > 1000) {
15
+ return yield* new CatalogReadError({ reason: "limit" });
16
+ }
17
+ const current = yield* Ref.get(entries);
18
+ const previous = new Map([...current].map(([id, entry]) => [entry.key, id]));
19
+ const next = new Map();
20
+ const keys = new Set();
21
+ const summaries = [];
22
+ for (const entry of discovered.stacks) {
23
+ if (keys.has(entry.key))
24
+ return yield* new CatalogReadError({ reason: "invalid-source" });
25
+ keys.add(entry.key);
26
+ const id = previous.get(entry.key) ?? (yield* cryptoService.randomUUIDv4.pipe(Effect.mapError(() => new CatalogReadError({ reason: "io" }))));
27
+ const summary = yield* Schema.decodeUnknownEffect(StackSummary)({
28
+ id,
29
+ app: entry.summary.app,
30
+ stage: entry.summary.stage,
31
+ backend: entry.summary.backend,
32
+ alchemyVersion: entry.summary.alchemyVersion,
33
+ lastDeploy: entry.summary.lastDeploy,
34
+ resourceCount: entry.summary.resourceCount
35
+ }).pipe(Effect.mapError(() => new CatalogReadError({ reason: "invalid-source" })));
36
+ next.set(id, entry);
37
+ summaries.push(summary);
38
+ }
39
+ const issues = discovered.issues.map((issue) => ({ source: issue.source, reason: issue.reason }));
40
+ yield* Ref.set(entries, next);
41
+ return { stacks: summaries, issues };
42
+ }, lock.withPermit, Effect.timeoutOrElse({
43
+ duration: "2 minutes",
44
+ orElse: () => Effect.fail(new CatalogReadError({ reason: "limit" }))
45
+ }));
46
+ const get = Effect.fn("AlchemyConsole.catalogGet")(function* (id) {
47
+ const entry = (yield* Ref.get(entries)).get(id);
48
+ if (entry === undefined)
49
+ return yield* new StackNotFound({});
50
+ const state = yield* entry.read;
51
+ if (state.app !== entry.summary.app || state.stage !== entry.summary.stage ||
52
+ state.backend !== entry.summary.backend)
53
+ return yield* new CatalogReadError({ reason: "invalid-source" });
54
+ if (state.resources.length > 50_000)
55
+ return yield* new CatalogReadError({ reason: "limit" });
56
+ return {
57
+ id,
58
+ state: {
59
+ app: state.app,
60
+ stage: state.stage,
61
+ backend: state.backend,
62
+ alchemyVersion: state.alchemyVersion,
63
+ lastDeploy: state.lastDeploy,
64
+ resources: state.resources.map(publicResource)
65
+ }
66
+ };
67
+ });
68
+ return Catalog.of({ list: list(), get });
69
+ }));
70
+ }
71
+ /** Explicit projection prevents a private reader's extra fields from reaching a transport encoder. */
72
+ const publicResource = (resource) => ({
73
+ fqn: resource.fqn,
74
+ logicalId: resource.logicalId,
75
+ resourceType: resource.resourceType,
76
+ status: resource.status,
77
+ parent: resource.parent,
78
+ providerId: resource.providerId,
79
+ account: resource.account,
80
+ region: resource.region,
81
+ consoleUrl: resource.consoleUrl
82
+ });
83
+ //# sourceMappingURL=Catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Catalog.js","sourceRoot":"","sources":["../../src/server/Catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Config, Effect, Path, Schema } from "effect";
2
+ export declare const Port: Schema.Int;
3
+ declare const StartupError_base: Schema.Class<StartupError, Schema.TaggedStruct<"StartupError", {
4
+ readonly reason: Schema.Literals<readonly ["config", "invalid-port", "package"]>;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ export declare class StartupError extends StartupError_base {
7
+ }
8
+ /** Resolve the manifest beside the built executable; release version edits need no source change. */
9
+ export declare const readPackageVersion: () => Effect.Effect<string, StartupError, import("effect/FileSystem").FileSystem | Path.Path>;
10
+ /** Read paths once at executable startup. None of this configuration crosses HTTP or browser storage. */
11
+ export declare const loadConfig: (home: string) => Effect.Effect<{
12
+ root: string;
13
+ awsConfigFile: string;
14
+ directory: string;
15
+ }, Config.ConfigError, Path.Path>;
16
+ export {};
17
+ //# sourceMappingURL=Config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/server/Config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGrD,eAAO,MAAM,IAAI,YAAwE,CAAA;;;;AAEzF,qBAAa,YAAa,SAAQ,iBAEhC;CAAG;AAEL,qGAAqG;AACrG,eAAO,MAAM,kBAAkB,+FAY7B,CAAA;AAEF,yGAAyG;AACzG,eAAO,MAAM,UAAU;;;;iCASrB,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { Config, Effect, Path, Schema } from "effect";
2
+ import { readText } from "../internal/files.js";
3
+ export const Port = Schema.Int.check(Schema.isBetween({ minimum: 1024, maximum: 65535 }));
4
+ export class StartupError extends Schema.TaggedError()("StartupError", {
5
+ reason: Schema.Literals(["config", "invalid-port", "package"])
6
+ }) {
7
+ }
8
+ /** Resolve the manifest beside the built executable; release version edits need no source change. */
9
+ export const readPackageVersion = Effect.fn("AlchemyConsole.readPackageVersion")(function* () {
10
+ const path = yield* Path.Path;
11
+ const file = yield* path.fromFileUrl(new URL("../../package.json", import.meta.url)).pipe(Effect.mapError(() => new StartupError({ reason: "package" })));
12
+ return yield* readText(file).pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Struct({ version: Schema.NonEmptyString })))), Effect.map(({ version }) => version), Effect.mapError(() => new StartupError({ reason: "package" })));
13
+ });
14
+ /** Read paths once at executable startup. None of this configuration crosses HTTP or browser storage. */
15
+ export const loadConfig = Effect.fn("AlchemyConsole.loadConfig")(function* (home) {
16
+ const path = yield* Path.Path;
17
+ return {
18
+ root: yield* Config.String("ALCHEMY_CONSOLE_ROOT").pipe(Config.withDefault(path.join(home, "Work", "dev"))),
19
+ awsConfigFile: yield* Config.String("AWS_CONFIG_FILE").pipe(Config.withDefault(path.join(home, ".aws", "config"))),
20
+ directory: yield* Config.String("ALCHEMY_CONSOLE_HOME").pipe(Config.withDefault(path.join(home, ".cache", "alchemy-console")))
21
+ };
22
+ });
23
+ //# sourceMappingURL=Config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Config.js","sourceRoot":"","sources":["../../src/server/Config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;AAEzF,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,cAAc,EAAE;IACnF,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;CAC/D,CAAC;CAAG;AAEL,qGAAqG;AACrG,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC,QAAQ,CAAC;IACxF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CACvF,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAC/D,CAAA;IACD,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAC/B,MAAM,CAAC,OAAO,CACZ,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CACrG,EACD,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EACpC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAC/D,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,yGAAyG;AACzG,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,2BAA2B,CAAC,CAAC,QAAQ,CAAC,EAAC,IAAY;IACrF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;IAC7B,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3G,aAAa,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;QAClH,SAAS,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAC1D,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CACjE;KACF,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,19 @@
1
+ import type { OwnerSessionService } from "@knpkv/browser-pairing/owner-session";
2
+ import { Effect, FileSystem, Option, Path, Schema } from "effect";
3
+ declare const ControlError_base: Schema.Class<ControlError, Schema.TaggedStruct<"ControlError", {
4
+ readonly reason: Schema.Literals<readonly ["unsafe", "io", "occupied", "path-limit", "invalid-reply", "timeout", "unsupported-platform"]>;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ export declare class ControlError extends ControlError_base {
7
+ }
8
+ /** Paths are server-private. The effective UID is read once at the executable boundary. */
9
+ export interface ControlOptions {
10
+ readonly directory: string;
11
+ readonly port: number;
12
+ readonly uid: number;
13
+ }
14
+ /** Bind atomically; refuse all pre-existing entries. Never unlink a possibly live server during startup. */
15
+ export declare const controlSocket: (options: ControlOptions, session: OwnerSessionService, listening: Effect.Effect<void, never, never>) => Effect.Effect<undefined, ControlError, FileSystem.FileSystem | Path.Path | import("effect/Scope").Scope>;
16
+ /** None means no socket exists. Unsafe paths, stale sockets and bad replies propagate without starting another server. */
17
+ export declare const requestLoginUrl: (options: ControlOptions) => Effect.Effect<Option.Option<string>, ControlError, FileSystem.FileSystem | Path.Path>;
18
+ export {};
19
+ //# sourceMappingURL=ControlSocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ControlSocket.d.ts","sourceRoot":"","sources":["../../src/server/ControlSocket.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAkB,MAAM,EAAE,MAAM,QAAQ,CAAA;;;;AAKjF,qBAAa,YAAa,SAAQ,iBAUhC;CAAG;AAEL,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AA6ED,4GAA4G;AAC5G,eAAO,MAAM,aAAa,mNA4CxB,CAAA;AAMF,0HAA0H;AAC1H,eAAO,MAAM,eAAe,oHA0B1B,CAAA"}
@@ -0,0 +1,147 @@
1
+ /** Owner-only local login channel. Credential URLs never enter diagnostics, logs, or telemetry. */
2
+ import { NodeSocket, NodeSocketServer } from "@effect/platform-node";
3
+ import { PairingCode } from "@knpkv/browser-pairing";
4
+ import { Effect, FileSystem, Option, Path, Predicate, Ref, Schema } from "effect";
5
+ import { mintBootstrapUrl } from "./OwnerSession.js";
6
+ export class ControlError extends Schema.TaggedError()("ControlError", {
7
+ reason: Schema.Literals([
8
+ "unsafe",
9
+ "io",
10
+ "occupied",
11
+ "path-limit",
12
+ "invalid-reply",
13
+ "timeout",
14
+ "unsupported-platform"
15
+ ])
16
+ }) {
17
+ }
18
+ const errnoSchema = Schema.Struct({ code: Schema.String });
19
+ const errno = (error) => Option.getOrUndefined(Schema.decodeUnknownOption(errnoSchema)(error._tag === "PlatformError" ? error.cause : error.reason.cause))?.code;
20
+ const unsafe = () => new ControlError({ reason: "unsafe" });
21
+ const io = () => new ControlError({ reason: "io" });
22
+ /** Check the final component without following a symlink. EINVAL alone proves it is not a link. */
23
+ const refuseLink = (fs, path) => fs.readLink(path).pipe(Effect.matchEffect({
24
+ onSuccess: () => Effect.fail(unsafe()),
25
+ onFailure: (error) => error.reason._tag === "NotFound" || errno(error) === "EINVAL" ?
26
+ Effect.void :
27
+ Effect.fail(unsafe())
28
+ }));
29
+ const location = Effect.fnUntraced(function* (options) {
30
+ const path = yield* Path.Path;
31
+ if (path.sep !== "/" || options.uid < 0)
32
+ return yield* new ControlError({ reason: "unsupported-platform" });
33
+ const socket = path.join(options.directory, `serve-${options.port}.sock`);
34
+ if (new TextEncoder().encode(socket).byteLength > 103)
35
+ return yield* new ControlError({ reason: "path-limit" });
36
+ return socket;
37
+ });
38
+ /** Existing directories must already be owned by this user and 0700; never tighten someone else's directory. */
39
+ const inspectDirectory = Effect.fnUntraced(function* (options, create) {
40
+ const fs = yield* FileSystem.FileSystem;
41
+ yield* refuseLink(fs, options.directory);
42
+ const present = yield* fs.exists(options.directory).pipe(Effect.mapError(io));
43
+ if (!present) {
44
+ if (!create)
45
+ return false;
46
+ yield* fs.makeDirectory(options.directory, { recursive: true, mode: 0o700 }).pipe(Effect.mapError(io));
47
+ }
48
+ const info = yield* fs.stat(options.directory).pipe(Effect.mapError(io));
49
+ if (info.type !== "Directory" || Option.getOrUndefined(info.uid) !== options.uid || (info.mode & 0o777) !== 0o700)
50
+ return yield* unsafe();
51
+ return true;
52
+ });
53
+ const inspectSocket = Effect.fnUntraced(function* (options, socket) {
54
+ const fs = yield* FileSystem.FileSystem;
55
+ yield* refuseLink(fs, socket);
56
+ if (!(yield* fs.exists(socket).pipe(Effect.mapError(io))))
57
+ return undefined;
58
+ const info = yield* fs.stat(socket).pipe(Effect.mapError(io));
59
+ if (info.type !== "Socket" || Option.getOrUndefined(info.uid) !== options.uid || (info.mode & 0o777) !== 0o600) {
60
+ return yield* unsafe();
61
+ }
62
+ const inode = Option.getOrUndefined(info.ino);
63
+ if (inode === undefined)
64
+ return yield* unsafe();
65
+ return inode;
66
+ });
67
+ /** Bound both bytes and time, including peers that disconnect or never finish a line. */
68
+ const readLine = Effect.fnUntraced(function* (reader) {
69
+ const decoder = new TextDecoder();
70
+ let text = "";
71
+ let bytes = 0;
72
+ while (!text.includes("\n")) {
73
+ const chunks = yield* reader.pull.pipe(Effect.mapError(io));
74
+ for (const chunk of chunks) {
75
+ bytes += Predicate.isString(chunk) ? new TextEncoder().encode(chunk).byteLength : chunk.byteLength;
76
+ if (bytes > 4096)
77
+ return yield* new ControlError({ reason: "invalid-reply" });
78
+ text += Predicate.isString(chunk) ? chunk : decoder.decode(chunk, { stream: true });
79
+ }
80
+ }
81
+ if (text.indexOf("\n") !== text.length - 1)
82
+ return yield* new ControlError({ reason: "invalid-reply" });
83
+ return text.slice(0, -1);
84
+ });
85
+ /** Bind atomically; refuse all pre-existing entries. Never unlink a possibly live server during startup. */
86
+ export const controlSocket = Effect.fn("AlchemyConsole.controlSocket")(function* (options, session, listening) {
87
+ const fs = yield* FileSystem.FileSystem;
88
+ const socketPath = yield* location(options);
89
+ yield* inspectDirectory(options, true);
90
+ yield* refuseLink(fs, socketPath);
91
+ if (yield* fs.exists(socketPath).pipe(Effect.mapError(io)))
92
+ return yield* new ControlError({ reason: "occupied" });
93
+ const identity = yield* Ref.make(undefined);
94
+ const server = yield* NodeSocketServer.make({ path: socketPath }).pipe(Effect.mapError((error) => new ControlError({ reason: errno(error) === "EADDRINUSE" ? "occupied" : "io" })));
95
+ // Register cleanup immediately after successful bind; identity checks prevent deleting a replacement.
96
+ yield* Effect.addFinalizer(() => Effect.gen(function* () {
97
+ const inode = yield* Ref.get(identity);
98
+ const current = yield* fs.stat(socketPath);
99
+ if (inode !== undefined && Option.getOrUndefined(current.ino) === inode && current.type === "Socket") {
100
+ yield* refuseLink(fs, socketPath);
101
+ yield* fs.remove(socketPath);
102
+ }
103
+ }).pipe(Effect.catch(() => Effect.logWarning("Alchemy console control cleanup failed; a stale socket may need removal."))));
104
+ const bound = yield* fs.stat(socketPath).pipe(Effect.mapError(io));
105
+ yield* Ref.set(identity, Option.getOrUndefined(bound.ino));
106
+ yield* fs.chmod(socketPath, 0o600).pipe(Effect.mapError(io));
107
+ yield* inspectSocket(options, socketPath);
108
+ const answer = (socket) => Effect.scoped(Effect.gen(function* () {
109
+ const reader = yield* socket.reader;
110
+ const writer = yield* socket.writer;
111
+ if ((yield* readLine(reader)) !== "mint")
112
+ return;
113
+ yield* listening;
114
+ const url = yield* mintBootstrapUrl(session);
115
+ yield* writer.write(`${JSON.stringify({ url })}\n`);
116
+ })).pipe(Effect.timeout("5 seconds"), Effect.catch(() => Effect.logWarning("Alchemy console control exchange failed.")));
117
+ yield* Effect.forkScoped(server.run(answer).pipe(Effect.mapError(io)));
118
+ });
119
+ /** Credential-bearing response: one loopback URL containing a single-use PairingCode. */
120
+ const LoginReply = Schema.fromJsonString(Schema.Struct({ url: Schema.String }));
121
+ const isCode = Schema.is(PairingCode);
122
+ /** None means no socket exists. Unsafe paths, stale sockets and bad replies propagate without starting another server. */
123
+ export const requestLoginUrl = Effect.fn("AlchemyConsole.requestLoginUrl")(function* (options) {
124
+ const socketPath = yield* location(options);
125
+ if (!(yield* inspectDirectory(options, false)))
126
+ return Option.none();
127
+ if ((yield* inspectSocket(options, socketPath)) === undefined)
128
+ return Option.none();
129
+ const reply = yield* Effect.scoped(Effect.gen(function* () {
130
+ const socket = yield* NodeSocket.makeNet({ path: socketPath });
131
+ const reader = yield* socket.reader;
132
+ const writer = yield* socket.writer;
133
+ yield* writer.write("mint\n");
134
+ return yield* readLine(reader);
135
+ })).pipe(Effect.mapError(io), Effect.timeoutOrElse({ duration: "5 seconds", orElse: () => Effect.fail(new ControlError({ reason: "timeout" })) }));
136
+ const decoded = yield* Schema.decodeUnknownEffect(LoginReply)(reply).pipe(Effect.mapError(() => new ControlError({ reason: "invalid-reply" })));
137
+ if (!URL.canParse(decoded.url))
138
+ return yield* new ControlError({ reason: "invalid-reply" });
139
+ const url = new URL(decoded.url);
140
+ const origin = `http://127.0.0.1:${options.port}`;
141
+ const prefix = "#bootstrap_token=";
142
+ if (url.origin !== origin || url.pathname !== "/" || url.search !== "" || url.username !== "" ||
143
+ url.password !== "" || !url.hash.startsWith(prefix) || !isCode(url.hash.slice(prefix.length)))
144
+ return yield* new ControlError({ reason: "invalid-reply" });
145
+ return Option.some(decoded.url);
146
+ });
147
+ //# sourceMappingURL=ControlSocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ControlSocket.js","sourceRoot":"","sources":["../../src/server/ControlSocket.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import * as OwnerSession from "@knpkv/browser-pairing/owner-session";
2
+ import { Layer } from "effect";
3
+ import { HttpRouter } from "effect/http";
4
+ import { Catalog } from "./Catalog.js";
5
+ /** Listener, source readers and owner session belong to the executable's runtime layer. */
6
+ export declare const application: Layer.Layer<never, import("effect/PlatformError").BadArgument | import("effect/PlatformError").PlatformError, Catalog | import("effect/FileSystem").FileSystem | import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | HttpRouter.HttpRouter | OwnerSession.OwnerSession | import("effect/Path").Path | HttpRouter.Request<"Error", import("effect/http/HttpBody").HttpBodyError>>;
7
+ //# sourceMappingURL=HttpApplication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpApplication.d.ts","sourceRoot":"","sources":["../../src/server/HttpApplication.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,UAAU,EAAyC,MAAM,aAAa,CAAA;AAI/E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AA0CtC,2FAA2F;AAC3F,eAAO,MAAM,WAAW,uZAKvB,CAAA"}
@@ -0,0 +1,46 @@
1
+ import * as OwnerSession from "@knpkv/browser-pairing/owner-session";
2
+ import { Effect, Layer } from "effect";
3
+ import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
4
+ import { HttpApiBuilder } from "effect/http-api";
5
+ import { AlchemyConsoleApi } from "../api.js";
6
+ import { BootstrapRoutes } from "./Bootstrap.js";
7
+ import { Catalog } from "./Catalog.js";
8
+ import { ownerAuthLayer } from "./OwnerSession.js";
9
+ const handlers = HttpApiBuilder.group(AlchemyConsoleApi, "stacks", (handlers) => Effect.gen(function* () {
10
+ const catalog = yield* Catalog;
11
+ return handlers.handle("list", () => catalog.list).handle("get", ({ params }) => catalog.get(params.id));
12
+ }));
13
+ /** Refuse unsafe/unmatched API requests before handlers; even refusals and missing routes cannot be cached. */
14
+ const boundary = Layer.unwrap(Effect.gen(function* () {
15
+ const session = yield* OwnerSession.OwnerSession;
16
+ const host = new URL(session.authorityOrigin).host;
17
+ return HttpRouter.middleware((httpEffect) => Effect.gen(function* () {
18
+ const request = yield* HttpServerRequest.HttpServerRequest;
19
+ if (request.headers.host !== host)
20
+ return HttpServerResponse.empty({ status: 403 });
21
+ if (!URL.canParse(request.url, session.authorityOrigin))
22
+ return HttpServerResponse.empty({ status: 400 });
23
+ const url = new URL(request.url, session.authorityOrigin);
24
+ if (url.origin !== session.authorityOrigin)
25
+ return HttpServerResponse.empty({ status: 403 });
26
+ const pathname = url.pathname;
27
+ if (pathname === "/api" || pathname.startsWith("/api/")) {
28
+ const authorized = yield* Effect.result(session.authorizeHttp(request.cookies[session.cookieName] ?? ""));
29
+ if (authorized._tag === "Failure") {
30
+ return HttpServerResponse.empty({
31
+ status: authorized.failure._tag === "OwnerSessionUnauthorizedError" ? 401 : 403
32
+ });
33
+ }
34
+ }
35
+ return yield* httpEffect;
36
+ }).pipe(Effect.map((response) => response.pipe(HttpServerResponse.setHeaders({
37
+ "cache-control": "private, no-store",
38
+ "referrer-policy": "no-referrer",
39
+ "x-content-type-options": "nosniff",
40
+ "x-frame-options": "DENY",
41
+ "content-security-policy": "default-src 'none'; script-src 'self'; connect-src 'self'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'"
42
+ })))), { global: true });
43
+ }));
44
+ /** Listener, source readers and owner session belong to the executable's runtime layer. */
45
+ export const application = Layer.mergeAll(HttpApiBuilder.layer(AlchemyConsoleApi).pipe(Layer.provide(handlers), Layer.provide(ownerAuthLayer)), OwnerSession.BootstrapRouter, BootstrapRoutes, boundary);
46
+ //# sourceMappingURL=HttpApplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpApplication.js","sourceRoot":"","sources":["../../src/server/HttpApplication.ts"],"names":[],"mappings":"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"}