@knpkv/alchemy-console 0.0.0-stage → 0.2.0

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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -2
  3. package/dist/api.d.ts +126 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +62 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/client/bootstrap.js +2834 -0
  8. package/dist/discovery.d.ts +12 -0
  9. package/dist/discovery.d.ts.map +1 -0
  10. package/dist/discovery.js +39 -0
  11. package/dist/discovery.js.map +1 -0
  12. package/dist/index.d.ts +14 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +11 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/internal/files.d.ts +9 -0
  17. package/dist/internal/files.d.ts.map +1 -0
  18. package/dist/internal/files.js +34 -0
  19. package/dist/internal/files.js.map +1 -0
  20. package/dist/local-state.d.ts +8 -0
  21. package/dist/local-state.d.ts.map +1 -0
  22. package/dist/local-state.js +53 -0
  23. package/dist/local-state.js.map +1 -0
  24. package/dist/main.d.ts +3 -0
  25. package/dist/main.d.ts.map +1 -0
  26. package/dist/main.js +39 -0
  27. package/dist/main.js.map +1 -0
  28. package/dist/profiles.d.ts +24 -0
  29. package/dist/profiles.d.ts.map +1 -0
  30. package/dist/profiles.js +82 -0
  31. package/dist/profiles.js.map +1 -0
  32. package/dist/s3-live.d.ts +13 -0
  33. package/dist/s3-live.d.ts.map +1 -0
  34. package/dist/s3-live.js +112 -0
  35. package/dist/s3-live.js.map +1 -0
  36. package/dist/s3-reader.d.ts +46 -0
  37. package/dist/s3-reader.d.ts.map +1 -0
  38. package/dist/s3-reader.js +10 -0
  39. package/dist/s3-reader.js.map +1 -0
  40. package/dist/s3-state.d.ts +21 -0
  41. package/dist/s3-state.d.ts.map +1 -0
  42. package/dist/s3-state.js +129 -0
  43. package/dist/s3-state.js.map +1 -0
  44. package/dist/schema.d.ts +43 -0
  45. package/dist/schema.d.ts.map +1 -0
  46. package/dist/schema.js +27 -0
  47. package/dist/schema.js.map +1 -0
  48. package/dist/server/Bootstrap.d.ts +4 -0
  49. package/dist/server/Bootstrap.d.ts.map +1 -0
  50. package/dist/server/Bootstrap.js +12 -0
  51. package/dist/server/Bootstrap.js.map +1 -0
  52. package/dist/server/Catalog.d.ts +27 -0
  53. package/dist/server/Catalog.d.ts.map +1 -0
  54. package/dist/server/Catalog.js +83 -0
  55. package/dist/server/Catalog.js.map +1 -0
  56. package/dist/server/Config.d.ts +17 -0
  57. package/dist/server/Config.d.ts.map +1 -0
  58. package/dist/server/Config.js +23 -0
  59. package/dist/server/Config.js.map +1 -0
  60. package/dist/server/ControlSocket.d.ts +19 -0
  61. package/dist/server/ControlSocket.d.ts.map +1 -0
  62. package/dist/server/ControlSocket.js +147 -0
  63. package/dist/server/ControlSocket.js.map +1 -0
  64. package/dist/server/HttpApplication.d.ts +7 -0
  65. package/dist/server/HttpApplication.d.ts.map +1 -0
  66. package/dist/server/HttpApplication.js +46 -0
  67. package/dist/server/HttpApplication.js.map +1 -0
  68. package/dist/server/Launch.d.ts +7 -0
  69. package/dist/server/Launch.d.ts.map +1 -0
  70. package/dist/server/Launch.js +17 -0
  71. package/dist/server/Launch.js.map +1 -0
  72. package/dist/server/OwnerSession.d.ts +9 -0
  73. package/dist/server/OwnerSession.d.ts.map +1 -0
  74. package/dist/server/OwnerSession.js +27 -0
  75. package/dist/server/OwnerSession.js.map +1 -0
  76. package/dist/server/Server.d.ts +6 -0
  77. package/dist/server/Server.d.ts.map +1 -0
  78. package/dist/server/Server.js +22 -0
  79. package/dist/server/Server.js.map +1 -0
  80. package/dist/server/Sources.d.ts +12 -0
  81. package/dist/server/Sources.d.ts.map +1 -0
  82. package/dist/server/Sources.js +118 -0
  83. package/dist/server/Sources.js.map +1 -0
  84. package/dist/sso-credentials.d.ts +17 -0
  85. package/dist/sso-credentials.d.ts.map +1 -0
  86. package/dist/sso-credentials.js +43 -0
  87. package/dist/sso-credentials.js.map +1 -0
  88. package/dist/state.d.ts +15 -0
  89. package/dist/state.d.ts.map +1 -0
  90. package/dist/state.js +45 -0
  91. package/dist/state.js.map +1 -0
  92. package/dist/version.d.ts +5 -0
  93. package/dist/version.d.ts.map +1 -0
  94. package/dist/version.js +61 -0
  95. package/dist/version.js.map +1 -0
  96. package/package.json +60 -3
