@rikalabs/akter-cli 0.1.0-alpha.3 → 0.1.0-alpha.4

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.
package/dist/main.js CHANGED
@@ -8,7 +8,7 @@ import { FetchHttpClient } from "effect/http";
8
8
  import { Effect as Effect22, Runtime as Runtime2, Schema as Schema29 } from "effect";
9
9
  import { CliError, Command as Command19 } from "effect/cli";
10
10
  // package.json
11
- var version = "0.1.0-alpha.3";
11
+ var version = "0.1.0-alpha.4";
12
12
 
13
13
  // src/commands/adopt/run.ts
14
14
  import {
@@ -1112,7 +1112,7 @@ class Authentication extends HttpApiMiddleware.Service()("@akter/cloud-api/Authe
1112
1112
  apiKey: HttpApiSecurity.apiKey({ key: apiKeyHeaderName, in: "header" }),
1113
1113
  bearer: HttpApiSecurity.bearer
1114
1114
  },
1115
- error: [Unauthorized, Forbidden]
1115
+ error: [Unauthorized, Forbidden, Unavailable]
1116
1116
  }) {
1117
1117
  }
1118
1118
  // ../../packages/cloud-api/src/identity.ts
@@ -1304,8 +1304,11 @@ var Environment = Schema13.Struct({
1304
1304
  projectId: ProjectId,
1305
1305
  currentDeploymentId: Schema13.NullOr(DeploymentId),
1306
1306
  database: Schema13.optionalKey(Schema13.Struct({
1307
- source: Schema13.Literals(["managed", "customer"]),
1308
- state: Schema13.Literals(["provisioning", "ready", "read-only", "failed"])
1307
+ source: Schema13.Literal("customer"),
1308
+ state: Schema13.Literals(["missing", "reachable", "unreachable"]),
1309
+ latency: Schema13.NullOr(NonNegative),
1310
+ latencyWarning: Schema13.Boolean,
1311
+ runnerCap: Schema13.NullOr(Schema13.Int)
1309
1312
  }))
1310
1313
  });
1311
1314
  var CreateEnvironment = Schema13.Struct({ name: EnvironmentName });
@@ -1776,7 +1779,7 @@ var capFields = {
1776
1779
  reason: Schema16.optionalKey(Schema16.Literal("unbound"))
1777
1780
  };
1778
1781
  var CapState = Schema16.Struct({
1779
- cap: Schema16.Literals(["spend", "connections", "compute", "storage"]),
1782
+ cap: Schema16.Literals(["spend", "connections", "compute"]),
1780
1783
  ...capFields
1781
1784
  });
1782
1785
  var BillingSummary = Schema16.Struct({
@@ -1811,10 +1814,7 @@ var machineSizeFields = {
1811
1814
  var PlanFeature = Schema16.Literals([
1812
1815
  "compute-overage",
1813
1816
  "compute-cap",
1814
- "storage-overage",
1815
- "storage-cap",
1816
1817
  "byo-database",
1817
- "dedicated-database",
1818
1818
  "checkout"
1819
1819
  ]);
1820
1820
  var CatalogPlan = Schema16.Struct({
@@ -1825,13 +1825,10 @@ var CatalogPlan = Schema16.Struct({
1825
1825
  allowances: Schema16.Struct({
1826
1826
  computeUnitHours: NonNegative,
1827
1827
  computeUnitHourCap: Schema16.NullOr(NonNegative),
1828
- storageGb: NonNegative,
1829
- storageGbCap: Schema16.NullOr(NonNegative),
1830
1828
  concurrentConnections: NonNegativeInt
1831
1829
  }),
1832
1830
  overage: Schema16.Struct({
1833
- computeCentsPerUnitHour: NonNegative,
1834
- storageCentsPerGbMonth: NonNegative
1831
+ computeCentsPerUnitHour: NonNegative
1835
1832
  }),
1836
1833
  features: Schema16.Array(PlanFeature),
1837
1834
  provisional: Schema16.Boolean
@@ -1845,7 +1842,7 @@ var PlanCatalog = Schema16.Struct({
1845
1842
  computeSizes: Schema16.Array(ComputeSize),
1846
1843
  provisional: Schema16.Boolean
1847
1844
  });
1848
- var UsageMeterName = Schema16.Literals(["runnerHours", "storageGb"]);
1845
+ var UsageMeterName = Schema16.Literal("runnerHours");
1849
1846
  var UsageMeter = Schema16.Struct({
1850
1847
  meter: UsageMeterName,
1851
1848
  used: NonNegative,
@@ -1855,7 +1852,6 @@ var UsageMeter = Schema16.Struct({
1855
1852
  });
1856
1853
  var UsagePricing = Schema16.Struct({
1857
1854
  computeCentsPerUnitHour: NonNegative,
1858
- storageCentsPerGbMonth: NonNegative,
1859
1855
  provisional: Schema16.optionalKey(Schema16.Boolean)
1860
1856
  });
1861
1857
  var ComputeUsage = Schema16.Struct({
@@ -1864,18 +1860,15 @@ var ComputeUsage = Schema16.Struct({
1864
1860
  machineHours: NonNegative,
1865
1861
  computeUnitHours: NonNegative
1866
1862
  });
1867
- var StorageSample = Schema16.Struct({ bytes: NonNegative, sampledAt: Timestamp });
1868
1863
  var Usage = Schema16.Struct({
1869
1864
  period: BillingPeriod,
1870
1865
  meters: Schema16.Array(UsageMeter),
1871
- latestStorageSample: Schema16.NullOr(StorageSample),
1872
1866
  caps: Schema16.Array(CapState),
1873
1867
  byProject: Schema16.Array(Schema16.Struct({
1874
1868
  projectId: ProjectId,
1875
1869
  name: Schema16.String,
1876
1870
  computeUnitHours: NonNegative,
1877
1871
  compute: Schema16.Array(ComputeUsage),
1878
- storageGbMonths: NonNegative,
1879
1872
  estimatedCostCents: NonNegative
1880
1873
  })),
1881
1874
  pricing: UsagePricing
@@ -2422,7 +2415,7 @@ class RuntimeGroup extends HttpApiGroup5.make("runtime").add(HttpApiEndpoint5.ge
2422
2415
  class CloudApi extends HttpApi.make("akter-cloud").add(AccountGroup, OrganizationsGroup, MembersGroup, InvitationsGroup, ApiKeysGroup, ProjectsGroup, EnvironmentVariablesGroup, DomainsGroup, RegionsGroup, IntegrationsGroup, DeploymentsGroup, RuntimeGroup, BillingGroup, UsageGroup, AuditGroup).middleware(Authentication).prefix("/api").annotateMerge(OpenApi3.annotations({ title: "Akter Cloud API" })) {
2423
2416
  }
2424
2417
  // src/commands/cloud/deploy.ts
2425
- import { Clock as Clock3, Config as Config3, Console as Console8, Duration as Duration2, Effect as Effect16, Option as Option8, Schema as Schema26, Stream } from "effect";
2418
+ import { Clock as Clock3, Config as Config3, Console as Console9, Duration as Duration3, Effect as Effect16, Option as Option8, Schema as Schema26, Stream } from "effect";
2426
2419
  import { Command as Command13, Flag as Flag12 } from "effect/cli";
2427
2420
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
2428
2421
 
@@ -2590,7 +2583,7 @@ var packContext = (input) => Effect13.gen(function* () {
2590
2583
  });
2591
2584
 
2592
2585
  // src/commands/cloud/client.ts
2593
- import { Effect as Effect15, Match, Schema as Schema25 } from "effect";
2586
+ import { Console as Console8, Duration as Duration2, Effect as Effect15, Match, Schema as Schema25 } from "effect";
2594
2587
  import { HttpClient as HttpClient2, HttpClientRequest as HttpClientRequest2 } from "effect/http";
2595
2588
  import { HttpApiClient } from "effect/http-api";
2596
2589
 
@@ -2697,6 +2690,21 @@ var signedIn = Effect15.gen(function* () {
2697
2690
  const credentials = yield* loadCredentials;
2698
2691
  return { credentials, client: yield* cloudClient(credentials) };
2699
2692
  });
2693
+ var MAX_READ_RETRIES = 5;
2694
+ var readRetryDelay = (attempt) => Duration2.seconds(Math.min(2 ** (attempt - 1), 8));
2695
+ var isTransient = (error) => Match.value(error).pipe(Match.tag("Unavailable", (unavailable) => unavailable.reason === undefined), Match.tag("HttpClientError", ({ reason }) => Match.value(reason).pipe(Match.tag("TransportError", () => true), Match.tag("StatusCodeError", "DecodeError", "EmptyBodyError", ({ response }) => response.status >= 500), Match.orElse(() => false))), Match.orElse(() => false));
2696
+ var retryTransient = (notice) => {
2697
+ let failures = 0;
2698
+ const read = (effect) => effect.pipe(Effect15.tap(() => Effect15.sync(() => {
2699
+ failures = 0;
2700
+ })), Effect15.catchIf((error) => failures < MAX_READ_RETRIES && isTransient(error), () => Effect15.gen(function* () {
2701
+ failures += 1;
2702
+ yield* Console8.error(notice);
2703
+ yield* Effect15.sleep(readRetryDelay(failures));
2704
+ return yield* read(effect);
2705
+ })));
2706
+ return read;
2707
+ };
2700
2708
  var octal2 = (mode) => mode.toString(8).padStart(3, "0");
2701
2709
  var describe = Match.type().pipe(Match.tagsExhaustive({
2702
2710
  NotLoggedIn: () => ({
@@ -2818,11 +2826,12 @@ var follow = Effect16.fnUntraced(function* (input) {
2818
2826
  let cursor = 0;
2819
2827
  let following = false;
2820
2828
  let logComplete = false;
2829
+ const read = retryTransient("The control plane is unavailable; still following the deployment.");
2821
2830
  const printLog = Effect16.gen(function* () {
2822
- const log = yield* input.client.deployments.getBuildLog({ params, query: { after: cursor } });
2831
+ const log = yield* read(input.client.deployments.getBuildLog({ params, query: { after: cursor } }));
2823
2832
  const last = log.lines.at(-1);
2824
2833
  for (const line of log.lines)
2825
- yield* Console8.log(` ${line.text}`);
2834
+ yield* Console9.log(` ${line.text}`);
2826
2835
  if (last !== undefined)
2827
2836
  cursor = last.index + 1;
2828
2837
  following = true;
@@ -2835,7 +2844,7 @@ var follow = Effect16.fnUntraced(function* (input) {
2835
2844
  if (step.name === "build" && step.status === "succeeded" && following && !logComplete)
2836
2845
  yield* printLog;
2837
2846
  printed.set(step.name, step.status);
2838
- yield* Console8.log(` ${step.name} ${step.status}${step.status === "running" ? "" : seconds(step.durationMs)}`);
2847
+ yield* Console9.log(` ${step.name} ${step.status}${step.status === "running" ? "" : seconds(step.durationMs)}`);
2839
2848
  }
2840
2849
  if (!logComplete && detail.steps.some((step) => step.name === "build" && step.status === "running"))
2841
2850
  yield* printLog;
@@ -2844,9 +2853,9 @@ var follow = Effect16.fnUntraced(function* (input) {
2844
2853
  if (detail.status === "failed") {
2845
2854
  const failed = detail.steps.find((step) => step.status === "failed");
2846
2855
  if (failed?.name === "build") {
2847
- const log = yield* input.client.deployments.getBuildLog({ params, query: {} });
2856
+ const log = yield* read(input.client.deployments.getBuildLog({ params, query: {} }));
2848
2857
  for (const line of log.lines.slice(-20))
2849
- yield* Console8.error(` ${line.text}`);
2858
+ yield* Console9.error(` ${line.text}`);
2850
2859
  }
2851
2860
  return yield* DeploymentFailed.make({
2852
2861
  deploymentId: detail.id,
@@ -2859,8 +2868,8 @@ var follow = Effect16.fnUntraced(function* (input) {
2859
2868
  deploymentId: detail.id,
2860
2869
  seconds: input.timeoutSeconds
2861
2870
  });
2862
- yield* Effect16.sleep(Duration2.seconds(1));
2863
- detail = yield* input.client.deployments.get({ params });
2871
+ yield* Effect16.sleep(Duration3.seconds(1));
2872
+ detail = yield* read(input.client.deployments.get({ params }));
2864
2873
  }
2865
2874
  });
2866
2875
  var deployCommand = Command13.make("deploy", flags9, (options) => Effect16.gen(function* () {
@@ -2875,7 +2884,7 @@ var deployCommand = Command13.make("deploy", flags9, (options) => Effect16.gen(f
2875
2884
  reason: "ContextTooLarge",
2876
2885
  message: `The app directory is ${packed.archive.byteLength} bytes compressed; the control plane accepts at most ${MAX_SOURCE_BYTES}. Exclude more files in .akterignore.`
2877
2886
  });
2878
- yield* Console8.log(`Uploading ${packed.files.length} files (${packed.archive.byteLength} bytes) from ${options.context} to ${credentials.apiUrl}`);
2887
+ yield* Console9.log(`Uploading ${packed.files.length} files (${packed.archive.byteLength} bytes) from ${options.context} to ${credentials.apiUrl}`);
2879
2888
  const source = yield* client.deployments.uploadSource({
2880
2889
  params: { projectId: options.project },
2881
2890
  payload: packed.archive
@@ -2895,14 +2904,28 @@ var deployCommand = Command13.make("deploy", flags9, (options) => Effect16.gen(f
2895
2904
  source: { digest: source.digest }
2896
2905
  }
2897
2906
  });
2898
- yield* Console8.log(`Deployment ${deployment.id} of ${commitSha.slice(0, 7)} to ${options.environment} started`);
2907
+ yield* Console9.log(`Deployment ${deployment.id} of ${commitSha.slice(0, 7)} to ${options.environment} started`);
2899
2908
  const live = yield* follow({
2900
2909
  client,
2901
2910
  projectId: options.project,
2902
2911
  deployment,
2903
2912
  timeoutSeconds: options.timeout
2904
2913
  });
2905
- yield* Console8.log(`Deployment ${live.id} is live in ${options.environment}`);
2914
+ yield* Console9.log(`Deployment ${live.id} is live in ${options.environment}`);
2915
+ const report = yield* retryTransient("The control plane is unavailable; retrying the database report.")(client.projects.getEnvironment({
2916
+ params: { projectId: options.project, environment: options.environment }
2917
+ })).pipe(Effect16.catch(() => Console9.error("Warning: could not read the database report; the deployment is already live.").pipe(Effect16.as(undefined))));
2918
+ if (report === undefined)
2919
+ return;
2920
+ if (report.currentDeploymentId !== live.id)
2921
+ return yield* Console9.error("Warning: the database report is not for this deployment; skipping its diagnostics.");
2922
+ const { database } = report;
2923
+ if (database !== undefined) {
2924
+ if (database.latencyWarning)
2925
+ yield* Console9.error(`Warning: database p50 latency${database.latency === null ? "" : ` (${database.latency} ms)`} exceeds 5 ms from the runner region; deployment is not refused.`);
2926
+ if (database.runnerCap !== null)
2927
+ yield* Console9.log(`Database runner cap: ${database.runnerCap}`);
2928
+ }
2906
2929
  }).pipe(Effect16.catchTags({
2907
2930
  ContextInvalid: (error) => fail({ reason: "ContextInvalid", message: error.message }),
2908
2931
  DeploymentFailed: (error) => fail({
@@ -2918,7 +2941,7 @@ var deployCommand = Command13.make("deploy", flags9, (options) => Effect16.gen(f
2918
2941
  }), reportFailures)).pipe(Command13.withDescription("Upload the app directory, build and roll it out on Akter Cloud, and follow it until it is live"));
2919
2942
 
2920
2943
  // src/commands/cloud/login.ts
2921
- import { Clock as Clock4, Config as Config4, Console as Console9, Data, Duration as Duration3, Effect as Effect17, Schema as Schema27 } from "effect";
2944
+ import { Clock as Clock4, Config as Config4, Console as Console10, Data, Duration as Duration4, Effect as Effect17, Schema as Schema27 } from "effect";
2922
2945
  import { Command as Command14, Flag as Flag13 } from "effect/cli";
2923
2946
  import { HttpClient as HttpClient3, HttpClientRequest as HttpClientRequest3, HttpClientResponse } from "effect/http";
2924
2947
  var CLIENT_ID = "akter-cli";
@@ -2958,7 +2981,7 @@ var deviceLogin = (apiUrl) => Effect17.gen(function* () {
2958
2981
  return yield* LoginRefused.make({ status: started.status, error });
2959
2982
  }
2960
2983
  const code = yield* HttpClientResponse.schemaBodyJson(DeviceCode)(started);
2961
- yield* Console9.log(`To sign in, open ${code.verification_uri}
2984
+ yield* Console10.log(`To sign in, open ${code.verification_uri}
2962
2985
  and enter the code ${displayCode(code.user_code)}. Waiting for approval…`);
2963
2986
  const poll = Effect17.gen(function* () {
2964
2987
  const response = yield* post(`${apiUrl}/auth/device/token`, {
@@ -2982,14 +3005,14 @@ and enter the code ${displayCode(code.user_code)}. Waiting for approval…`);
2982
3005
  return yield* LoginRefused.make({ status: response.status, error });
2983
3006
  });
2984
3007
  const deadline = (yield* Clock4.currentTimeMillis) + code.expires_in * 1000;
2985
- let interval = Duration3.seconds(code.interval);
3008
+ let interval = Duration4.seconds(code.interval);
2986
3009
  while ((yield* Clock4.currentTimeMillis) < deadline) {
2987
3010
  yield* Effect17.sleep(interval);
2988
3011
  const answer = yield* poll;
2989
3012
  if (Poll.$is("Granted")(answer))
2990
3013
  return answer.token;
2991
3014
  if (Poll.$is("SlowDown")(answer))
2992
- interval = Duration3.sum(interval, Duration3.seconds(5));
3015
+ interval = Duration4.sum(interval, Duration4.seconds(5));
2993
3016
  }
2994
3017
  return yield* LoginExpired.make({});
2995
3018
  });
@@ -3000,7 +3023,7 @@ var loginCommand = Command14.make("login", flags10, ({ apiUrl }) => Effect17.gen
3000
3023
  const me = yield* client.account.me().pipe(Effect17.tapError(() => revoke(apiUrl, token)));
3001
3024
  const email = me.user?.email ?? "";
3002
3025
  const file = yield* saveCredentials({ apiUrl, token, email });
3003
- yield* Console9.log(`Logged in to ${apiUrl} as ${email}. Credentials saved to ${file}.`);
3026
+ yield* Console10.log(`Logged in to ${apiUrl} as ${email}. Credentials saved to ${file}.`);
3004
3027
  }).pipe(Effect17.catchTags({
3005
3028
  LoginDenied: () => fail({
3006
3029
  reason: "LoginDenied",
@@ -3020,7 +3043,7 @@ var loginCommand = Command14.make("login", flags10, ({ apiUrl }) => Effect17.gen
3020
3043
  }), reportFailures)).pipe(Command14.withDescription("Sign in to Akter Cloud through the browser and store the session for deploy"));
3021
3044
 
3022
3045
  // src/commands/cloud/logout.ts
3023
- import { Console as Console10, Effect as Effect18, Option as Option9 } from "effect";
3046
+ import { Console as Console11, Effect as Effect18, Option as Option9 } from "effect";
3024
3047
  import { Command as Command15 } from "effect/cli";
3025
3048
  import { HttpClient as HttpClient4, HttpClientRequest as HttpClientRequest4 } from "effect/http";
3026
3049
  var logout = Effect18.gen(function* () {
@@ -3032,17 +3055,17 @@ var logout = Effect18.gen(function* () {
3032
3055
  var logoutCommand = Command15.make("logout", {}, () => Effect18.gen(function* () {
3033
3056
  const { credentials, revoked } = yield* logout;
3034
3057
  if (credentials === undefined)
3035
- return yield* Console10.log("Removed the stored credentials.");
3036
- yield* Console10.log(revoked ? `Logged out of ${credentials.apiUrl}.` : `Removed the stored credentials. ${credentials.apiUrl} could not revoke the session, which ends when it expires.`);
3037
- }).pipe(Effect18.catchTag("NotLoggedIn", () => Console10.log("Not logged in.")), reportFailures)).pipe(Command15.withDescription("Sign out of Akter Cloud and delete the stored session"));
3058
+ return yield* Console11.log("Removed the stored credentials.");
3059
+ yield* Console11.log(revoked ? `Logged out of ${credentials.apiUrl}.` : `Removed the stored credentials. ${credentials.apiUrl} could not revoke the session, which ends when it expires.`);
3060
+ }).pipe(Effect18.catchTag("NotLoggedIn", () => Console11.log("Not logged in.")), reportFailures)).pipe(Command15.withDescription("Sign out of Akter Cloud and delete the stored session"));
3038
3061
 
3039
3062
  // src/commands/cloud/whoami.ts
3040
- import { Console as Console11, Effect as Effect19 } from "effect";
3063
+ import { Console as Console12, Effect as Effect19 } from "effect";
3041
3064
  import { Command as Command16 } from "effect/cli";
3042
3065
  var whoamiCommand = Command16.make("whoami", {}, () => Effect19.gen(function* () {
3043
3066
  const { credentials, client } = yield* signedIn;
3044
3067
  const me = yield* client.account.me();
3045
- yield* Console11.log([
3068
+ yield* Console12.log([
3046
3069
  `${me.user?.email ?? credentials.email} at ${credentials.apiUrl}`,
3047
3070
  ...me.organizations.map((membership) => ` ${membership.organization.slug} ${membership.role} ${membership.organization.id}`)
3048
3071
  ].join(`
@@ -3050,7 +3073,7 @@ var whoamiCommand = Command16.make("whoami", {}, () => Effect19.gen(function* ()
3050
3073
  }).pipe(reportFailures)).pipe(Command16.withDescription("Show who the stored Akter Cloud session signs in as"));
3051
3074
 
3052
3075
  // src/commands/cloud/env.ts
3053
- import { Config as Config5, Console as Console12, DateTime as DateTime2, Effect as Effect20, FileSystem as FileSystem5, Option as Option10, Stdio, Stream as Stream2 } from "effect";
3076
+ import { Config as Config5, Console as Console13, DateTime as DateTime2, Effect as Effect20, FileSystem as FileSystem5, Option as Option10, Stdio, Stream as Stream2 } from "effect";
3054
3077
  import { Argument as Argument6, Command as Command17, Flag as Flag14 } from "effect/cli";
3055
3078
  var scope = {
3056
3079
  project: Flag14.String("project").pipe(Flag14.withFallbackConfig(Config5.String("AKTER_PROJECT")), Flag14.withSchema(ProjectId)),
@@ -3101,7 +3124,7 @@ var list2 = Command17.make("list", scope, ({ project, environment }) => Effect20
3101
3124
  params: { projectId: project, environment }
3102
3125
  });
3103
3126
  for (const variable of variables)
3104
- yield* Console12.log(`${variable.name} ${DateTime2.formatIso(variable.updatedAt)}${variable.usedBy.includes("platform") ? "\tmanaged" : ""}`);
3127
+ yield* Console13.log(`${variable.name} ${DateTime2.formatIso(variable.updatedAt)}`);
3105
3128
  }).pipe(reportFailures)).pipe(Command17.withDescription("List variable names and update times; values cannot be read back"));
3106
3129
  var set = Command17.make("set", { ...scope, name, file: Flag14.File("file", { mustExist: true }).pipe(Flag14.optional) }, (options) => Effect20.gen(function* () {
3107
3130
  const { client } = yield* signedIn;
@@ -3114,13 +3137,13 @@ var set = Command17.make("set", { ...scope, name, file: Flag14.File("file", { mu
3114
3137
  },
3115
3138
  payload: { value }
3116
3139
  });
3117
- yield* Console12.log(`Set ${options.name} in ${options.environment}. The value takes effect on the next deployment.`);
3140
+ yield* Console13.log(`Set ${options.name} in ${options.environment}. The value takes effect on the next deployment.`);
3118
3141
  }).pipe(reportFailures)).pipe(Command17.withDescription("Set a write-only value from piped stdin or --file"));
3119
3142
  var unset = Command17.make("unset", { ...scope, name }, ({ project, environment, name }) => Effect20.gen(function* () {
3120
3143
  const { client } = yield* signedIn;
3121
3144
  yield* client.environmentVariables.delete({ params: { projectId: project, environment, name } });
3122
- yield* Console12.log(`Unset ${name} in ${environment}. The change takes effect on the next deployment.`);
3123
- }).pipe(reportFailures)).pipe(Command17.withDescription("Remove a customer-managed variable"));
3145
+ yield* Console13.log(`Unset ${name} in ${environment}. The change takes effect on the next deployment.`);
3146
+ }).pipe(reportFailures)).pipe(Command17.withDescription("Remove an environment variable"));
3124
3147
  var importVariables = Command17.make("import", { ...scope, file: Argument6.String("file").pipe(Argument6.withDefault("-")) }, ({ project, environment, file }) => Effect20.gen(function* () {
3125
3148
  const { client } = yield* signedIn;
3126
3149
  const content = yield* input(file, 1048576);
@@ -3128,12 +3151,12 @@ var importVariables = Command17.make("import", { ...scope, file: Argument6.Strin
3128
3151
  params: { projectId: project, environment },
3129
3152
  payload: { content }
3130
3153
  });
3131
- yield* Console12.log(`Imported ${result.created.length} new and ${result.updated.length} updated variables in ${environment}.`);
3154
+ yield* Console13.log(`Imported ${result.created.length} new and ${result.updated.length} updated variables in ${environment}.`);
3132
3155
  }).pipe(reportFailures)).pipe(Command17.withDescription("Import a dotenv file atomically; use - or no file for stdin"));
3133
3156
  var envCommand = Command17.make("env").pipe(Command17.withDescription("Manage encrypted, write-only Akter Cloud environment variables"), Command17.withSubcommands([list2, set, unset, importVariables]));
3134
3157
 
3135
3158
  // src/commands/cloud/logs.ts
3136
- import { Config as Config6, Console as Console13, DateTime as DateTime3, Effect as Effect21, Option as Option11, Schema as Schema28 } from "effect";
3159
+ import { Config as Config6, Console as Console14, DateTime as DateTime3, Effect as Effect21, Option as Option11, Schema as Schema28 } from "effect";
3137
3160
  import { Command as Command18, Flag as Flag15 } from "effect/cli";
3138
3161
  var colourSequence = new RegExp(`${String.fromCodePoint(27)}\\[[0-?]*[ -/]*[@-~]`, "gu");
3139
3162
  var logsCommand = Command18.make("logs", {
@@ -3150,11 +3173,11 @@ var logsCommand = Command18.make("logs", {
3150
3173
  let more = false;
3151
3174
  let failures = 0;
3152
3175
  const retryRead = (error) => Effect21.gen(function* () {
3153
- if (!options.follow || failures >= 5)
3176
+ if (!options.follow || failures >= MAX_READ_RETRIES)
3154
3177
  return yield* error;
3155
3178
  failures += 1;
3156
- yield* Console13.error("Log read unavailable; reconnecting from the last cursor.");
3157
- yield* Effect21.sleep(`${Math.min(2 ** (failures - 1), 8)} seconds`);
3179
+ yield* Console14.error("Log read unavailable; reconnecting from the last cursor.");
3180
+ yield* Effect21.sleep(readRetryDelay(failures));
3158
3181
  return;
3159
3182
  });
3160
3183
  while (true) {
@@ -3176,7 +3199,7 @@ var logsCommand = Command18.make("logs", {
3176
3199
  continue;
3177
3200
  failures = 0;
3178
3201
  for (const line of page.lines)
3179
- yield* Console13.log(`${DateTime3.formatIso(line.at)} ${line.runnerId} ${line.stream} ${line.text.replace(colourSequence, "").replace(/\p{Cc}|[\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/gu, "�")}${line.clipped ? " …" : ""}`);
3202
+ yield* Console14.log(`${DateTime3.formatIso(line.at)} ${line.runnerId} ${line.stream} ${line.text.replace(colourSequence, "").replace(/\p{Cc}|[\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/gu, "�")}${line.clipped ? " …" : ""}`);
3180
3203
  cursor = page.cursor;
3181
3204
  more = page.more;
3182
3205
  if (!options.follow && !more)
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@rikalabs/akter-cli","version":"0.1.0-alpha.3","files":["dist","CHANGELOG.md","README.md","LICENSE","NOTICE"],"dependencies":{"@effect/platform-bun":"4.0.2","@effect/platform-node":"4.0.2","@rikalabs/akter":"0.1.0-alpha.3"},"peerDependencies":{"@effect/sql-pg":"^4.0.2","@effect/sql-pglite":"^4.0.2","drizzle-orm":"^1.0.0-rc.5-5935859","effect":"^4.0.2"},"bin":{"akter":"dist/main.js"},"publishConfig":{"access":"public"},"description":"The Akter command-line tool for local development and Akter Cloud","keywords":["actors","akter","durable","effect","pglite","postgres"],"homepage":"https://github.com/Rika-Labs/akter#readme","bugs":"https://github.com/Rika-Labs/akter/issues","license":"Apache-2.0","author":"Rika Labs","repository":{"type":"git","url":"git+https://github.com/Rika-Labs/akter.git","directory":"apps/cli"},"type":"module","types":"./dist/main.d.ts","exports":{".":{"types":"./dist/main.d.ts","default":"./dist/main.js"},"./cloud-api":{"types":"./dist/cloud-api/index.d.ts","default":"./dist/cloud-api/index.js"}},"engines":{"bun":">=1.4.2","node":">=24.0.0"}}
1
+ {"name":"@rikalabs/akter-cli","version":"0.1.0-alpha.4","files":["dist","CHANGELOG.md","README.md","LICENSE","NOTICE"],"dependencies":{"@effect/platform-bun":"4.0.2","@effect/platform-node":"4.0.2","@rikalabs/akter":"0.1.0-alpha.4"},"peerDependencies":{"@effect/sql-pg":"^4.0.2","@effect/sql-pglite":"^4.0.2","drizzle-orm":"^1.0.0-rc.5-5935859","effect":"^4.0.2"},"bin":{"akter":"dist/main.js"},"publishConfig":{"access":"public"},"description":"The Akter command-line tool for local development and Akter Cloud","keywords":["actors","akter","durable","effect","pglite","postgres"],"homepage":"https://github.com/Rika-Labs/akter#readme","bugs":"https://github.com/Rika-Labs/akter/issues","license":"Apache-2.0","author":"Rika Labs","repository":{"type":"git","url":"git+https://github.com/Rika-Labs/akter.git","directory":"apps/cli"},"type":"module","types":"./dist/main.d.ts","exports":{".":{"types":"./dist/main.d.ts","default":"./dist/main.js"},"./cloud-api":{"types":"./dist/cloud-api/index.d.ts","default":"./dist/cloud-api/index.js"}},"engines":{"bun":">=1.4.2","node":">=24.0.0"}}