@@ -0,0 +1,12 @@
1
+ import { Effect, FileSystem, Path, Schema } from "effect";
2
+ import { StateReadError } from "./schema.js";
3
+ /** Server-private paths. Retain only in memory; never emit to HTTP, browser storage, logs, or telemetry. */
4
+ export declare const Project: Schema.Struct<{
5
+ readonly directory: Schema.String;
6
+ readonly entrypoint: Schema.String;
7
+ }>;
8
+ export interface Project extends Schema.Schema.Type<typeof Project> {
9
+ }
10
+ /** Read directory metadata only. No stack imports, evaluation, subprocesses, or credential reads. */
11
+ export declare const discoverProjects: (directory: string) => Effect.Effect<Project[], StateReadError, FileSystem.FileSystem | Path.Path>;
12
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,4GAA4G;AAC5G,eAAO,MAAM,OAAO;;;EAAyE,CAAA;AAC7F,MAAM,WAAW,OAAQ,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAItE,qGAAqG;AACrG,eAAO,MAAM,gBAAgB,oGAyB3B,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { Effect, FileSystem, Path, Schema } from "effect";
2
+ import { entries, stat, withinRoot } from "./internal/files.js";
3
+ import { StateReadError } from "./schema.js";
4
+ /** Server-private paths. Retain only in memory; never emit to HTTP, browser storage, logs, or telemetry. */
5
+ export const Project = Schema.Struct({ directory: Schema.String, entrypoint: Schema.String });
6
+ const excluded = new Set([".git", "node_modules", ".alchemy", ".direnv", ".cache", "dist"]);
7
+ /** Read directory metadata only. No stack imports, evaluation, subprocesses, or credential reads. */
8
+ export const discoverProjects = Effect.fn("AlchemyConsole.discoverProjects")(function* (directory) {
9
+ const fs = yield* FileSystem.FileSystem;
10
+ const path = yield* Path.Path;
11
+ const root = yield* fs.realPath(directory).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
12
+ const pending = [root];
13
+ const visited = new Set();
14
+ const projects = [];
15
+ while (pending.length > 0) {
16
+ const candidate = pending.pop();
17
+ if (candidate === undefined)
18
+ break;
19
+ const current = yield* withinRoot(root, candidate);
20
+ if (visited.has(current))
21
+ continue;
22
+ visited.add(current);
23
+ if (visited.size > 50_000)
24
+ return yield* new StateReadError({ reason: "limit" });
25
+ for (const name of yield* entries(current)) {
26
+ if (excluded.has(name))
27
+ continue;
28
+ const file = yield* withinRoot(root, path.join(current, name));
29
+ const info = yield* stat(file);
30
+ if (info.type === "Directory")
31
+ pending.push(file);
32
+ else if (name === "alchemy.run.ts" && info.type === "File") {
33
+ projects.push(Project.make({ directory: current, entrypoint: file }));
34
+ }
35
+ }
36
+ }
37
+ return projects.sort((a, b) => a.directory.localeCompare(b.directory));
38
+ });
39
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export { discoverProjects, Project } from "./discovery.js";
2
+ export { readLocalState } from "./local-state.js";
3
+ export { discoverSsoProfiles, SsoProfile, SsoProfileError } from "./profiles.js";
4
+ export { s3ReaderLayer } from "./s3-live.js";
5
+ export { S3Reader, S3ReadError } from "./s3-reader.js";
6
+ export type { S3Bucket, S3BucketPage, S3Version, S3VersionPage, VersionCursor } from "./s3-reader.js";
7
+ export { discoverS3Buckets, discoverS3Stacks, listS3Versions, readS3Resource, readS3State } from "./s3-state.js";
8
+ export type { S3StackLocator } from "./s3-state.js";
9
+ export { ResourceSummary, StackState, StateReadError } from "./schema.js";
10
+ export { SsoCredentials, ssoCredentialsLayer } from "./sso-credentials.js";
11
+ export type { SsoCredentialProviderFactory } from "./sso-credentials.js";
12
+ export { decodeResource } from "./state.js";
13
+ export { readAlchemyVersion } from "./version.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACtD,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACrG,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChH,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1E,YAAY,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { discoverProjects, Project } from "./discovery.js";
2
+ export { readLocalState } from "./local-state.js";
3
+ export { discoverSsoProfiles, SsoProfile, SsoProfileError } from "./profiles.js";
4
+ export { s3ReaderLayer } from "./s3-live.js";
5
+ export { S3Reader, S3ReadError } from "./s3-reader.js";
6
+ export { discoverS3Buckets, discoverS3Stacks, listS3Versions, readS3Resource, readS3State } from "./s3-state.js";
7
+ export { ResourceSummary, StackState, StateReadError } from "./schema.js";
8
+ export { SsoCredentials, ssoCredentialsLayer } from "./sso-credentials.js";
9
+ export { decodeResource } from "./state.js";
10
+ export { readAlchemyVersion } from "./version.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { Effect, FileSystem, Path } from "effect";
2
+ import { StateReadError } from "../schema.js";
3
+ export declare const readText: (file: string) => Effect.Effect<string, StateReadError, FileSystem.FileSystem>;
4
+ export declare const entries: (directory: string) => Effect.Effect<string[], StateReadError, FileSystem.FileSystem>;
5
+ /** Resolve before inspecting a candidate; symlinks may not escape the caller's explicit root. */
6
+ export declare const withinRoot: (root: string, candidate: string) => Effect.Effect<string, StateReadError, FileSystem.FileSystem | Path.Path>;
7
+ export declare const exists: (file: string) => Effect.Effect<boolean, StateReadError, FileSystem.FileSystem>;
8
+ export declare const stat: (file: string) => Effect.Effect<FileSystem.File.Info, StateReadError, FileSystem.FileSystem>;
9
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/internal/files.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,eAAO,MAAM,QAAQ,gFAKnB,CAAA;AAEF,eAAO,MAAM,OAAO,uFAOlB,CAAA;AAEF,iGAAiG;AACjG,eAAO,MAAM,UAAU,+GASrB,CAAA;AAEF,eAAO,MAAM,MAAM,iFAGjB,CAAA;AAEF,eAAO,MAAM,IAAI,8FAGf,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { collectBoundedText } from "@knpkv/bounded-io";
2
+ import { Effect, FileSystem, Path } from "effect";
3
+ import { StateReadError } from "../schema.js";
4
+ export const readText = Effect.fn("AlchemyConsole.readText")(function* (file) {
5
+ const fs = yield* FileSystem.FileSystem;
6
+ return yield* collectBoundedText(fs.stream(file), 8 * 1024 * 1024).pipe(Effect.mapError((error) => new StateReadError({ reason: error._tag === "ByteLimitExceeded" ? "limit" : "io" })));
7
+ });
8
+ export const entries = Effect.fn("AlchemyConsole.entries")(function* (directory) {
9
+ const fs = yield* FileSystem.FileSystem;
10
+ const names = yield* fs.readDirectory(directory).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
11
+ if (names.length > 50_000)
12
+ return yield* new StateReadError({ reason: "limit" });
13
+ return names.sort();
14
+ });
15
+ /** Resolve before inspecting a candidate; symlinks may not escape the caller's explicit root. */
16
+ export const withinRoot = Effect.fn("AlchemyConsole.withinRoot")(function* (root, candidate) {
17
+ const fs = yield* FileSystem.FileSystem;
18
+ const path = yield* Path.Path;
19
+ const real = yield* fs.realPath(candidate).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
20
+ const relative = path.relative(root, real);
21
+ if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
22
+ return yield* new StateReadError({ reason: "outside-root" });
23
+ }
24
+ return real;
25
+ });
26
+ export const exists = Effect.fn("AlchemyConsole.exists")(function* (file) {
27
+ const fs = yield* FileSystem.FileSystem;
28
+ return yield* fs.exists(file).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
29
+ });
30
+ export const stat = Effect.fn("AlchemyConsole.stat")(function* (file) {
31
+ const fs = yield* FileSystem.FileSystem;
32
+ return yield* fs.stat(file).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
33
+ });
34
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/internal/files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Effect, FileSystem, Path } from "effect";
2
+ import { type StackState, StateReadError } from "./schema.js";
3
+ /** Reads .alchemy/state/<app>/<stage>/<encoded-fqn>.json. Missing state is distinct from an empty stage. */
4
+ export declare const readLocalState: (directory: string, alchemyVersion: string | null) => Effect.Effect<{
5
+ available: boolean;
6
+ stacks: StackState[];
7
+ }, StateReadError, FileSystem.FileSystem | Path.Path>;
8
+ //# sourceMappingURL=local-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-state.d.ts","sourceRoot":"","sources":["../src/local-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,KAAK,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAG7D,4GAA4G;AAC5G,eAAO,MAAM,cAAc;;;qDA2CzB,CAAA"}
@@ -0,0 +1,53 @@
1
+ import { Effect, FileSystem, Path } from "effect";
2
+ import { entries, exists, readText, stat, withinRoot } from "./internal/files.js";
3
+ import { StateReadError } from "./schema.js";
4
+ import { decodeResource } from "./state.js";
5
+ /** Reads .alchemy/state/<app>/<stage>/<encoded-fqn>.json. Missing state is distinct from an empty stage. */
6
+ export const readLocalState = Effect.fn("AlchemyConsole.readLocalState")(function* (directory, alchemyVersion) {
7
+ if (alchemyVersion !== "2.0.0-beta.74" && alchemyVersion !== "2.0.0-beta.77") {
8
+ return yield* new StateReadError({ reason: "unsupported-version" });
9
+ }
10
+ const fs = yield* FileSystem.FileSystem;
11
+ const path = yield* Path.Path;
12
+ const root = yield* fs.realPath(directory).pipe(Effect.mapError(() => new StateReadError({ reason: "io" })));
13
+ const candidate = path.join(root, ".alchemy", "state");
14
+ if (!(yield* exists(candidate)))
15
+ return { available: false, stacks: [] };
16
+ const stateRoot = yield* withinRoot(root, candidate);
17
+ const stacks = [];
18
+ for (const app of yield* entries(stateRoot)) {
19
+ const appDir = yield* withinRoot(stateRoot, path.join(stateRoot, app));
20
+ if ((yield* stat(appDir)).type !== "Directory")
21
+ continue;
22
+ for (const stage of yield* entries(appDir)) {
23
+ const stageDir = yield* withinRoot(appDir, path.join(appDir, stage));
24
+ if ((yield* stat(stageDir)).type !== "Directory")
25
+ continue;
26
+ const resources = [];
27
+ for (const name of yield* entries(stageDir)) {
28
+ if (!name.endsWith(".json") || name === "__stack_output__.json")
29
+ continue;
30
+ const file = yield* withinRoot(stageDir, path.join(stageDir, name));
31
+ if ((yield* stat(file)).type !== "File")
32
+ return yield* new StateReadError({ reason: "invalid-state" });
33
+ const resource = yield* decodeResource(yield* readText(file));
34
+ if (resource === null)
35
+ continue;
36
+ if (name !== `${resource.fqn.replaceAll("/", "__")}.json`) {
37
+ return yield* new StateReadError({ reason: "invalid-state" });
38
+ }
39
+ resources.push(resource);
40
+ }
41
+ stacks.push({
42
+ app,
43
+ stage,
44
+ backend: "local",
45
+ alchemyVersion,
46
+ lastDeploy: null,
47
+ resources: resources.sort((a, b) => a.fqn.localeCompare(b.fqn))
48
+ });
49
+ }
50
+ }
51
+ return { available: true, stacks };
52
+ });
53
+ //# sourceMappingURL=local-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-state.js","sourceRoot":"","sources":["../src/local-state.ts"],"names":[],"mappings":"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"}
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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"}
@@ -0,0 +1,24 @@
1
+ import { Effect, Schema } from "effect";
2
+ /** Server-private SSO configuration. Keep every field in memory, out of HTTP, browser storage, logs and telemetry. */
3
+ export declare const SsoProfile: Schema.Struct<{
4
+ readonly name: Schema.NonEmptyString;
5
+ readonly configFile: Schema.NonEmptyString;
6
+ readonly account: Schema.NonEmptyString;
7
+ readonly role: Schema.NonEmptyString;
8
+ readonly region: Schema.NonEmptyString;
9
+ readonly ssoRegion: Schema.NonEmptyString;
10
+ readonly startUrl: Schema.NonEmptyString;
11
+ readonly session: Schema.NullOr<Schema.NonEmptyString>;
12
+ }>;
13
+ export interface SsoProfile extends Schema.Schema.Type<typeof SsoProfile> {
14
+ }
15
+ declare const SsoProfileError_base: Schema.Class<SsoProfileError, Schema.TaggedStruct<"SsoProfileError", {
16
+ readonly reason: Schema.Literals<readonly ["io", "limit", "invalid-config"]>;
17
+ }>, import("effect/Cause").YieldableError>;
18
+ /** Safe reason only; SDK/parser diagnostics can contain private configuration. */
19
+ export declare class SsoProfileError extends SsoProfileError_base {
20
+ }
21
+ /** Read only the supplied AWS config; skip static/process/role profiles and resolve modern or legacy SSO sections. */
22
+ export declare const discoverSsoProfiles: (configFile: string) => Effect.Effect<SsoProfile[], SsoProfileError, import("effect/FileSystem").FileSystem>;
23
+ export {};
24
+ //# sourceMappingURL=profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGvC,sHAAsH;AACtH,eAAO,MAAM,UAAU;;;;;;;;;EASrB,CAAA;AACF,MAAM,WAAW,UAAW,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC;CAAG;;;;AAE5E,kFAAkF;AAClF,qBAAa,eAAgB,SAAQ,oBAEnC;CAAG;AA2BL,sHAAsH;AACtH,eAAO,MAAM,mBAAmB,8GAkC9B,CAAA"}
@@ -0,0 +1,82 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { exists, readText } from "./internal/files.js";
3
+ /** Server-private SSO configuration. Keep every field in memory, out of HTTP, browser storage, logs and telemetry. */
4
+ export const SsoProfile = Schema.Struct({
5
+ name: Schema.NonEmptyString,
6
+ configFile: Schema.NonEmptyString,
7
+ account: Schema.NonEmptyString,
8
+ role: Schema.NonEmptyString,
9
+ region: Schema.NonEmptyString,
10
+ ssoRegion: Schema.NonEmptyString,
11
+ startUrl: Schema.NonEmptyString,
12
+ session: Schema.NullOr(Schema.NonEmptyString)
13
+ });
14
+ /** Safe reason only; SDK/parser diagnostics can contain private configuration. */
15
+ export class SsoProfileError extends Schema.TaggedError()("SsoProfileError", {
16
+ reason: Schema.Literals(["io", "limit", "invalid-config"])
17
+ }) {
18
+ }
19
+ /** Select only SSO fields; static keys and commands are discarded while parsing. */
20
+ const parseSections = Effect.fnUntraced(function* (text) {
21
+ const sections = new Map();
22
+ let fields;
23
+ for (const line of text.split(/\r?\n/)) {
24
+ const trimmed = line.split(/(^|\s)[;#]/)[0]?.trim() ?? "";
25
+ if (trimmed.length === 0)
26
+ continue;
27
+ if (trimmed.startsWith("[")) {
28
+ const match = /^\[([^\]]+)\]$/.exec(trimmed);
29
+ if (match?.[1] === undefined || match[1].length === 0) {
30
+ return yield* new SsoProfileError({ reason: "invalid-config" });
31
+ }
32
+ const name = match[1].trim().replace(/^(profile|sso-session)\s+["']?([^"']+)["']?$/, "$1.$2");
33
+ fields = sections.get(name) ?? new Map();
34
+ sections.set(name, fields);
35
+ continue;
36
+ }
37
+ const equals = trimmed.indexOf("=");
38
+ if (fields === undefined || equals <= 0)
39
+ continue;
40
+ const key = trimmed.slice(0, equals).trim();
41
+ if (key === "region" || key.startsWith("sso_"))
42
+ fields.set(key, trimmed.slice(equals + 1).trim());
43
+ }
44
+ return new Map([...sections].map(([name, fields]) => [name, Object.fromEntries(fields)]));
45
+ });
46
+ /** Read only the supplied AWS config; skip static/process/role profiles and resolve modern or legacy SSO sections. */
47
+ export const discoverSsoProfiles = Effect.fn("AlchemyConsole.discoverSsoProfiles")(function* (configFile) {
48
+ const present = yield* exists(configFile).pipe(Effect.mapError(() => new SsoProfileError({ reason: "io" })));
49
+ if (!present)
50
+ return [];
51
+ const text = yield* readText(configFile).pipe(Effect.mapError((error) => new SsoProfileError({ reason: error.reason === "limit" ? "limit" : "io" })));
52
+ const ini = yield* parseSections(text);
53
+ const profiles = [];
54
+ for (const [section, fields] of ini) {
55
+ if (section !== "default" && !section.startsWith("profile."))
56
+ continue;
57
+ if (!Object.keys(fields).some((key) => key.startsWith("sso_")))
58
+ continue;
59
+ const session = fields.sso_session === undefined ? undefined : ini.get(`sso-session.${fields.sso_session}`);
60
+ if (fields.sso_session !== undefined && session === undefined) {
61
+ return yield* new SsoProfileError({ reason: "invalid-config" });
62
+ }
63
+ const ssoRegion = session?.sso_region ?? fields.sso_region;
64
+ const startUrl = session?.sso_start_url ?? fields.sso_start_url;
65
+ if ((fields.sso_region !== undefined && fields.sso_region !== ssoRegion) ||
66
+ (fields.sso_start_url !== undefined && fields.sso_start_url !== startUrl))
67
+ return yield* new SsoProfileError({ reason: "invalid-config" });
68
+ const profile = yield* Schema.decodeUnknownEffect(SsoProfile)({
69
+ name: section === "default" ? section : section.slice("profile.".length),
70
+ configFile,
71
+ account: fields.sso_account_id,
72
+ role: fields.sso_role_name,
73
+ region: fields.region ?? ssoRegion,
74
+ ssoRegion,
75
+ startUrl,
76
+ session: fields.sso_session ?? null
77
+ }).pipe(Effect.mapError(() => new SsoProfileError({ reason: "invalid-config" })));
78
+ profiles.push(profile);
79
+ }
80
+ return profiles.sort((a, b) => a.name.localeCompare(b.name));
81
+ });
82
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Effect, Layer } from "effect";
2
+ import * as HttpClient from "effect/http/HttpClient";
3
+ import type { SsoProfile } from "./profiles.js";
4
+ import { type S3Bucket, S3Reader, S3ReadError, type VersionCursor } from "./s3-reader.js";
5
+ import { SsoCredentials } from "./sso-credentials.js";
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>;
12
+ export declare const s3ReaderLayer: (profile: SsoProfile) => Layer.Layer<S3Reader, never, HttpClient.HttpClient | SsoCredentials>;
13
+ //# sourceMappingURL=s3-live.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,112 @@
1
+ import { Credentials } from "@distilled.cloud/aws/Credentials";
2
+ import { Region } from "@distilled.cloud/aws/Region";
3
+ import { getObject, listBuckets, listObjectVersions } from "@distilled.cloud/aws/s3";
4
+ import { collectBoundedText } from "@knpkv/bounded-io";
5
+ import { Effect, Layer, Predicate } from "effect";
6
+ import * as HttpClient from "effect/http/HttpClient";
7
+ import { S3Reader, S3ReadError } from "./s3-reader.js";
8
+ import { SsoCredentials } from "./sso-credentials.js";
9
+ import { decodeResource } from "./state.js";
10
+ const providerError = (error) => {
11
+ if (error._tag === "S3ReadError")
12
+ return error;
13
+ const tag = error._tag === "UnknownAwsError" ? error.errorTag : error._tag;
14
+ if (tag === "AccessDenied" || tag === "AccessDeniedException") {
15
+ return new S3ReadError({ reason: "denied" });
16
+ }
17
+ if (["NoSuchKey", "NoSuchVersion", "NoSuchBucket"].includes(tag))
18
+ return new S3ReadError({ reason: "not-found" });
19
+ if (["ExpiredToken", "ExpiredTokenException", "InvalidToken", "InvalidAccessKeyId", "SignatureDoesNotMatch"].includes(tag)) {
20
+ return new S3ReadError({ reason: "authentication" });
21
+ }
22
+ return new S3ReadError({ reason: "provider" });
23
+ };
24
+ /** Independent read-only adapter. ExpectedBucketOwner binds requests to the selected SSO account. */
25
+ export const makeS3Reader = Effect.fn("AlchemyConsole.makeS3Reader")(function* (profile) {
26
+ const client = yield* HttpClient.HttpClient;
27
+ const sso = yield* SsoCredentials;
28
+ const call = Effect.fn("AlchemyConsole.callS3")(function* (effect, region) {
29
+ const credentials = yield* sso.resolve(profile);
30
+ return yield* effect.pipe(Effect.provideService(Credentials, Effect.succeed(credentials)), Effect.provideService(Region, Effect.succeed(region)), Effect.provideService(HttpClient.HttpClient, client),
31
+ // S3 request URLs contain server-private bucket, key and version locators.
32
+ Effect.provideService(HttpClient.TracerDisabledWhen, () => true), Effect.timeoutOrElse({
33
+ duration: "30 seconds",
34
+ orElse: () => Effect.fail(new S3ReadError({ reason: "provider" }))
35
+ }), Effect.mapError(providerError));
36
+ });
37
+ return S3Reader.of({
38
+ buckets: Effect.fn("AlchemyConsole.listS3Buckets")(function* (cursor) {
39
+ const request = { MaxBuckets: 1000 };
40
+ if (cursor !== null)
41
+ request.ContinuationToken = cursor;
42
+ const page = yield* call(listBuckets(request), profile.region);
43
+ const buckets = [];
44
+ for (const bucket of page.Buckets ?? []) {
45
+ if (bucket.Name === undefined || bucket.Name.length === 0 || bucket.BucketRegion === undefined ||
46
+ bucket.BucketRegion.length === 0)
47
+ return yield* new S3ReadError({ reason: "invalid-response" });
48
+ buckets.push({ name: bucket.Name, region: bucket.BucketRegion });
49
+ }
50
+ return { buckets, next: page.ContinuationToken ?? null };
51
+ }),
52
+ versions: Effect.fn("AlchemyConsole.listS3Versions")(function* (bucket, prefix, cursor) {
53
+ const request = {
54
+ Bucket: bucket.name,
55
+ ExpectedBucketOwner: profile.account,
56
+ Prefix: prefix,
57
+ MaxKeys: 1000
58
+ };
59
+ if (cursor !== null) {
60
+ request.KeyMarker = cursor.key;
61
+ if (cursor.versionId !== null)
62
+ request.VersionIdMarker = cursor.versionId;
63
+ }
64
+ const page = yield* call(listObjectVersions(request), bucket.region);
65
+ const versions = [];
66
+ const groups = [
67
+ { rows: page.Versions ?? [], deleted: false },
68
+ { rows: page.DeleteMarkers ?? [], deleted: true }
69
+ ];
70
+ for (const { deleted, rows } of groups) {
71
+ for (const row of rows) {
72
+ if (row.Key === undefined || row.Key.length === 0 || row.VersionId === undefined ||
73
+ row.VersionId.length === 0 || row.IsLatest === undefined) {
74
+ return yield* new S3ReadError({ reason: "invalid-response" });
75
+ }
76
+ versions.push({ key: row.Key, versionId: row.VersionId, latest: row.IsLatest, deleted });
77
+ }
78
+ }
79
+ if (page.IsTruncated === undefined ||
80
+ (page.IsTruncated && (page.NextKeyMarker === undefined || page.NextKeyMarker.length === 0))) {
81
+ return yield* new S3ReadError({ reason: "invalid-response" });
82
+ }
83
+ return {
84
+ versions,
85
+ next: page.IsTruncated === true ?
86
+ {
87
+ key: page.NextKeyMarker ?? "",
88
+ versionId: page.NextVersionIdMarker ?? null
89
+ } :
90
+ null
91
+ };
92
+ }),
93
+ resource: Effect.fn("AlchemyConsole.getS3Resource")(function* (bucket, key, versionId) {
94
+ const result = yield* call(getObject({
95
+ Bucket: bucket.name,
96
+ ExpectedBucketOwner: profile.account,
97
+ Key: key,
98
+ VersionId: versionId
99
+ }), bucket.region);
100
+ if ((result.VersionId ?? "null") !== versionId || result.DeleteMarker === true || result.Body === undefined) {
101
+ return yield* new S3ReadError({ reason: "invalid-response" });
102
+ }
103
+ const text = yield* collectBoundedText(result.Body, 8 * 1024 * 1024).pipe(Effect.mapError((error) => new S3ReadError({ reason: Predicate.isTagged(error, "ByteLimitExceeded") ? "limit" : "provider" })), Effect.timeoutOrElse({
104
+ duration: "30 seconds",
105
+ orElse: () => Effect.fail(new S3ReadError({ reason: "provider" }))
106
+ }));
107
+ return yield* decodeResource(text);
108
+ })
109
+ });
110
+ });
111
+ export const s3ReaderLayer = (profile) => Layer.effect(S3Reader, makeS3Reader(profile));
112
+ //# sourceMappingURL=s3-live.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-live.js","sourceRoot":"","sources":["../src/s3-live.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { Effect } from "effect";
2
+ import { Context, Schema } from "effect";
3
+ import type { ResourceSummary, StateReadError } from "./schema.js";
4
+ /** Server-private bucket name and routing region; memory only, never HTTP, browser storage, logs or telemetry. */
5
+ export interface S3Bucket {
6
+ readonly name: string;
7
+ readonly region: string;
8
+ }
9
+ /** Server-private S3 pagination coordinates with the same boundary as bucket/key/version locators. */
10
+ export interface VersionCursor {
11
+ readonly key: string;
12
+ readonly versionId: string | null;
13
+ }
14
+ /** Server-private persisted S3 key/version coordinates. Only normalized resource metadata may leave the server. */
15
+ export interface S3Version {
16
+ readonly key: string;
17
+ readonly versionId: string;
18
+ readonly latest: boolean;
19
+ readonly deleted: boolean;
20
+ }
21
+ /** Server-private bucket listing and opaque continuation token. */
22
+ export interface S3BucketPage {
23
+ readonly buckets: ReadonlyArray<S3Bucket>;
24
+ readonly next: string | null;
25
+ }
26
+ /** Server-private version listing and continuation coordinates. */
27
+ export interface S3VersionPage {
28
+ readonly versions: ReadonlyArray<S3Version>;
29
+ readonly next: VersionCursor | null;
30
+ }
31
+ declare const S3ReadError_base: Schema.Class<S3ReadError, Schema.TaggedStruct<"S3ReadError", {
32
+ readonly reason: Schema.Literals<readonly ["authentication", "denied", "not-found", "provider", "invalid-response", "limit"]>;
33
+ }>, import("effect/Cause").YieldableError>;
34
+ /** No raw provider error, credentials or locator is retained. */
35
+ export declare class S3ReadError extends S3ReadError_base {
36
+ }
37
+ declare const S3Reader_base: Context.ServiceClass<S3Reader, "@knpkv/alchemy-console/S3Reader", {
38
+ readonly buckets: (cursor: string | null) => Effect.Effect<S3BucketPage, S3ReadError>;
39
+ readonly versions: (bucket: S3Bucket, prefix: string, cursor: VersionCursor | null) => Effect.Effect<S3VersionPage, S3ReadError>;
40
+ readonly resource: (bucket: S3Bucket, key: string, versionId: string) => Effect.Effect<ResourceSummary | null, S3ReadError | StateReadError>;
41
+ }>;
42
+ /** Bound to one explicit SSO profile. No writes, Alchemy runtime, credential chain or implicit login. */
43
+ export declare class S3Reader extends S3Reader_base {
44
+ }
45
+ export {};
46
+ //# sourceMappingURL=s3-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-reader.d.ts","sourceRoot":"","sources":["../src/s3-reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAElE,kHAAkH;AAClH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,sGAAsG;AACtG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED,mHAAmH;AACnH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;IAC3C,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;CACpC;;;;AAED,iEAAiE;AACjE,qBAAa,WAAY,SAAQ,gBAE/B;CAAG;;sBAIe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC;uBAClE,CACjB,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,GAAG,IAAI,KACzB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC;uBAC3B,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CACpF,eAAe,GAAG,IAAI,EACtB,WAAW,GAAG,cAAc,CAC7B;;AAXH,yGAAyG;AACzG,qBAAa,QAAS,SAAQ,aAWS;CAAG"}