@capxul/cli 4.20.0-beta.7 → 4.20.0-beta.8
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/README.md +103 -14
- package/dist/browser/signer.js.map +1 -1
- package/dist/main.mjs +653 -166
- package/dist/main.mjs.map +1 -1
- package/package.json +3 -3
package/dist/main.mjs
CHANGED
|
@@ -4174,11 +4174,11 @@ function encodePacked(types, values) {
|
|
|
4174
4174
|
for (let i = 0; i < types.length; i++) {
|
|
4175
4175
|
const type = types[i];
|
|
4176
4176
|
const value = values[i];
|
|
4177
|
-
data.push(encode$
|
|
4177
|
+
data.push(encode$3(type, value));
|
|
4178
4178
|
}
|
|
4179
4179
|
return concatHex(data);
|
|
4180
4180
|
}
|
|
4181
|
-
function encode$
|
|
4181
|
+
function encode$3(type, value, isArray = false) {
|
|
4182
4182
|
if (type === "address") {
|
|
4183
4183
|
const address = value;
|
|
4184
4184
|
if (!isAddress(address)) throw new InvalidAddressError({ address });
|
|
@@ -4212,7 +4212,7 @@ function encode$2(type, value, isArray = false) {
|
|
|
4212
4212
|
if (arrayMatch && Array.isArray(value)) {
|
|
4213
4213
|
const [_type, childType] = arrayMatch;
|
|
4214
4214
|
const data = [];
|
|
4215
|
-
for (let i = 0; i < value.length; i++) data.push(encode$
|
|
4215
|
+
for (let i = 0; i < value.length; i++) data.push(encode$3(childType, value[i], true));
|
|
4216
4216
|
if (data.length === 0) return "0x";
|
|
4217
4217
|
return concatHex(data);
|
|
4218
4218
|
}
|
|
@@ -11001,6 +11001,18 @@ function withInvocationParentSpan(effect, controls) {
|
|
|
11001
11001
|
const parent = controls?.[INVOCATION_PARENT_SPAN];
|
|
11002
11002
|
return parent === void 0 ? effect : effect.pipe(Effect.withParentSpan(parent));
|
|
11003
11003
|
}
|
|
11004
|
+
/**
|
|
11005
|
+
* The input field a refused request named.
|
|
11006
|
+
*
|
|
11007
|
+
* The surfaces that call the port directly already carry `details.field` for an
|
|
11008
|
+
* `INVALID_INPUT` refusal. The actor keeps that one allowlisted detail instead of
|
|
11009
|
+
* dropping it, so a caller sees the same refusal either way.
|
|
11010
|
+
*/
|
|
11011
|
+
const refusedInputField = (failure) => {
|
|
11012
|
+
if (failure.code !== "INVALID_INPUT") return void 0;
|
|
11013
|
+
const field = failure.error?.details?.field;
|
|
11014
|
+
return typeof field === "string" && field.length > 0 ? { field } : void 0;
|
|
11015
|
+
};
|
|
11004
11016
|
var ActorFailure = class extends Error {
|
|
11005
11017
|
reason;
|
|
11006
11018
|
machine;
|
|
@@ -11166,7 +11178,7 @@ const boot = (spec, options = {}) => Effect.gen(function* () {
|
|
|
11166
11178
|
const event = { _tag: env.origin.event };
|
|
11167
11179
|
const failedState = exit.failure === timeoutFailure || exit.failure === cancelledFailure ? yield* recoverFailure(state, env.origin, exit.failure) : state;
|
|
11168
11180
|
yield* emit(nonApplied(failedState, event, exit.failure.code, outcome, env, exit.failure));
|
|
11169
|
-
const details = exit.failure === timeoutFailure ? { reason: "timeout" } :
|
|
11181
|
+
const details = exit.failure === timeoutFailure ? { reason: "timeout" } : refusedInputField(exit.failure);
|
|
11170
11182
|
yield* failReply(held.reply, makeFailure(failedState, event, exit.failure.code, details, exit.failure.error ?? exit.failure));
|
|
11171
11183
|
return;
|
|
11172
11184
|
}
|
|
@@ -13225,7 +13237,7 @@ function subscribeActivity(deps, actor, controls, onChange) {
|
|
|
13225
13237
|
}
|
|
13226
13238
|
//#endregion
|
|
13227
13239
|
//#region ../../packages/sdk/package.json
|
|
13228
|
-
var version$1 = "4.20.0-beta.
|
|
13240
|
+
var version$1 = "4.20.0-beta.8";
|
|
13229
13241
|
//#endregion
|
|
13230
13242
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
13231
13243
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -25087,7 +25099,7 @@ function toFormData$1(obj, formData, options) {
|
|
|
25087
25099
|
*
|
|
25088
25100
|
* @returns {string} The encoded string.
|
|
25089
25101
|
*/
|
|
25090
|
-
function encode$
|
|
25102
|
+
function encode$2(str) {
|
|
25091
25103
|
const charMap = {
|
|
25092
25104
|
"!": "%21",
|
|
25093
25105
|
"'": "%27",
|
|
@@ -25118,8 +25130,8 @@ prototype.append = function append(name, value) {
|
|
|
25118
25130
|
};
|
|
25119
25131
|
prototype.toString = function toString(encoder) {
|
|
25120
25132
|
const _encode = encoder ? function(value) {
|
|
25121
|
-
return encoder.call(this, value, encode$
|
|
25122
|
-
} : encode$
|
|
25133
|
+
return encoder.call(this, value, encode$2);
|
|
25134
|
+
} : encode$2;
|
|
25123
25135
|
return this._pairs.map(function each(pair) {
|
|
25124
25136
|
return _encode(pair[0]) + "=" + _encode(pair[1]);
|
|
25125
25137
|
}, "").join("&");
|
|
@@ -25134,7 +25146,7 @@ prototype.toString = function toString(encoder) {
|
|
|
25134
25146
|
*
|
|
25135
25147
|
* @returns {string} The encoded value.
|
|
25136
25148
|
*/
|
|
25137
|
-
function encode(val) {
|
|
25149
|
+
function encode$1(val) {
|
|
25138
25150
|
return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+");
|
|
25139
25151
|
}
|
|
25140
25152
|
/**
|
|
@@ -25148,7 +25160,7 @@ function encode(val) {
|
|
|
25148
25160
|
*/
|
|
25149
25161
|
function buildURL(url, params, options) {
|
|
25150
25162
|
if (!params) return url;
|
|
25151
|
-
const _encode = options && options.encode || encode;
|
|
25163
|
+
const _encode = options && options.encode || encode$1;
|
|
25152
25164
|
const _options = utils_default.isFunction(options) ? { serialize: options } : options;
|
|
25153
25165
|
const serializeFn = _options && _options.serialize;
|
|
25154
25166
|
let serializedParams;
|
|
@@ -41029,6 +41041,7 @@ function mapBetterAuthError(operation, body) {
|
|
|
41029
41041
|
const code = typeof errBody.code === "string" ? errBody.code : "";
|
|
41030
41042
|
if (code === "OTP_EXPIRED") return Errors.otpExpired();
|
|
41031
41043
|
if (code === "INVALID_OTP") return Errors.invalidInput("otp", errBody.message ?? "invalid OTP");
|
|
41044
|
+
if (code === "TOO_MANY_ATTEMPTS") return Errors.rateLimited({ resource: "better-auth/verifyOtp" });
|
|
41032
41045
|
if (code === "VALIDATION_ERROR" || code === "INVALID_EMAIL") return Errors.invalidInput("email", errBody.message ?? "invalid email");
|
|
41033
41046
|
}
|
|
41034
41047
|
return Errors.providerError("better-auth", operation, new Error(String(body)));
|
|
@@ -41646,6 +41659,10 @@ var BetterAuthNodeAdapter = class {
|
|
|
41646
41659
|
ok: false,
|
|
41647
41660
|
error: Errors.invalidInput("otp", errBody.message ?? "invalid OTP")
|
|
41648
41661
|
};
|
|
41662
|
+
if (errBody.code === "TOO_MANY_ATTEMPTS") return {
|
|
41663
|
+
ok: false,
|
|
41664
|
+
error: Errors.rateLimited({ resource: "better-auth/verifyOtp" })
|
|
41665
|
+
};
|
|
41649
41666
|
}
|
|
41650
41667
|
}
|
|
41651
41668
|
return {
|
|
@@ -45158,6 +45175,12 @@ const stderrConvexLogger = {
|
|
|
45158
45175
|
error: writeConvexDiagnostic,
|
|
45159
45176
|
logVerbose: () => void 0
|
|
45160
45177
|
};
|
|
45178
|
+
const silentConvexLogger = {
|
|
45179
|
+
log: () => void 0,
|
|
45180
|
+
warn: () => void 0,
|
|
45181
|
+
error: () => void 0,
|
|
45182
|
+
logVerbose: () => void 0
|
|
45183
|
+
};
|
|
45161
45184
|
/** Exact floor-first allowlist; every additional handler must migrate its validator first. */
|
|
45162
45185
|
const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
45163
45186
|
"system:healthObserved",
|
|
@@ -45246,7 +45269,7 @@ var ConvexCallAdapter = class {
|
|
|
45246
45269
|
const webSocketConstructor = this.#connectionMonitor.observedWebSocketConstructor();
|
|
45247
45270
|
this.#client = deps.client ?? new ConvexClient(deps.convexUrl, {
|
|
45248
45271
|
...webSocketConstructor === void 0 ? {} : { webSocketConstructor },
|
|
45249
|
-
|
|
45272
|
+
logger: deps.localDiagnostics === true ? stderrConvexLogger : silentConvexLogger
|
|
45250
45273
|
});
|
|
45251
45274
|
this.#tokenProvider = deps.tokenProvider;
|
|
45252
45275
|
this.#applicationId = deps.applicationId;
|
|
@@ -51040,7 +51063,7 @@ function productionAuthCacheLayer(input) {
|
|
|
51040
51063
|
function productionConvexCallLayer(input, refreshConvexAuthRef) {
|
|
51041
51064
|
return Layer.unwrap(Effect.map(AuthClientPortTag, (authClient) => ConvexCallLayer({
|
|
51042
51065
|
convexUrl: input.runtimeUrls.convexUrl,
|
|
51043
|
-
|
|
51066
|
+
localDiagnostics: input.localDiagnostics,
|
|
51044
51067
|
...input.applicationId === void 0 ? {} : { applicationId: input.applicationId },
|
|
51045
51068
|
...input.observation === void 0 ? {} : { observation: input.observation },
|
|
51046
51069
|
...input.convexClient === void 0 ? {} : { client: input.convexClient },
|
|
@@ -51079,6 +51102,7 @@ function resolveProductionObservability(input) {
|
|
|
51079
51102
|
};
|
|
51080
51103
|
}
|
|
51081
51104
|
async function createProductionAdapters(input) {
|
|
51105
|
+
const localDiagnostics = productionLocalDiagnostics(input);
|
|
51082
51106
|
const { observation, telemetry, invocationObservation, invocationTelemetry } = resolveProductionObservability(input);
|
|
51083
51107
|
const resolvedInput = resolveInput(input);
|
|
51084
51108
|
if (!resolvedInput.ok) return resolvedInput;
|
|
@@ -51149,6 +51173,7 @@ async function createProductionAdapters(input) {
|
|
|
51149
51173
|
const portsLayer = mergeProductionAdapterLayers(makeProductionAdapterLayerEntries({
|
|
51150
51174
|
bootstrap,
|
|
51151
51175
|
runtime: resolvedInput.value.runtime,
|
|
51176
|
+
localDiagnostics,
|
|
51152
51177
|
...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin },
|
|
51153
51178
|
runtimeUrls: runtimeUrls.value,
|
|
51154
51179
|
chainId: bootstrapResult.value.chainId,
|
|
@@ -51163,7 +51188,7 @@ async function createProductionAdapters(input) {
|
|
|
51163
51188
|
...input.signal === void 0 ? {} : { signal: input.signal },
|
|
51164
51189
|
...input.resetSignerSession === void 0 ? {} : { resetSignerSession: input.resetSignerSession }
|
|
51165
51190
|
}));
|
|
51166
|
-
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime, hostEngineeringPolicy(input.observability))).pipe(Layer.provideMerge(resolvedInput.value.runtime
|
|
51191
|
+
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime, hostEngineeringPolicy(input.observability))).pipe(Layer.provideMerge(localDiagnosticsLayer(localDiagnostics, resolvedInput.value.runtime)));
|
|
51167
51192
|
const context = await Effect.runPromise(Layer.buildWithScope(applicationLayer, scope));
|
|
51168
51193
|
const collected = await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(context)));
|
|
51169
51194
|
const indexerUrl = input.indexerUrl ?? bootstrapResult.value.indexerUrl;
|
|
@@ -51227,6 +51252,13 @@ function optionalEngineeringTelemetryLayer(policy, runtime, hostPolicy) {
|
|
|
51227
51252
|
return Layer.empty;
|
|
51228
51253
|
}
|
|
51229
51254
|
}
|
|
51255
|
+
function localDiagnosticsLayer(enabled, runtime) {
|
|
51256
|
+
if (!enabled) return Logger.layer([]);
|
|
51257
|
+
return runtime === "node" ? Layer.succeed(Logger.LogToStderr, true) : Layer.empty;
|
|
51258
|
+
}
|
|
51259
|
+
function productionLocalDiagnostics(input) {
|
|
51260
|
+
return input.localDiagnostics !== false;
|
|
51261
|
+
}
|
|
51230
51262
|
function refreshConvexAuthOnSession(authClient, refresh) {
|
|
51231
51263
|
return {
|
|
51232
51264
|
...authClient,
|
|
@@ -51291,7 +51323,7 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
51291
51323
|
runtime,
|
|
51292
51324
|
authBaseUrl: resolvedAuthBaseUrl,
|
|
51293
51325
|
createBrowserSigner: createOpenfortBrowserSignerFromBootstrap,
|
|
51294
|
-
diagnostic: new EffectLogDiagnosticAdapter(adapters.value.context, new ConsoleDiagnosticAdapter()),
|
|
51326
|
+
diagnostic: new EffectLogDiagnosticAdapter(adapters.value.context, productionLocalDiagnostics(input) ? new ConsoleDiagnosticAdapter() : void 0),
|
|
51295
51327
|
signer: input.signer,
|
|
51296
51328
|
factory: input.openfortSignerFactory,
|
|
51297
51329
|
finalSign: controls.signUserOpHash,
|
|
@@ -51663,8 +51695,8 @@ function captureException(telemetry, error, context) {
|
|
|
51663
51695
|
}
|
|
51664
51696
|
//#endregion
|
|
51665
51697
|
//#region src/version.ts
|
|
51666
|
-
const cliVersion = "4.20.0-beta.
|
|
51667
|
-
const sdkVersion = "4.20.0-beta.
|
|
51698
|
+
const cliVersion = "4.20.0-beta.8";
|
|
51699
|
+
const sdkVersion = "4.20.0-beta.8";
|
|
51668
51700
|
const ReleaseVersion = Schema.String.check(Schema.isMaxLength(256), Schema.isPattern(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/u)).pipe(Schema.brand("CliReleaseVersion"));
|
|
51669
51701
|
const parts = (version) => {
|
|
51670
51702
|
const [core = "", ...prerelease] = version.split("+")[0].split("-");
|
|
@@ -52193,7 +52225,7 @@ const finishUpdateCheck = Effect.fn(function* (directory, attempt, target) {
|
|
|
52193
52225
|
});
|
|
52194
52226
|
//#endregion
|
|
52195
52227
|
//#region src/platform/collection-policy.ts
|
|
52196
|
-
const decode$
|
|
52228
|
+
const decode$3 = Schema.decodeUnknownOption(Schema.fromJsonString(Settings), { onExcessProperty: "error" });
|
|
52197
52229
|
const missing = (error) => error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
52198
52230
|
const resolveProtectedDirectory = (directory, uid) => {
|
|
52199
52231
|
const stateDirectory = lstatSync(directory, { throwIfNoEntry: false });
|
|
@@ -52237,7 +52269,7 @@ const collectionPolicy = (settingsPath, forcedDisabled) => () => {
|
|
|
52237
52269
|
length += count;
|
|
52238
52270
|
}
|
|
52239
52271
|
if (length > 65536) return false;
|
|
52240
|
-
const settings = decode$
|
|
52272
|
+
const settings = decode$3(bytes.toString("utf8", 0, length));
|
|
52241
52273
|
return Option.isSome(settings) && settings.value.collection.enabled;
|
|
52242
52274
|
} catch {
|
|
52243
52275
|
return false;
|
|
@@ -52258,9 +52290,31 @@ var CliFailure = class extends Data.TaggedError("CliFailure") {};
|
|
|
52258
52290
|
*/
|
|
52259
52291
|
const WRONG_STATE_MESSAGE = "The command cannot run from the current state.";
|
|
52260
52292
|
const ORGANIZATION_WRONG_STATE_MESSAGE = "The Organization cannot run this command from its current state. Resume that exact Organization with capxul org retry --org instead of creating a replacement.";
|
|
52293
|
+
const PERSONAL_ACCOUNT_WRONG_STATE_MESSAGE = "The personal Account cannot run this command from its current state. Resume the same Account and Profile with capxul auth signup instead of creating a replacement.";
|
|
52261
52294
|
const INPUT_MESSAGE = "The input was refused. Check the email and verification code, or request a new code.";
|
|
52295
|
+
const PROFILE_INPUT_MESSAGE = "The Profile input was refused. Correct the display name, country, or handle, then run capxul auth signup again.";
|
|
52296
|
+
const HANDLE_INPUT_MESSAGE = "That handle is not available. Choose another handle, then run capxul auth signup again.";
|
|
52262
52297
|
const organizationCommand = (command) => command === "org" || command?.startsWith("org.") === true;
|
|
52263
52298
|
/**
|
|
52299
|
+
* The authentication journey family. A Profile or personal Account refusal is
|
|
52300
|
+
* not an email or verification-code problem, so it never reuses OTP copy.
|
|
52301
|
+
*/
|
|
52302
|
+
const authCommand = (command) => command === "auth" || command?.startsWith("auth.") === true;
|
|
52303
|
+
/** The Profile fields a personal signup states. */
|
|
52304
|
+
const PROFILE_FIELDS = /* @__PURE__ */ new Set([
|
|
52305
|
+
"profile",
|
|
52306
|
+
"displayName",
|
|
52307
|
+
"country",
|
|
52308
|
+
"countryCode",
|
|
52309
|
+
"handle"
|
|
52310
|
+
]);
|
|
52311
|
+
const authInputMessage = (error) => {
|
|
52312
|
+
const field = typeof error.details?.field === "string" ? error.details.field : "";
|
|
52313
|
+
if (field === "handle") return HANDLE_INPUT_MESSAGE;
|
|
52314
|
+
if (PROFILE_FIELDS.has(field)) return PROFILE_INPUT_MESSAGE;
|
|
52315
|
+
return INPUT_MESSAGE;
|
|
52316
|
+
};
|
|
52317
|
+
/**
|
|
52264
52318
|
* The one allowlist. Only a WRONG_STATE whose SDK details carry an Organization
|
|
52265
52319
|
* ID the public constructor accepts emits that ID, and it never enters message
|
|
52266
52320
|
* text or valid states. No other error detail reaches terminal output, and a
|
|
@@ -52310,7 +52364,7 @@ function classifyFailure(cause, command) {
|
|
|
52310
52364
|
const details = allowlistedDetails(error);
|
|
52311
52365
|
return {
|
|
52312
52366
|
code: error.code,
|
|
52313
|
-
message: auth ? "Authentication is required." : denied ? "This action is not permitted." : wrongState ? organizationCommand(command) ? ORGANIZATION_WRONG_STATE_MESSAGE : WRONG_STATE_MESSAGE : input ? INPUT_MESSAGE : "The Capxul request failed.",
|
|
52367
|
+
message: auth ? "Authentication is required." : denied ? "This action is not permitted." : wrongState ? organizationCommand(command) ? ORGANIZATION_WRONG_STATE_MESSAGE : authCommand(command) ? PERSONAL_ACCOUNT_WRONG_STATE_MESSAGE : WRONG_STATE_MESSAGE : input ? authCommand(command) ? authInputMessage(error) : INPUT_MESSAGE : "The Capxul request failed.",
|
|
52314
52368
|
exitCode: auth ? 3 : denied ? 4 : input || wrongState ? 2 : 5,
|
|
52315
52369
|
outcome: auth || denied || input || wrongState ? "refused" : "failed",
|
|
52316
52370
|
...details === void 0 ? {} : { details }
|
|
@@ -52330,7 +52384,7 @@ function parsedCommand(cause) {
|
|
|
52330
52384
|
//#endregion
|
|
52331
52385
|
//#region src/runtime/config.ts
|
|
52332
52386
|
const bundledKey = Redacted.make("cap_pk_test_DXF9C0HPKB9GPQX5C6RDP6NXKZG1B0D7");
|
|
52333
|
-
const bundledOrigin = "https://
|
|
52387
|
+
const bundledOrigin = "https://api.staging.capxul.com";
|
|
52334
52388
|
const defaultHost = "https://us.i.posthog.com";
|
|
52335
52389
|
const defaultProjectToken = Redacted.make("phc_BZuAVofrkNXzwpJkuDG7Rdfurir45fj2dudQvJZk847e");
|
|
52336
52390
|
const optionalText$1 = (name) => Config.option(Config.string(name));
|
|
@@ -53005,9 +53059,14 @@ const runCommand = (options, work) => Effect.gen(function* () {
|
|
|
53005
53059
|
//#endregion
|
|
53006
53060
|
//#region src/platform/capxul.ts
|
|
53007
53061
|
const resultValue = (result) => result.ok ? Effect.succeed(result.value) : Effect.fail(result.error);
|
|
53062
|
+
const localDiagnosticsEnabled = (args) => args.some((arg, index) => arg === "--log-level=debug" || arg === "--logLevel=debug" || (arg === "--log-level" || arg === "--logLevel") && args[index + 1] === "debug");
|
|
53008
53063
|
const acquireClient = (input, onFinalize) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
53064
|
+
const runtime = yield* CliRuntime;
|
|
53009
53065
|
const created = yield* restore(Effect.promise(async (signal) => {
|
|
53010
|
-
const result = await createCapxulClient(
|
|
53066
|
+
const result = await createCapxulClient({
|
|
53067
|
+
...input,
|
|
53068
|
+
localDiagnostics: localDiagnosticsEnabled(runtime.args ?? [])
|
|
53069
|
+
});
|
|
53011
53070
|
if (signal.aborted && result.ok) await result.value.close();
|
|
53012
53071
|
return result;
|
|
53013
53072
|
}));
|
|
@@ -53166,11 +53225,11 @@ const CurrentSession = Schema.Struct({
|
|
|
53166
53225
|
authUserId: Schema.NonEmptyString
|
|
53167
53226
|
}))
|
|
53168
53227
|
});
|
|
53169
|
-
const decode$
|
|
53228
|
+
const decode$2 = (value) => Schema.decodeUnknownEffect(Schema.fromJsonString(CurrentSession), { onExcessProperty: "error" })(value).pipe(Effect.mapError(() => new StateFileError({ reason: "Corrupt" })));
|
|
53170
53229
|
const readCurrentSession = (config) => Effect.gen(function* () {
|
|
53171
53230
|
const { directory, scope } = yield* privateRecordScope(config, "current-session", "current");
|
|
53172
53231
|
const value = yield* readPrivateRecord(directory, scope);
|
|
53173
|
-
return value === null ? null : (yield* decode$
|
|
53232
|
+
return value === null ? null : (yield* decode$2(value)).current;
|
|
53174
53233
|
});
|
|
53175
53234
|
const rememberCurrentSession = (config, session, stillAuthenticated) => Effect.gen(function* () {
|
|
53176
53235
|
const { directory, scope } = yield* privateRecordScope(config, "current-session", "current");
|
|
@@ -53183,7 +53242,7 @@ const rememberCurrentSession = (config, session, stillAuthenticated) => Effect.g
|
|
|
53183
53242
|
};
|
|
53184
53243
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
53185
53244
|
const expected = yield* readPrivateRecord(directory, scope);
|
|
53186
|
-
if (expected !== null) yield* decode$
|
|
53245
|
+
if (expected !== null) yield* decode$2(expected);
|
|
53187
53246
|
if (yield* compareAndSetPrivateRecord(directory, scope, expected, JSON.stringify(next), stillAuthenticated)) return;
|
|
53188
53247
|
if (!(yield* stillAuthenticated)) break;
|
|
53189
53248
|
}
|
|
@@ -53193,7 +53252,7 @@ const forgetCurrentSession = (config, email, stillCleared) => Effect.gen(functio
|
|
|
53193
53252
|
const { directory, scope } = yield* privateRecordScope(config, "current-session", "current");
|
|
53194
53253
|
const expected = yield* readPrivateRecordSnapshot(directory, scope);
|
|
53195
53254
|
if (expected === null) return false;
|
|
53196
|
-
if ((yield* decode$
|
|
53255
|
+
if ((yield* decode$2(expected)).current?.email !== email.toLowerCase()) return false;
|
|
53197
53256
|
return yield* compareAndSetPrivateRecord(directory, scope, expected, JSON.stringify({
|
|
53198
53257
|
version: 1,
|
|
53199
53258
|
current: null
|
|
@@ -53210,48 +53269,118 @@ const inputRequired = (message) => new CliFailure({
|
|
|
53210
53269
|
const readEmail = (email) => Effect.gen(function* () {
|
|
53211
53270
|
const runtime = yield* CliRuntime;
|
|
53212
53271
|
if (email === void 0) {
|
|
53213
|
-
if (!runtime.tty || runtime.ci || runtime.mode === "json") return yield* Effect.fail(inputRequired("Provide --email.
|
|
53272
|
+
if (!runtime.tty || runtime.ci || runtime.mode === "json") return yield* Effect.fail(inputRequired("Provide --email."));
|
|
53214
53273
|
email = yield* Prompt.text({ message: "Email" });
|
|
53215
53274
|
}
|
|
53216
53275
|
const normalized = email.trim().toLowerCase();
|
|
53217
53276
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalized)) return yield* Effect.fail(inputRequired("Provide a valid email."));
|
|
53218
53277
|
return normalized;
|
|
53219
53278
|
});
|
|
53279
|
+
const OTP_INPUT_ERROR = "OTP input must contain six digits only.";
|
|
53280
|
+
const OTP_BOUNDARY_MARKS = /^[\s\p{Cf}]+|[\s\p{Cf}]+$/gu;
|
|
53281
|
+
const normalizeOtpInput = (input) => {
|
|
53282
|
+
if (new TextEncoder().encode(input).byteLength > 64) return null;
|
|
53283
|
+
const normalized = input.replace(OTP_BOUNDARY_MARKS, "");
|
|
53284
|
+
return /^[0-9]{6}$/.test(normalized) ? normalized : null;
|
|
53285
|
+
};
|
|
53220
53286
|
const readOtp = (stdin) => Effect.gen(function* () {
|
|
53221
53287
|
const runtime = yield* CliRuntime;
|
|
53222
53288
|
if (!stdin) {
|
|
53223
53289
|
if (!runtime.tty || runtime.ci || runtime.mode === "json") return yield* Effect.fail(inputRequired("Provide the OTP on stdin with --otp-stdin; OTP arguments are not accepted."));
|
|
53224
|
-
return Redacted.value(yield* Prompt.
|
|
53290
|
+
return Redacted.value(yield* Prompt.password({
|
|
53291
|
+
message: "Email OTP",
|
|
53292
|
+
validate: (input) => {
|
|
53293
|
+
const normalized = normalizeOtpInput(input);
|
|
53294
|
+
return normalized === null ? Effect.fail(OTP_INPUT_ERROR) : Effect.succeed(normalized);
|
|
53295
|
+
}
|
|
53296
|
+
}));
|
|
53225
53297
|
}
|
|
53226
53298
|
const stdio = yield* Stdio.Stdio;
|
|
53227
53299
|
let length = 0;
|
|
53228
53300
|
const chunks = yield* stdio.stdin.pipe(Stream.mapEffect((chunk) => {
|
|
53229
53301
|
length += chunk.byteLength;
|
|
53230
|
-
return length > 64 ? Effect.fail(inputRequired(
|
|
53302
|
+
return length > 64 ? Effect.fail(inputRequired(OTP_INPUT_ERROR)) : Effect.succeed(chunk);
|
|
53231
53303
|
}), Stream.decodeText(), Stream.runCollect);
|
|
53232
|
-
const code = Array.from(chunks).join("")
|
|
53233
|
-
if (
|
|
53304
|
+
const code = normalizeOtpInput(Array.from(chunks).join(""));
|
|
53305
|
+
if (code === null) return yield* Effect.fail(inputRequired(OTP_INPUT_ERROR));
|
|
53234
53306
|
return code;
|
|
53235
53307
|
});
|
|
53236
|
-
const
|
|
53237
|
-
|
|
53238
|
-
|
|
53239
|
-
|
|
53240
|
-
|
|
53241
|
-
|
|
53308
|
+
const PROFILE_FLAGS = {
|
|
53309
|
+
displayName: "--display-name",
|
|
53310
|
+
country: "--country",
|
|
53311
|
+
handle: "--handle"
|
|
53312
|
+
};
|
|
53313
|
+
const PROFILE_REFUSALS = {
|
|
53314
|
+
displayName: "Provide --display-name with at least one visible character.",
|
|
53315
|
+
country: "Provide --country as a two-letter ISO country code, for example GH.",
|
|
53316
|
+
handle: "Provide --handle as 3 to 30 characters of a-z, 0-9, underscore, or hyphen."
|
|
53317
|
+
};
|
|
53318
|
+
/**
|
|
53319
|
+
* Accept one Profile value, or return the refusal that names its field.
|
|
53320
|
+
*
|
|
53321
|
+
* Country and handle use the public SDK constructors, so the CLI accepts
|
|
53322
|
+
* exactly the values the backend stores. A handle loses its leading `@` and
|
|
53323
|
+
* its case before the check, which is the canon spelling the owner persists.
|
|
53324
|
+
*/
|
|
53325
|
+
const acceptPersonField = (field, raw) => {
|
|
53326
|
+
const trimmed = raw.trim();
|
|
53327
|
+
if (trimmed.length === 0) return { refusal: inputRequired(PROFILE_REFUSALS[field]) };
|
|
53328
|
+
try {
|
|
53329
|
+
if (field === "country") return { value: toCountryCode(trimmed) };
|
|
53330
|
+
if (field === "handle") return { value: toHandle(trimmed.replace(/^@/u, "").toLowerCase()) };
|
|
53331
|
+
return { value: trimmed };
|
|
53332
|
+
} catch {
|
|
53333
|
+
return { refusal: inputRequired(PROFILE_REFUSALS[field]) };
|
|
53334
|
+
}
|
|
53335
|
+
};
|
|
53336
|
+
/**
|
|
53337
|
+
* Validate the Profile values a caller supplied, before any client work.
|
|
53338
|
+
*
|
|
53339
|
+
* `auth signup` runs this first, so a malformed value refuses locally and
|
|
53340
|
+
* consumes no one-time code. An absent field stays with `readPersonInput`,
|
|
53341
|
+
* which prompts on a terminal and refuses headlessly.
|
|
53342
|
+
*/
|
|
53343
|
+
const checkPersonFlags = (flags) => Effect.gen(function* () {
|
|
53344
|
+
for (const field of [
|
|
53345
|
+
"displayName",
|
|
53346
|
+
"country",
|
|
53347
|
+
"handle"
|
|
53348
|
+
]) {
|
|
53349
|
+
const supplied = flags[field];
|
|
53350
|
+
if (supplied === void 0) continue;
|
|
53351
|
+
const accepted = acceptPersonField(field, supplied);
|
|
53352
|
+
if ("refusal" in accepted) return yield* Effect.fail(accepted.refusal);
|
|
53242
53353
|
}
|
|
53243
|
-
|
|
53244
|
-
|
|
53245
|
-
|
|
53354
|
+
});
|
|
53355
|
+
/**
|
|
53356
|
+
* One required Profile field.
|
|
53357
|
+
*
|
|
53358
|
+
* A non-interactive run accepts only the explicit flag, so headless signup is
|
|
53359
|
+
* deterministic and never prompts. An interactive run prompts, and offers the
|
|
53360
|
+
* existing Profile value as the default so a continuation keeps it.
|
|
53361
|
+
*/
|
|
53362
|
+
const readRequired = (label, field, supplied, existing) => Effect.gen(function* () {
|
|
53363
|
+
const runtime = yield* CliRuntime;
|
|
53364
|
+
if (!runtime.tty || runtime.ci || runtime.mode === "json") {
|
|
53365
|
+
if (supplied === void 0) return yield* Effect.fail(inputRequired(`Provide ${PROFILE_FLAGS[field]}.`));
|
|
53366
|
+
const accepted = acceptPersonField(field, supplied);
|
|
53367
|
+
if ("refusal" in accepted) return yield* Effect.fail(accepted.refusal);
|
|
53368
|
+
return accepted.value;
|
|
53369
|
+
}
|
|
53370
|
+
const fallback = supplied ?? existing;
|
|
53371
|
+
const value = yield* Prompt.text({
|
|
53372
|
+
message: label,
|
|
53373
|
+
...fallback === void 0 || fallback.trim().length === 0 ? {} : { default: fallback }
|
|
53374
|
+
});
|
|
53375
|
+
const accepted = acceptPersonField(field, value);
|
|
53376
|
+
if ("refusal" in accepted) return yield* Effect.fail(accepted.refusal);
|
|
53377
|
+
return accepted.value;
|
|
53246
53378
|
});
|
|
53247
53379
|
const readPersonInput = (flags, profile) => Effect.gen(function* () {
|
|
53248
|
-
const displayName = yield* readRequired("Display name", "display-name", flags.displayName ?? profile?.displayName ?? void 0);
|
|
53249
|
-
const country = yield* readRequired("Country code", "country", flags.country ?? profile?.country ?? void 0);
|
|
53250
|
-
const handle = yield* readRequired("Handle", "handle", flags.handle ?? profile?.handle ?? void 0);
|
|
53251
53380
|
return {
|
|
53252
|
-
displayName,
|
|
53253
|
-
country: country.
|
|
53254
|
-
handle
|
|
53381
|
+
displayName: yield* readRequired("Display name", "displayName", flags.displayName, profile?.displayName ?? void 0),
|
|
53382
|
+
country: yield* readRequired("Country code", "country", flags.country, profile?.country ?? void 0),
|
|
53383
|
+
handle: yield* readRequired("Handle", "handle", flags.handle, profile?.handle ?? void 0)
|
|
53255
53384
|
};
|
|
53256
53385
|
});
|
|
53257
53386
|
//#endregion
|
|
@@ -53928,6 +54057,17 @@ const verifiedSession = (client, email) => Effect.gen(function* () {
|
|
|
53928
54057
|
if (session === null || session.email.toLowerCase() !== email) return yield* Effect.fail(Errors.notAuthenticated());
|
|
53929
54058
|
return session;
|
|
53930
54059
|
});
|
|
54060
|
+
const submitOtp = (otpStdin, verify) => Effect.gen(function* () {
|
|
54061
|
+
const submissionLimit = otpStdin ? 1 : 3;
|
|
54062
|
+
for (let submission = 1; submission <= submissionLimit; submission += 1) {
|
|
54063
|
+
const code = yield* readOtp(otpStdin);
|
|
54064
|
+
const result = yield* Effect.result(verify(code));
|
|
54065
|
+
if (Result.isSuccess(result)) return;
|
|
54066
|
+
const error = result.failure;
|
|
54067
|
+
if (!(error.code === "INVALID_INPUT" && error.details?.field === "otp") || submission === submissionLimit) return yield* Effect.fail(error);
|
|
54068
|
+
yield* writeStderr("Invalid OTP. Try again.\n");
|
|
54069
|
+
}
|
|
54070
|
+
});
|
|
53931
54071
|
/**
|
|
53932
54072
|
* Local authentication checks only: the current-session pointer, the explicit
|
|
53933
54073
|
* email, and a stored credential. No bootstrap, client, or network work. A
|
|
@@ -54005,6 +54145,60 @@ const flushWalletDiagnostics = (bridge, invocationId) => Effect.suspend(() => br
|
|
|
54005
54145
|
invocation_id: invocationId,
|
|
54006
54146
|
journey_id: invocationId
|
|
54007
54147
|
}), { discard: true }));
|
|
54148
|
+
const SIGNUP_OTP_INPUT_REQUIRED = "Use --otp-stdin for non-interactive signup. OTP arguments are not accepted.";
|
|
54149
|
+
/**
|
|
54150
|
+
* One account-setup continuation: profile input, then wallet and Account work.
|
|
54151
|
+
*
|
|
54152
|
+
* `signup` calls this after authentication. An interactive `login` calls it
|
|
54153
|
+
* only after the person accepts the setup offer. A headless `login` never calls
|
|
54154
|
+
* it, so sign-in cannot become signup.
|
|
54155
|
+
*
|
|
54156
|
+
* The step returns a ready report only. When the personal Account is not ready,
|
|
54157
|
+
* it returns a typed recoverable report: `setupState` names the state, the
|
|
54158
|
+
* lifecycle carries the failure code, and the copy names the exact resume
|
|
54159
|
+
* action. The step never starts wallet work for a ready Account, so a retry
|
|
54160
|
+
* reuses the one Profile, wallet, Smart Account, and Account.
|
|
54161
|
+
*/
|
|
54162
|
+
const completeAccountSetup = (config, store, client, session, suppliedProfile) => Effect.gen(function* () {
|
|
54163
|
+
const current = yield* call((signal) => client.identity.loadCurrent({ signal }));
|
|
54164
|
+
const before = yield* profileReport(client, session);
|
|
54165
|
+
if (before.data.setupState === "ready") return before;
|
|
54166
|
+
const profile = yield* readPersonInput(suppliedProfile, current);
|
|
54167
|
+
const runtime = yield* CliRuntime;
|
|
54168
|
+
const run = Effect.runPromiseWith(yield* Effect.context());
|
|
54169
|
+
let bridge;
|
|
54170
|
+
const invocation = yield* Ref.get(runtime.current);
|
|
54171
|
+
const openfortSignerFactory = (bootstrap) => {
|
|
54172
|
+
const created = createBrowserSignerBridge({
|
|
54173
|
+
bootstrap,
|
|
54174
|
+
environment: config.environment,
|
|
54175
|
+
handle: () => profile.handle,
|
|
54176
|
+
trustedAuthOrigin: new URL(config.bootstrapBaseUrl).origin,
|
|
54177
|
+
sessionToken: () => run(store.tokenIfCurrent())
|
|
54178
|
+
});
|
|
54179
|
+
bridge = created;
|
|
54180
|
+
invocation?.onFinalize?.(Effect.promise(() => created.close()).pipe(Effect.asVoid, Effect.catchCause(() => Effect.void)));
|
|
54181
|
+
return created.signer;
|
|
54182
|
+
};
|
|
54183
|
+
const walletClient = yield* clientFor(config, store, {
|
|
54184
|
+
restore: true,
|
|
54185
|
+
requirement: "deployed",
|
|
54186
|
+
openfortSignerFactory
|
|
54187
|
+
});
|
|
54188
|
+
const verified = yield* verifiedSession(walletClient, session.email);
|
|
54189
|
+
yield* writeStderr("Preparing your wallet in the browser. Keep that tab open.\n");
|
|
54190
|
+
const report = yield* Effect.gen(function* () {
|
|
54191
|
+
yield* call((signal) => walletClient.onboarding.completePerson(profile, { signal }));
|
|
54192
|
+
return yield* profileReport(walletClient, verified);
|
|
54193
|
+
}).pipe(Effect.ensuring(Effect.suspend(() => flushWalletDiagnostics(bridge, runtime.invocationId))));
|
|
54194
|
+
return {
|
|
54195
|
+
data: {
|
|
54196
|
+
...report.data,
|
|
54197
|
+
signerStatus: walletClient.signer.status()
|
|
54198
|
+
},
|
|
54199
|
+
lines: report.lines
|
|
54200
|
+
};
|
|
54201
|
+
});
|
|
54008
54202
|
const sendOtp = (config, suppliedEmail) => Effect.gen(function* () {
|
|
54009
54203
|
const email = yield* readEmail(suppliedEmail);
|
|
54010
54204
|
const store = yield* openSessionRecord(config, email);
|
|
@@ -54029,7 +54223,6 @@ const verifyOtp = (config, suppliedEmail, otpStdin) => Effect.gen(function* () {
|
|
|
54029
54223
|
const store = yield* openSessionRecord(config, email);
|
|
54030
54224
|
const flow = store.current().flow;
|
|
54031
54225
|
if (flow === null || flow.email !== email) return yield* Effect.fail(inputRequired("No pending OTP. Run auth send --email <email> first."));
|
|
54032
|
-
const code = yield* readOtp(otpStdin);
|
|
54033
54226
|
const client = yield* clientFor(config, store, { restore: false });
|
|
54034
54227
|
yield* call((signal) => client.auth.getSession({ signal }));
|
|
54035
54228
|
yield* call((signal) => client.auth.resumeOtp({
|
|
@@ -54039,13 +54232,13 @@ const verifyOtp = (config, suppliedEmail, otpStdin) => Effect.gen(function* () {
|
|
|
54039
54232
|
signal,
|
|
54040
54233
|
journey_id: flow.journeyId
|
|
54041
54234
|
}));
|
|
54042
|
-
yield* call((signal) => client.auth.verifyOtp({
|
|
54235
|
+
yield* submitOtp(otpStdin, (code) => call((signal) => client.auth.verifyOtp({
|
|
54043
54236
|
email,
|
|
54044
54237
|
code
|
|
54045
54238
|
}, {
|
|
54046
54239
|
signal,
|
|
54047
54240
|
journey_id: flow.journeyId
|
|
54048
|
-
}));
|
|
54241
|
+
})));
|
|
54049
54242
|
const session = yield* verifiedSession(client, email);
|
|
54050
54243
|
yield* bindPerson(config, store, session);
|
|
54051
54244
|
const report = yield* profileReport(client, session);
|
|
@@ -54060,95 +54253,64 @@ const verifyOtp = (config, suppliedEmail, otpStdin) => Effect.gen(function* () {
|
|
|
54060
54253
|
const login = (config, suppliedEmail, otpStdin) => Effect.gen(function* () {
|
|
54061
54254
|
const email = yield* readEmail(suppliedEmail);
|
|
54062
54255
|
const runtime = yield* CliRuntime;
|
|
54063
|
-
if (!otpStdin && (!runtime.tty || runtime.ci || runtime.mode === "json")) return yield* Effect.fail(inputRequired("Use auth send, then auth verify
|
|
54256
|
+
if (!otpStdin && (!runtime.tty || runtime.ci || runtime.mode === "json")) return yield* Effect.fail(inputRequired("Provide the OTP on stdin with --otp-stdin. Use capxul auth send, then capxul auth verify, to split sign-in across two commands."));
|
|
54064
54257
|
const store = yield* openSessionRecord(config, email);
|
|
54065
54258
|
const client = yield* clientFor(config, store, { restore: false });
|
|
54066
54259
|
yield* call((signal) => client.auth.getSession({ signal }));
|
|
54067
54260
|
yield* store.begin(yield* Clock.currentTimeMillis, runtime.invocationId);
|
|
54068
54261
|
yield* call((signal) => client.auth.signIn({ email }, { signal }));
|
|
54069
54262
|
yield* writeStderr("Verification email sent. Enter the code to continue.\n");
|
|
54070
|
-
|
|
54071
|
-
yield* call((signal) => client.auth.verifyOtp({
|
|
54263
|
+
yield* submitOtp(otpStdin, (code) => call((signal) => client.auth.verifyOtp({
|
|
54072
54264
|
email,
|
|
54073
54265
|
code
|
|
54074
54266
|
}, {
|
|
54075
54267
|
signal,
|
|
54076
54268
|
journey_id: runtime.invocationId
|
|
54077
|
-
}));
|
|
54269
|
+
})));
|
|
54078
54270
|
const session = yield* verifiedSession(client, email);
|
|
54079
54271
|
yield* bindPerson(config, store, session);
|
|
54080
|
-
|
|
54272
|
+
const report = yield* profileReport(client, session);
|
|
54273
|
+
if (report.data.setupState === "ready") return report;
|
|
54274
|
+
if (!runtime.tty || runtime.ci || runtime.mode === "json") return report;
|
|
54275
|
+
if (!(yield* Prompt.confirm({
|
|
54276
|
+
message: "Your Capxul account is not set up yet. Continue setup now?",
|
|
54277
|
+
initial: false
|
|
54278
|
+
}))) return report;
|
|
54279
|
+
return yield* completeAccountSetup(config, store, client, session, {});
|
|
54081
54280
|
});
|
|
54082
54281
|
const signup = (config, suppliedEmail, otpStdin, suppliedProfile) => Effect.gen(function* () {
|
|
54083
54282
|
const email = yield* readEmail(suppliedEmail);
|
|
54084
54283
|
const runtime = yield* CliRuntime;
|
|
54284
|
+
yield* checkPersonFlags(suppliedProfile);
|
|
54085
54285
|
const store = yield* openSessionRecord(config, email);
|
|
54086
|
-
const run = Effect.runPromiseWith(yield* Effect.context());
|
|
54087
54286
|
const restore = store.current().token !== null;
|
|
54088
|
-
|
|
54089
|
-
let bridge;
|
|
54287
|
+
if (!restore && !otpStdin && (!runtime.tty || runtime.ci || runtime.mode === "json")) return yield* Effect.fail(inputRequired(SIGNUP_OTP_INPUT_REQUIRED));
|
|
54090
54288
|
let client = yield* clientFor(config, store, { restore });
|
|
54091
54289
|
let session = restore ? yield* verifiedSession(client, email).pipe(Effect.catch((error) => error.code === "NOT_AUTHENTICATED" ? store.clear.pipe(Effect.as(null)) : Effect.fail(error))) : null;
|
|
54092
54290
|
if (session === null) {
|
|
54093
54291
|
if (restore) client = yield* clientFor(config, store, { restore: false });
|
|
54094
|
-
if (!otpStdin && (!runtime.tty || runtime.ci || runtime.mode === "json")) return yield* Effect.fail(inputRequired(
|
|
54292
|
+
if (!otpStdin && (!runtime.tty || runtime.ci || runtime.mode === "json")) return yield* Effect.fail(inputRequired(SIGNUP_OTP_INPUT_REQUIRED));
|
|
54095
54293
|
yield* call((signal) => client.auth.getSession({ signal }));
|
|
54096
54294
|
yield* store.begin(yield* Clock.currentTimeMillis, runtime.invocationId);
|
|
54097
54295
|
yield* call((signal) => client.auth.signIn({ email }, { signal }));
|
|
54098
54296
|
yield* writeStderr("Verification email sent. Enter the code to continue.\n");
|
|
54099
|
-
|
|
54100
|
-
yield* call((signal) => client.auth.verifyOtp({
|
|
54297
|
+
yield* submitOtp(otpStdin, (code) => call((signal) => client.auth.verifyOtp({
|
|
54101
54298
|
email,
|
|
54102
54299
|
code
|
|
54103
54300
|
}, {
|
|
54104
54301
|
signal,
|
|
54105
54302
|
journey_id: runtime.invocationId
|
|
54106
|
-
}));
|
|
54303
|
+
})));
|
|
54107
54304
|
session = yield* verifiedSession(client, email);
|
|
54108
54305
|
}
|
|
54109
54306
|
yield* bindPerson(config, store, session);
|
|
54110
|
-
|
|
54111
|
-
const before = yield* profileReport(client, session);
|
|
54112
|
-
if (before.data.setupState === "ready") return before;
|
|
54113
|
-
const profile = yield* readPersonInput(suppliedProfile, current);
|
|
54114
|
-
handle = profile.handle;
|
|
54115
|
-
const invocation = yield* Ref.get(runtime.current);
|
|
54116
|
-
const openfortSignerFactory = (bootstrap) => {
|
|
54117
|
-
const created = createBrowserSignerBridge({
|
|
54118
|
-
bootstrap,
|
|
54119
|
-
environment: config.environment,
|
|
54120
|
-
handle: () => handle,
|
|
54121
|
-
trustedAuthOrigin: new URL(config.bootstrapBaseUrl).origin,
|
|
54122
|
-
sessionToken: () => run(store.tokenIfCurrent())
|
|
54123
|
-
});
|
|
54124
|
-
bridge = created;
|
|
54125
|
-
invocation?.onFinalize?.(Effect.promise(() => created.close()).pipe(Effect.asVoid, Effect.catchCause(() => Effect.void)));
|
|
54126
|
-
return created.signer;
|
|
54127
|
-
};
|
|
54128
|
-
const walletClient = yield* clientFor(config, store, {
|
|
54129
|
-
restore: true,
|
|
54130
|
-
requirement: "deployed",
|
|
54131
|
-
openfortSignerFactory
|
|
54132
|
-
});
|
|
54133
|
-
session = yield* verifiedSession(walletClient, email);
|
|
54134
|
-
yield* writeStderr("Preparing your wallet in the browser. Keep that tab open.\n");
|
|
54135
|
-
const report = yield* Effect.gen(function* () {
|
|
54136
|
-
yield* call((signal) => walletClient.onboarding.completePerson(profile, { signal }));
|
|
54137
|
-
return yield* profileReport(walletClient, session);
|
|
54138
|
-
}).pipe(Effect.ensuring(Effect.suspend(() => flushWalletDiagnostics(bridge, runtime.invocationId))));
|
|
54139
|
-
return {
|
|
54140
|
-
data: {
|
|
54141
|
-
...report.data,
|
|
54142
|
-
signerStatus: walletClient.signer.status()
|
|
54143
|
-
},
|
|
54144
|
-
lines: report.lines
|
|
54145
|
-
};
|
|
54307
|
+
return yield* completeAccountSetup(config, store, client, session, suppliedProfile);
|
|
54146
54308
|
});
|
|
54147
54309
|
const readProfile = (config, suppliedEmail) => Effect.gen(function* () {
|
|
54148
54310
|
const email = yield* readEmail(suppliedEmail);
|
|
54149
54311
|
const store = yield* openSessionRecord(config, email);
|
|
54150
54312
|
if (store.current().token === null) {
|
|
54151
|
-
if (usableGrant(yield* loadGrant(config, email))) return yield* Effect.fail(inputRequired("
|
|
54313
|
+
if (usableGrant(yield* loadGrant(config, email))) return yield* Effect.fail(inputRequired("Sign in again with capxul auth login to use this command."));
|
|
54152
54314
|
return yield* Effect.fail(Errors.notAuthenticated());
|
|
54153
54315
|
}
|
|
54154
54316
|
const client = yield* clientFor(config, store, { restore: true });
|
|
@@ -54207,11 +54369,11 @@ const logout = (config, suppliedEmail) => Effect.gen(function* () {
|
|
|
54207
54369
|
});
|
|
54208
54370
|
//#endregion
|
|
54209
54371
|
//#region src/commands/auth.ts
|
|
54210
|
-
const emailFlag$3 = Flag.string("email").pipe(Flag.withDescription("
|
|
54211
|
-
const otpStdinFlag = Flag.boolean("otp-stdin").pipe(Flag.withDefault(false), Flag.withDescription("Read the six-digit OTP from
|
|
54212
|
-
const displayNameFlag = Flag.string("display-name").pipe(Flag.withDescription("
|
|
54213
|
-
const countryFlag = Flag.string("country").pipe(Flag.withDescription("Two-letter
|
|
54214
|
-
const handleFlag = Flag.string("handle").pipe(Flag.withDescription("
|
|
54372
|
+
const emailFlag$3 = Flag.string("email").pipe(Flag.withDescription("Email address"), Flag.optional);
|
|
54373
|
+
const otpStdinFlag = Flag.boolean("otp-stdin").pipe(Flag.withDefault(false), Flag.withDescription("Read the six-digit OTP from standard input; never pass it as an argument"));
|
|
54374
|
+
const displayNameFlag = Flag.string("display-name").pipe(Flag.withDescription("Your display name"), Flag.optional);
|
|
54375
|
+
const countryFlag = Flag.string("country").pipe(Flag.withDescription("Two-letter country code"), Flag.optional);
|
|
54376
|
+
const handleFlag = Flag.string("handle").pipe(Flag.withDescription("Your unique Capxul handle"), Flag.optional);
|
|
54215
54377
|
const metadata$4 = (name) => ({
|
|
54216
54378
|
name,
|
|
54217
54379
|
capability: "authentication",
|
|
@@ -54223,7 +54385,7 @@ const loginCommand = Command.make("login", {
|
|
|
54223
54385
|
}, ({ email, otpStdin }) => runCommand({
|
|
54224
54386
|
...metadata$4("auth.login"),
|
|
54225
54387
|
network: true
|
|
54226
|
-
}, (config) => login(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.login")), Command.withDescription("
|
|
54388
|
+
}, (config) => login(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.login")), Command.withDescription("Sign in with your email and a one-time code"));
|
|
54227
54389
|
const signupCommand = Command.make("signup", {
|
|
54228
54390
|
email: emailFlag$3,
|
|
54229
54391
|
otpStdin: otpStdinFlag,
|
|
@@ -54237,31 +54399,31 @@ const signupCommand = Command.make("signup", {
|
|
|
54237
54399
|
displayName: Option.getOrUndefined(displayName),
|
|
54238
54400
|
country: Option.getOrUndefined(country),
|
|
54239
54401
|
handle: Option.getOrUndefined(handle)
|
|
54240
|
-
}))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.signup")), Command.withDescription("
|
|
54402
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.signup")), Command.withDescription("Create your Capxul account and wallet"));
|
|
54241
54403
|
const sendCommand = Command.make("send", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54242
54404
|
...metadata$4("auth.send"),
|
|
54243
54405
|
network: true
|
|
54244
|
-
}, (config) => sendOtp(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.send")), Command.withDescription("Send
|
|
54406
|
+
}, (config) => sendOtp(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.send")), Command.withDescription("Send a sign-in code to your email"));
|
|
54245
54407
|
const verifyCommand = Command.make("verify", {
|
|
54246
54408
|
email: emailFlag$3,
|
|
54247
54409
|
otpStdin: otpStdinFlag
|
|
54248
54410
|
}, ({ email, otpStdin }) => runCommand({
|
|
54249
54411
|
...metadata$4("auth.verify"),
|
|
54250
54412
|
network: true
|
|
54251
|
-
}, (config) => verifyOtp(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.verify")), Command.withDescription("
|
|
54413
|
+
}, (config) => verifyOtp(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.verify")), Command.withDescription("Finish signing in with the code from your email"));
|
|
54252
54414
|
const profileCommand = Command.make("profile", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54253
54415
|
...metadata$4("auth.profile"),
|
|
54254
54416
|
network: true
|
|
54255
|
-
}, (config) => readProfile(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.profile")), Command.withDescription("
|
|
54417
|
+
}, (config) => readProfile(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.profile")), Command.withDescription("Show your profile and account readiness"));
|
|
54256
54418
|
const statusCommand = Command.make("status", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54257
54419
|
...metadata$4("auth.status"),
|
|
54258
54420
|
network: true
|
|
54259
|
-
}, (config) => status$2(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.status")), Command.withDescription("
|
|
54421
|
+
}, (config) => status$2(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.status")), Command.withDescription("Show whether you are signed in"));
|
|
54260
54422
|
const logoutCommand = Command.make("logout", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54261
54423
|
...metadata$4("auth.logout"),
|
|
54262
54424
|
network: true
|
|
54263
|
-
}, (config) => logout(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.logout")), Command.withDescription("
|
|
54264
|
-
const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, metadata$4("auth")), Command.withDescription("
|
|
54425
|
+
}, (config) => logout(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.logout")), Command.withDescription("Sign out on this device"));
|
|
54426
|
+
const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, metadata$4("auth")), Command.withDescription("Sign in, create your account, and manage your session"), Command.withSubcommands([
|
|
54265
54427
|
loginCommand,
|
|
54266
54428
|
signupCommand,
|
|
54267
54429
|
sendCommand,
|
|
@@ -54334,6 +54496,73 @@ const telemetry = Command.make("telemetry").pipe(Command.annotate(CliCommandMeta
|
|
|
54334
54496
|
disable
|
|
54335
54497
|
]));
|
|
54336
54498
|
//#endregion
|
|
54499
|
+
//#region src/org-recovery.ts
|
|
54500
|
+
/**
|
|
54501
|
+
* The one safe recovery handle for a person's Organization journey.
|
|
54502
|
+
*
|
|
54503
|
+
* `handle` is the exact business handle the create prepared. It is the only
|
|
54504
|
+
* identity the CLI knows while the first durable Organization write is in
|
|
54505
|
+
* flight, and the backend resumes the same Organization for that handle.
|
|
54506
|
+
* `organizationId` is added from the first committed Organization. After that
|
|
54507
|
+
* the ID is the recovery target.
|
|
54508
|
+
*
|
|
54509
|
+
* A record with no handle releases the journey: the backend refused that exact
|
|
54510
|
+
* handle before it wrote any Organization row, so no Organization waits to be
|
|
54511
|
+
* resumed. The record stores no draft, submission, credential, or token.
|
|
54512
|
+
*/
|
|
54513
|
+
const Recovery = Schema.Struct({
|
|
54514
|
+
version: Schema.Literal(1),
|
|
54515
|
+
handle: Schema.optional(Schema.NonEmptyString),
|
|
54516
|
+
organizationId: Schema.optional(Schema.NonEmptyString)
|
|
54517
|
+
});
|
|
54518
|
+
const decode$1 = (value) => Schema.decodeUnknownEffect(Schema.fromJsonString(Recovery), { onExcessProperty: "error" })(value).pipe(Effect.flatMap((record) => {
|
|
54519
|
+
const organizationId = record.organizationId ?? null;
|
|
54520
|
+
if (record.handle === void 0) return organizationId === null ? Effect.succeed(null) : Effect.fail(new StateFileError({ reason: "Corrupt" }));
|
|
54521
|
+
const handle = record.handle;
|
|
54522
|
+
return Effect.try(() => ({
|
|
54523
|
+
handle: String(toHandle(handle)),
|
|
54524
|
+
organizationId: organizationId === null ? null : toOrgId(organizationId)
|
|
54525
|
+
}));
|
|
54526
|
+
}), Effect.mapError(() => new StateFileError({ reason: "Corrupt" })));
|
|
54527
|
+
const encode = (recovery) => JSON.stringify({
|
|
54528
|
+
version: 1,
|
|
54529
|
+
handle: recovery.handle,
|
|
54530
|
+
...recovery.organizationId === null ? {} : { organizationId: String(recovery.organizationId) }
|
|
54531
|
+
});
|
|
54532
|
+
/** The released shape: no handle waits to be resumed. */
|
|
54533
|
+
const RELEASED = JSON.stringify({ version: 1 });
|
|
54534
|
+
/** Read the safe recovery handle without writing. A corrupt record refuses the command. */
|
|
54535
|
+
const readOrganizationRecovery = (config, authUserId) => Effect.gen(function* () {
|
|
54536
|
+
const { directory, scope } = yield* privateRecordScope(config, "organization-recovery", authUserId);
|
|
54537
|
+
const value = yield* readPrivateRecord(directory, scope);
|
|
54538
|
+
return value === null ? null : yield* decode$1(value);
|
|
54539
|
+
});
|
|
54540
|
+
/**
|
|
54541
|
+
* Open the recovery handle for one command.
|
|
54542
|
+
*
|
|
54543
|
+
* `save` and `release` replace only the exact record this command read, so two
|
|
54544
|
+
* commands cannot overwrite each other's Organization journey, and a delayed
|
|
54545
|
+
* write cannot follow a newer one. A record this command did not read refuses
|
|
54546
|
+
* the write.
|
|
54547
|
+
*/
|
|
54548
|
+
const openOrganizationRecovery = (config, authUserId, stillAuthenticated) => Effect.gen(function* () {
|
|
54549
|
+
const { directory, scope } = yield* privateRecordScope(config, "organization-recovery", authUserId);
|
|
54550
|
+
let encoded = yield* readPrivateRecord(directory, scope);
|
|
54551
|
+
let record = encoded === null ? null : yield* decode$1(encoded);
|
|
54552
|
+
const write = (next) => Effect.gen(function* () {
|
|
54553
|
+
const value = next === null ? RELEASED : encode(next);
|
|
54554
|
+
if (value === encoded) return;
|
|
54555
|
+
if (!(yield* compareAndSetPrivateRecord(directory, scope, encoded, value, stillAuthenticated))) return yield* Effect.fail(Errors.notAuthenticated("The local Organization recovery state changed. Retry the command."));
|
|
54556
|
+
encoded = value;
|
|
54557
|
+
record = next;
|
|
54558
|
+
});
|
|
54559
|
+
return {
|
|
54560
|
+
current: () => record,
|
|
54561
|
+
save: (next) => write(next),
|
|
54562
|
+
release: () => write(null)
|
|
54563
|
+
};
|
|
54564
|
+
});
|
|
54565
|
+
//#endregion
|
|
54337
54566
|
//#region src/org-selection.ts
|
|
54338
54567
|
const Selection = Schema.Struct({
|
|
54339
54568
|
version: Schema.Literal(1),
|
|
@@ -54356,6 +54585,37 @@ const saveOrganizationSelection = (config, authUserId, organizationId, stillAuth
|
|
|
54356
54585
|
});
|
|
54357
54586
|
//#endregion
|
|
54358
54587
|
//#region src/org.ts
|
|
54588
|
+
/**
|
|
54589
|
+
* The exact Organization a read uses when the caller named no ID: the saved read
|
|
54590
|
+
* default first, then the recorded recovery handle for this person's
|
|
54591
|
+
* Organization journey. `recoverable` marks the handle source, whose Organization
|
|
54592
|
+
* may still run its setup lane and be absent from the own-access list.
|
|
54593
|
+
*/
|
|
54594
|
+
const readResolvedOrganization = (config, authUserId, organizationId) => Effect.gen(function* () {
|
|
54595
|
+
if (organizationId !== null) return {
|
|
54596
|
+
organizationId,
|
|
54597
|
+
recoverable: false
|
|
54598
|
+
};
|
|
54599
|
+
const selected = yield* readOrganizationSelection(config, authUserId);
|
|
54600
|
+
if (selected !== null) return {
|
|
54601
|
+
organizationId: selected,
|
|
54602
|
+
recoverable: false
|
|
54603
|
+
};
|
|
54604
|
+
const recovery = yield* readOrganizationRecovery(config, authUserId);
|
|
54605
|
+
return {
|
|
54606
|
+
organizationId: recovery?.organizationId ?? null,
|
|
54607
|
+
recoverable: recovery?.organizationId !== null && recovery?.organizationId !== void 0
|
|
54608
|
+
};
|
|
54609
|
+
});
|
|
54610
|
+
/**
|
|
54611
|
+
* A ready Organization this command reports must satisfy current access.
|
|
54612
|
+
*
|
|
54613
|
+
* The own-access list carries a founder's unfinished Organizations through the
|
|
54614
|
+
* backend's founder fallback, and the backend lifecycle read admits the founder
|
|
54615
|
+
* for the durable lane. A confirmed result therefore reads the list again: an
|
|
54616
|
+
* Organization the person cannot reach refuses instead of reporting its state.
|
|
54617
|
+
*/
|
|
54618
|
+
const requireCurrentAccess = (client, organizationId, lifecycle) => lifecycle.status !== "ready" ? Effect.void : Effect.promise((signal) => client.orgs({ signal })).pipe(Effect.flatMap(resultValue), Effect.flatMap((organizations) => organizations.some((organization) => organization.id === organizationId) ? Effect.void : Effect.fail(Errors.invalidInput("org", "The Organization is not accessible."))));
|
|
54359
54619
|
const readOrganization = (config, command, input) => Effect.gen(function* () {
|
|
54360
54620
|
const timeout = yield* Schema.decodeUnknownEffect(Schema.Int.check(Schema.isBetween({
|
|
54361
54621
|
minimum: 1,
|
|
@@ -54382,7 +54642,8 @@ const readOrganization = (config, command, input) => Effect.gen(function* () {
|
|
|
54382
54642
|
address: org.account.address
|
|
54383
54643
|
}))
|
|
54384
54644
|
};
|
|
54385
|
-
|
|
54645
|
+
const resolved = yield* readResolvedOrganization(config, session.authUserId, organizationId);
|
|
54646
|
+
organizationId = resolved.organizationId;
|
|
54386
54647
|
if (organizationId === null) {
|
|
54387
54648
|
const runtime = yield* CliRuntime;
|
|
54388
54649
|
if (!runtime.tty || runtime.ci || runtime.mode === "json" || organizations.length === 0) return yield* Effect.fail(inputRequired("Provide --org or select a read default with org use."));
|
|
@@ -54397,7 +54658,7 @@ const readOrganization = (config, command, input) => Effect.gen(function* () {
|
|
|
54397
54658
|
}))
|
|
54398
54659
|
});
|
|
54399
54660
|
}
|
|
54400
|
-
if (!organizations.some((org) => org.id === organizationId)) return yield* Effect.fail(Errors.invalidInput("org", "The Organization is not accessible."));
|
|
54661
|
+
if (!organizations.some((org) => org.id === organizationId) && !resolved.recoverable) return yield* Effect.fail(Errors.invalidInput("org", "The Organization is not accessible."));
|
|
54401
54662
|
if (command === "use") {
|
|
54402
54663
|
yield* saveOrganizationSelection(config, session.authUserId, organizationId, stillAuthenticated);
|
|
54403
54664
|
return {
|
|
@@ -54450,11 +54711,13 @@ const readOrganization = (config, command, input) => Effect.gen(function* () {
|
|
|
54450
54711
|
const read = Effect.promise((signal) => scoped.getLifecycle({ signal })).pipe(Effect.flatMap(resultValue));
|
|
54451
54712
|
const observed = yield* Effect.gen(function* () {
|
|
54452
54713
|
let lifecycle = yield* read;
|
|
54714
|
+
if (resolved.recoverable) yield* requireCurrentAccess(client, organizationId, lifecycle);
|
|
54453
54715
|
if (command !== "wait") return lifecycle;
|
|
54454
54716
|
while (lifecycle.status !== "ready" && lifecycle.status !== "failed") {
|
|
54455
54717
|
yield* Effect.sleep(1e3);
|
|
54456
54718
|
lifecycle = yield* read;
|
|
54457
54719
|
}
|
|
54720
|
+
if (resolved.recoverable) yield* requireCurrentAccess(client, organizationId, lifecycle);
|
|
54458
54721
|
return lifecycle;
|
|
54459
54722
|
}).pipe(Effect.timeoutOption(timeout * 1e3));
|
|
54460
54723
|
if (Option.isNone(observed)) return yield* Effect.fail(new CliFailure({
|
|
@@ -54538,45 +54801,89 @@ const requireWriteConfirmation = (supplied) => Effect.gen(function* () {
|
|
|
54538
54801
|
*
|
|
54539
54802
|
* The committed Organization ID is retained from the first state that carries
|
|
54540
54803
|
* one and never replaced, so a later failed lane keeps reporting the ID it was
|
|
54541
|
-
* committed to. `flush`
|
|
54542
|
-
*
|
|
54543
|
-
*
|
|
54804
|
+
* committed to. `flush` writes the queued lines first, then makes the ID durable
|
|
54805
|
+
* as this person's safe recovery handle, and only then resolves: the
|
|
54806
|
+
* command-scoped signer awaits it before forwarding a digest, so a failed or
|
|
54807
|
+
* cancelled write saves no handle and forwards no signature.
|
|
54544
54808
|
*/
|
|
54545
|
-
const makeOrganizationProgress = (mode, run) => {
|
|
54809
|
+
const makeOrganizationProgress = (mode, run, persist) => {
|
|
54546
54810
|
const queued = [];
|
|
54811
|
+
const held = [];
|
|
54812
|
+
const heldSet = /* @__PURE__ */ new Set();
|
|
54547
54813
|
const written = /* @__PURE__ */ new Set();
|
|
54548
54814
|
let committed = null;
|
|
54815
|
+
let persisted = null;
|
|
54816
|
+
let readyAllowed = false;
|
|
54549
54817
|
let failure = null;
|
|
54818
|
+
/** One command owns one committed Organization. A second ID is a defect. */
|
|
54819
|
+
const retain = (observed) => {
|
|
54820
|
+
if (committed === null) {
|
|
54821
|
+
committed = observed;
|
|
54822
|
+
return true;
|
|
54823
|
+
}
|
|
54824
|
+
if (committed === observed) return true;
|
|
54825
|
+
failure ??= new CliFailure({
|
|
54826
|
+
code: "CLI_DEFECT",
|
|
54827
|
+
message: "The onboarding stream reported a different Organization.",
|
|
54828
|
+
exitCode: 1,
|
|
54829
|
+
outcome: "failed"
|
|
54830
|
+
});
|
|
54831
|
+
return false;
|
|
54832
|
+
};
|
|
54833
|
+
/**
|
|
54834
|
+
* A ready line waits until the command confirms current access. Every other
|
|
54835
|
+
* line is progress evidence and goes out with the committed ID.
|
|
54836
|
+
*/
|
|
54837
|
+
const enqueue = (text, ready) => {
|
|
54838
|
+
if (written.has(text) || heldSet.has(text)) return;
|
|
54839
|
+
if (ready && !readyAllowed) {
|
|
54840
|
+
heldSet.add(text);
|
|
54841
|
+
held.push(text);
|
|
54842
|
+
return;
|
|
54843
|
+
}
|
|
54844
|
+
written.add(text);
|
|
54845
|
+
queued.push(text);
|
|
54846
|
+
};
|
|
54550
54847
|
const render = (state) => {
|
|
54551
54848
|
const organizationId = state.organizationId;
|
|
54552
54849
|
if (organizationId === null) return null;
|
|
54553
|
-
|
|
54554
|
-
if (committed === null) committed = observed;
|
|
54555
|
-
else if (committed !== observed) {
|
|
54556
|
-
failure ??= new CliFailure({
|
|
54557
|
-
code: "CLI_DEFECT",
|
|
54558
|
-
message: "The onboarding stream reported a different Organization.",
|
|
54559
|
-
exitCode: 1,
|
|
54560
|
-
outcome: "failed"
|
|
54561
|
-
});
|
|
54562
|
-
return null;
|
|
54563
|
-
}
|
|
54850
|
+
if (!retain(String(organizationId))) return null;
|
|
54564
54851
|
const status = state.lifecycle?.status;
|
|
54565
54852
|
if (status === void 0) return null;
|
|
54566
|
-
return
|
|
54567
|
-
|
|
54568
|
-
|
|
54569
|
-
|
|
54570
|
-
|
|
54853
|
+
return {
|
|
54854
|
+
text: `${mode === "json" ? JSON.stringify({
|
|
54855
|
+
type: "organization.lifecycle",
|
|
54856
|
+
organizationId: committed,
|
|
54857
|
+
status
|
|
54858
|
+
}) : `Organization ${JSON.stringify(committed)}: ${status}`}\n`,
|
|
54859
|
+
ready: status === "ready"
|
|
54860
|
+
};
|
|
54571
54861
|
};
|
|
54572
54862
|
return {
|
|
54573
54863
|
/** Synchronous by contract: the SDK publishes state from its own fiber. */
|
|
54574
54864
|
observe: (state) => {
|
|
54575
|
-
const
|
|
54576
|
-
if (
|
|
54577
|
-
|
|
54578
|
-
|
|
54579
|
-
|
|
54865
|
+
const line = render(state);
|
|
54866
|
+
if (line !== null) enqueue(line.text, line.ready);
|
|
54867
|
+
},
|
|
54868
|
+
/** One safe recovery line the command writes before it resumes a lane. */
|
|
54869
|
+
notice: (text) => enqueue(text, false),
|
|
54870
|
+
/** The final result ID joins the same one-Organization rule. */
|
|
54871
|
+
commit: (organizationId) => {
|
|
54872
|
+
retain(organizationId);
|
|
54873
|
+
},
|
|
54874
|
+
/** Release the ready lines once current access is confirmed. */
|
|
54875
|
+
allowReady: () => {
|
|
54876
|
+
readyAllowed = true;
|
|
54877
|
+
while (held.length > 0) {
|
|
54878
|
+
const text = held.shift();
|
|
54879
|
+
heldSet.delete(text);
|
|
54880
|
+
if (written.has(text)) continue;
|
|
54881
|
+
written.add(text);
|
|
54882
|
+
queued.push(text);
|
|
54883
|
+
}
|
|
54884
|
+
},
|
|
54885
|
+
/** The committed ID this command observed, or null when it observed none. */
|
|
54886
|
+
committed: () => committed,
|
|
54580
54887
|
failure: () => failure,
|
|
54581
54888
|
flush: async () => {
|
|
54582
54889
|
while (queued.length > 0) {
|
|
@@ -54589,6 +54896,13 @@ const makeOrganizationProgress = (mode, run) => {
|
|
|
54589
54896
|
}
|
|
54590
54897
|
queued.shift();
|
|
54591
54898
|
}
|
|
54899
|
+
if (committed !== null && persisted !== committed) try {
|
|
54900
|
+
await persist(committed);
|
|
54901
|
+
persisted = committed;
|
|
54902
|
+
} catch (cause) {
|
|
54903
|
+
failure = cause;
|
|
54904
|
+
throw cause;
|
|
54905
|
+
}
|
|
54592
54906
|
if (failure !== null) throw failure;
|
|
54593
54907
|
}
|
|
54594
54908
|
};
|
|
@@ -54603,15 +54917,63 @@ const confirmWrite = (preview) => Effect.gen(function* () {
|
|
|
54603
54917
|
yield* writeStderr(`${preview.lines.join("\n")}\n`);
|
|
54604
54918
|
if (!(yield* Prompt.confirm({ message: preview.question }).pipe(Effect.catch(() => Effect.succeed(false))))) return yield* Effect.fail(inputRequired("The write was not confirmed."));
|
|
54605
54919
|
});
|
|
54606
|
-
/**
|
|
54607
|
-
|
|
54920
|
+
/**
|
|
54921
|
+
* The Organization reads a terminal preview shows before it asks.
|
|
54922
|
+
*
|
|
54923
|
+
* A create preview also names the recovery handle this machine already holds, so
|
|
54924
|
+
* a person who confirms knows whether the command creates one more Organization
|
|
54925
|
+
* or continues the exact one their interrupted journey reached. The preview
|
|
54926
|
+
* reads that recorded Organization's lifecycle only when the requested handle
|
|
54927
|
+
* continues it; a different handle is a new creation, and the recorded
|
|
54928
|
+
* Organization must not block it.
|
|
54929
|
+
*/
|
|
54930
|
+
const organizationPreview = (client, organizationId, recovery, requestedHandle) => organizationId === null ? Effect.gen(function* () {
|
|
54608
54931
|
const organizations = yield* Effect.promise((signal) => client.orgs({ signal })).pipe(Effect.flatMap(resultValue));
|
|
54609
|
-
|
|
54610
|
-
|
|
54932
|
+
const lines = organizations.length === 0 ? ["Existing Organizations: none"] : [`Existing Organizations: ${organizations.length}`, ...organizations.map((organization) => ` ${JSON.stringify(String(organization.id))} ${JSON.stringify(organization.name)}`)];
|
|
54933
|
+
if (recovery === null) return {
|
|
54934
|
+
lines,
|
|
54935
|
+
recovery,
|
|
54936
|
+
recoveryLifecycle: null
|
|
54937
|
+
};
|
|
54938
|
+
const exact = recovery.organizationId;
|
|
54939
|
+
if (exact === null) return {
|
|
54940
|
+
lines: [...lines, `Recovery: a create for handle @${recovery.handle} is prepared on this machine.`],
|
|
54941
|
+
recovery,
|
|
54942
|
+
recoveryLifecycle: null
|
|
54943
|
+
};
|
|
54944
|
+
if (requestedHandle !== recovery.handle) return {
|
|
54945
|
+
lines: [...lines, `Recovery: Organization ${JSON.stringify(String(exact))} (@${recovery.handle}) is recorded on this machine.`],
|
|
54946
|
+
recovery,
|
|
54947
|
+
recoveryLifecycle: null
|
|
54948
|
+
};
|
|
54949
|
+
const lifecycle = yield* Effect.promise((signal) => client.org(exact).getLifecycle({ signal })).pipe(Effect.flatMap(resultValue));
|
|
54950
|
+
yield* requireCurrentAccess(client, exact, lifecycle);
|
|
54951
|
+
return {
|
|
54952
|
+
lines: [
|
|
54953
|
+
...lines,
|
|
54954
|
+
`Recovery: Organization ${JSON.stringify(String(exact))} (@${recovery.handle})`,
|
|
54955
|
+
`Current lifecycle: ${lifecycle.status}`
|
|
54956
|
+
],
|
|
54957
|
+
recovery,
|
|
54958
|
+
recoveryLifecycle: lifecycle
|
|
54959
|
+
};
|
|
54611
54960
|
}) : Effect.gen(function* () {
|
|
54612
|
-
return
|
|
54961
|
+
return {
|
|
54962
|
+
lines: [`Current lifecycle: ${(yield* Effect.promise((signal) => client.org(organizationId).getLifecycle({ signal })).pipe(Effect.flatMap(resultValue))).status}`],
|
|
54963
|
+
recovery,
|
|
54964
|
+
recoveryLifecycle: null
|
|
54965
|
+
};
|
|
54613
54966
|
});
|
|
54614
54967
|
/**
|
|
54968
|
+
* The confirmation question for a create. A matching recovery handle means the
|
|
54969
|
+
* command continues one exact Organization instead of creating another one.
|
|
54970
|
+
*/
|
|
54971
|
+
const createOrganizationQuestion = (handle, preview) => {
|
|
54972
|
+
if (preview.recovery === null || preview.recovery.organizationId === null) return "Create this Organization?";
|
|
54973
|
+
if (preview.recovery.handle !== handle) return "Create this Organization?";
|
|
54974
|
+
return preview.recoveryLifecycle?.status === "ready" ? "Return this ready Organization?" : "Resume this Organization's setup?";
|
|
54975
|
+
};
|
|
54976
|
+
/**
|
|
54615
54977
|
* Settle one exact Organization lifecycle read: poll every second with no
|
|
54616
54978
|
* overlapping read until the lane is ready or failed. The command's own deadline
|
|
54617
54979
|
* bounds this loop together with the write that preceded it.
|
|
@@ -54625,6 +54987,81 @@ const settleOrganizationLifecycle = (read) => Effect.gen(function* () {
|
|
|
54625
54987
|
return lifecycle;
|
|
54626
54988
|
});
|
|
54627
54989
|
/**
|
|
54990
|
+
* Resume the exact durable Organization lane through the SDK recovery owner, then
|
|
54991
|
+
* settle that exact lifecycle. It never creates an Organization and never
|
|
54992
|
+
* resubmits a recorded bootstrap submission.
|
|
54993
|
+
*/
|
|
54994
|
+
const resumeOrganizationSetup = (operation, scoped, deadline) => Effect.gen(function* () {
|
|
54995
|
+
yield* Effect.promise(() => scoped.retrySetup({ signal: deadline.signal })).pipe(Effect.flatMap(resultValue));
|
|
54996
|
+
const lifecycle = yield* settleOrganizationLifecycle(() => scoped.getLifecycle({ signal: deadline.signal }));
|
|
54997
|
+
yield* requireReadyLifecycle(operation, lifecycle);
|
|
54998
|
+
return lifecycle;
|
|
54999
|
+
});
|
|
55000
|
+
/**
|
|
55001
|
+
* A prepared handle owns the next durable Organization for that handle, so a
|
|
55002
|
+
* different handle would create a second Organization and leave the prepared lane
|
|
55003
|
+
* abandoned. The refusal names the exact handle to continue.
|
|
55004
|
+
*/
|
|
55005
|
+
const preparedJourneyRefusal = (handle) => new CliFailure({
|
|
55006
|
+
code: "WRONG_STATE",
|
|
55007
|
+
message: `An Organization creation is already prepared for handle @${handle}. Run capxul org create with the same handle to continue that exact Organization.`,
|
|
55008
|
+
exitCode: 2,
|
|
55009
|
+
outcome: "refused"
|
|
55010
|
+
});
|
|
55011
|
+
/**
|
|
55012
|
+
* Read how this create continues the person's Organization journey.
|
|
55013
|
+
*
|
|
55014
|
+
* The recovery handle is the only source of the exact identity, so a matching
|
|
55015
|
+
* handle resumes the Organization its lane reached and never creates another
|
|
55016
|
+
* one. A different handle creates one Organization only after the recorded
|
|
55017
|
+
* Organization reaches ready.
|
|
55018
|
+
*/
|
|
55019
|
+
const readCreateRoute = (client, recovery, handle, signal) => Effect.gen(function* () {
|
|
55020
|
+
if (recovery === null) return {
|
|
55021
|
+
kind: "create",
|
|
55022
|
+
continuesRecorded: false
|
|
55023
|
+
};
|
|
55024
|
+
if (recovery.organizationId === null) {
|
|
55025
|
+
if (recovery.handle === handle) return {
|
|
55026
|
+
kind: "create",
|
|
55027
|
+
continuesRecorded: true
|
|
55028
|
+
};
|
|
55029
|
+
return yield* Effect.fail(preparedJourneyRefusal(recovery.handle));
|
|
55030
|
+
}
|
|
55031
|
+
const lifecycle = yield* Effect.promise(() => client.org(recovery.organizationId).getLifecycle({ signal })).pipe(Effect.flatMap(resultValue));
|
|
55032
|
+
if (recovery.handle === handle) return {
|
|
55033
|
+
kind: "recover",
|
|
55034
|
+
organizationId: recovery.organizationId,
|
|
55035
|
+
handle: recovery.handle,
|
|
55036
|
+
lifecycle
|
|
55037
|
+
};
|
|
55038
|
+
if (lifecycle.status === "ready") return {
|
|
55039
|
+
kind: "create",
|
|
55040
|
+
continuesRecorded: false
|
|
55041
|
+
};
|
|
55042
|
+
return yield* Effect.fail(Errors.wrongState({
|
|
55043
|
+
method: CAPXUL_OPERATIONS.onboarding.completeOrganization,
|
|
55044
|
+
currentState: lifecycle.status,
|
|
55045
|
+
validStates: ["ready"],
|
|
55046
|
+
organizationId: String(recovery.organizationId)
|
|
55047
|
+
}));
|
|
55048
|
+
});
|
|
55049
|
+
/** One safe recovery line, in the same newline-delimited shape as the lifecycle. */
|
|
55050
|
+
const recoveryNotice = (mode, recovery) => mode === "json" ? `${JSON.stringify({
|
|
55051
|
+
type: "organization.recovery",
|
|
55052
|
+
organizationId: String(recovery.organizationId),
|
|
55053
|
+
handle: recovery.handle
|
|
55054
|
+
})}\n` : `Recovering Organization ${JSON.stringify(String(recovery.organizationId))} (@${recovery.handle}).\n`;
|
|
55055
|
+
/** A taken handle is refused before the backend writes any Organization row. */
|
|
55056
|
+
const refusedOrganizationHandle = (error) => isCapxulError(error) && error.code === "INVALID_INPUT" && error.details?.field === "handle";
|
|
55057
|
+
/** A write forwards no signature before its recovery handle exists; absence is a defect. */
|
|
55058
|
+
const organizationWriteDefect = () => new CliFailure({
|
|
55059
|
+
code: "CLI_DEFECT",
|
|
55060
|
+
message: "The Organization write lost its recovery handle.",
|
|
55061
|
+
exitCode: 1,
|
|
55062
|
+
outcome: "failed"
|
|
55063
|
+
});
|
|
55064
|
+
/**
|
|
54628
55065
|
* The one deadline for a write: it aborts the active SDK signal, so the waiting
|
|
54629
55066
|
* command stops and the signer forwards nothing further, while the durable
|
|
54630
55067
|
* backend lane keeps running and stays resumable by `org retry`.
|
|
@@ -54734,10 +55171,15 @@ const requireReadyLifecycle = (operation, lifecycle) => lifecycle.status === "re
|
|
|
54734
55171
|
* explicit create intent, then settle the exact Organization lifecycle. This
|
|
54735
55172
|
* never saves a read default and never returns an unrelated ready Organization.
|
|
54736
55173
|
*
|
|
55174
|
+
* A create that meets this person's prepared Organization journey continues that
|
|
55175
|
+
* exact Organization: the same handle resumes the lane its ID reached, and a
|
|
55176
|
+
* different handle refuses while that lane is unsettled. Neither path creates a
|
|
55177
|
+
* replacement Organization or treasury.
|
|
55178
|
+
*
|
|
54737
55179
|
* One deadline covers the write and its settlement. At the deadline the active
|
|
54738
55180
|
* SDK signal is aborted: the command stops waiting, forwards no further
|
|
54739
55181
|
* signature, and returns the typed wait failure, while the durable backend lane
|
|
54740
|
-
* keeps running and stays resumable by `org retry`.
|
|
55182
|
+
* keeps running and stays resumable by the same create or by `org retry`.
|
|
54741
55183
|
*/
|
|
54742
55184
|
const createOrganization = (config, input) => Effect.gen(function* () {
|
|
54743
55185
|
const operation = CAPXUL_OPERATIONS.org.create;
|
|
@@ -54747,50 +55189,99 @@ const createOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54747
55189
|
const opened = yield* openAuthenticatedSession(config, input.email);
|
|
54748
55190
|
if (interactivelyConfirm) {
|
|
54749
55191
|
const preview = yield* restoreVerifiedClient(config, opened, { requirement: "none" });
|
|
54750
|
-
const
|
|
55192
|
+
const recovery = yield* readOrganizationRecovery(config, preview.session.authUserId);
|
|
55193
|
+
const resolved = yield* organizationPreview(preview.client, null, recovery, draft.handle);
|
|
54751
55194
|
yield* confirmWrite({
|
|
54752
55195
|
lines: [
|
|
54753
55196
|
`Create Organization ${JSON.stringify(draft.name)} (@${draft.handle}, ${draft.country})`,
|
|
54754
55197
|
...draft.bio === void 0 ? [] : [`Bio: ${JSON.stringify(draft.bio)}`],
|
|
54755
55198
|
...draft.size === void 0 ? [] : [`Size: ${JSON.stringify(draft.size)}`],
|
|
54756
|
-
...resolved
|
|
55199
|
+
...resolved.lines
|
|
54757
55200
|
],
|
|
54758
|
-
question:
|
|
55201
|
+
question: createOrganizationQuestion(draft.handle, resolved)
|
|
54759
55202
|
});
|
|
54760
55203
|
}
|
|
54761
55204
|
const context = yield* Effect.context();
|
|
54762
55205
|
const run = Effect.runPromiseWith(context);
|
|
54763
55206
|
const runtime = yield* CliRuntime;
|
|
54764
|
-
const
|
|
55207
|
+
const progressRef = yield* Ref.make(null);
|
|
54765
55208
|
const deadline = new AbortController();
|
|
54766
55209
|
const openfortSignerFactory = yield* organizationWriteSigner(config, opened, run, async () => {
|
|
54767
55210
|
const cancelled = cancelledWrite(operation, deadline.signal);
|
|
54768
55211
|
if (cancelled !== null) throw cancelled;
|
|
54769
|
-
await
|
|
55212
|
+
const live = await run(Ref.get(progressRef));
|
|
55213
|
+
if (live === null) throw organizationWriteDefect();
|
|
55214
|
+
await live.flush();
|
|
54770
55215
|
const stopped = cancelledWrite(operation, deadline.signal);
|
|
54771
55216
|
if (stopped !== null) throw stopped;
|
|
54772
55217
|
});
|
|
54773
|
-
const { client } = yield* restoreVerifiedClient(config, opened, {
|
|
55218
|
+
const { client, session, stillAuthenticated } = yield* restoreVerifiedClient(config, opened, {
|
|
54774
55219
|
requirement: "deployed",
|
|
54775
55220
|
openfortSignerFactory
|
|
54776
55221
|
});
|
|
54777
|
-
const
|
|
54778
|
-
const
|
|
54779
|
-
const
|
|
54780
|
-
|
|
54781
|
-
|
|
54782
|
-
|
|
55222
|
+
const recovery = yield* openOrganizationRecovery(config, session.authUserId, stillAuthenticated);
|
|
55223
|
+
const persistRecovery = (organizationId) => Effect.gen(function* () {
|
|
55224
|
+
const committed = yield* onboardingOrganizationId(organizationId);
|
|
55225
|
+
yield* recovery.save({
|
|
55226
|
+
handle: draft.handle,
|
|
55227
|
+
organizationId: committed
|
|
55228
|
+
});
|
|
55229
|
+
});
|
|
55230
|
+
const progress = makeOrganizationProgress(runtime.mode, run, (organizationId) => run(persistRecovery(organizationId)));
|
|
55231
|
+
yield* Ref.set(progressRef, progress);
|
|
55232
|
+
const flushProgress = Effect.gen(function* () {
|
|
54783
55233
|
yield* Effect.tryPromise({
|
|
54784
55234
|
try: progress.flush,
|
|
54785
55235
|
catch: (cause) => cause
|
|
54786
55236
|
}).pipe(Effect.catch(() => Effect.void));
|
|
54787
55237
|
const localFailure = progress.failure();
|
|
54788
55238
|
if (localFailure !== null && localFailure !== void 0) return yield* Effect.fail(localFailure);
|
|
54789
|
-
|
|
55239
|
+
});
|
|
55240
|
+
const settled = yield* Effect.gen(function* () {
|
|
55241
|
+
const route = yield* readCreateRoute(client, recovery.current(), draft.handle, deadline.signal);
|
|
55242
|
+
if (route.kind === "recover") {
|
|
55243
|
+
if (route.lifecycle.status === "ready") {
|
|
55244
|
+
yield* requireCurrentAccess(client, route.organizationId, route.lifecycle);
|
|
55245
|
+
progress.allowReady();
|
|
55246
|
+
return {
|
|
55247
|
+
organizationId: route.organizationId,
|
|
55248
|
+
lifecycle: route.lifecycle
|
|
55249
|
+
};
|
|
55250
|
+
}
|
|
55251
|
+
progress.notice(recoveryNotice(runtime.mode, route));
|
|
55252
|
+
yield* flushProgress;
|
|
55253
|
+
const lifecycle = yield* resumeOrganizationSetup(operation, client.org(route.organizationId), deadline);
|
|
55254
|
+
yield* requireCurrentAccess(client, route.organizationId, lifecycle);
|
|
55255
|
+
progress.allowReady();
|
|
55256
|
+
return {
|
|
55257
|
+
organizationId: route.organizationId,
|
|
55258
|
+
lifecycle
|
|
55259
|
+
};
|
|
55260
|
+
}
|
|
55261
|
+
yield* recovery.save({
|
|
55262
|
+
handle: draft.handle,
|
|
55263
|
+
organizationId: null
|
|
55264
|
+
});
|
|
55265
|
+
const unsubscribe = client.onboarding.subscribeOrganization(progress.observe);
|
|
55266
|
+
const completed = yield* Effect.promise(() => client.onboarding.completeOrganization(draft, {
|
|
55267
|
+
intent: "create",
|
|
55268
|
+
signal: deadline.signal
|
|
55269
|
+
})).pipe(Effect.ensuring(Effect.sync(unsubscribe)));
|
|
55270
|
+
if (!completed.ok) {
|
|
55271
|
+
yield* flushProgress;
|
|
55272
|
+
if (refusedOrganizationHandle(completed.error) && progress.committed() === null) yield* recovery.release();
|
|
55273
|
+
return yield* Effect.fail(completed.error);
|
|
55274
|
+
}
|
|
55275
|
+
const onboarding = completed.value;
|
|
54790
55276
|
const organizationId = yield* onboardingOrganizationId(onboarding.organizationId);
|
|
55277
|
+
progress.commit(String(organizationId));
|
|
55278
|
+
yield* flushProgress;
|
|
54791
55279
|
const scoped = client.org(organizationId);
|
|
54792
55280
|
const lifecycle = yield* settleOrganizationLifecycle(() => scoped.getLifecycle({ signal: deadline.signal }));
|
|
54793
55281
|
yield* requireReadyLifecycle(operation, lifecycle);
|
|
55282
|
+
if (route.continuesRecorded) yield* requireCurrentAccess(client, organizationId, lifecycle);
|
|
55283
|
+
progress.allowReady();
|
|
55284
|
+
yield* flushProgress;
|
|
54794
55285
|
return {
|
|
54795
55286
|
organizationId,
|
|
54796
55287
|
lifecycle
|
|
@@ -54835,9 +55326,9 @@ const retryOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54835
55326
|
const opened = yield* openAuthenticatedSession(config, input.email);
|
|
54836
55327
|
if (interactivelyConfirm) {
|
|
54837
55328
|
const preview = yield* restoreVerifiedClient(config, opened, { requirement: "none" });
|
|
54838
|
-
const resolved = yield*
|
|
55329
|
+
const resolved = yield* organizationPreview(preview.client, organizationId, null);
|
|
54839
55330
|
yield* confirmWrite({
|
|
54840
|
-
lines: [`Resume setup for Organization ${JSON.stringify(String(organizationId))}`, ...resolved],
|
|
55331
|
+
lines: [`Resume setup for Organization ${JSON.stringify(String(organizationId))}`, ...resolved.lines],
|
|
54841
55332
|
question: "Resume this Organization's setup?"
|
|
54842
55333
|
});
|
|
54843
55334
|
}
|
|
@@ -54853,12 +55344,7 @@ const retryOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54853
55344
|
openfortSignerFactory
|
|
54854
55345
|
});
|
|
54855
55346
|
const scoped = client.org(organizationId);
|
|
54856
|
-
const settled = yield* Effect.
|
|
54857
|
-
yield* Effect.promise(() => scoped.retrySetup({ signal: deadline.signal })).pipe(Effect.flatMap(resultValue));
|
|
54858
|
-
const lifecycle = yield* settleOrganizationLifecycle(() => scoped.getLifecycle({ signal: deadline.signal }));
|
|
54859
|
-
yield* requireReadyLifecycle(operation, lifecycle);
|
|
54860
|
-
return lifecycle;
|
|
54861
|
-
}).pipe(Effect.onInterrupt(() => Effect.sync(() => deadline.abort()))).pipe(Effect.timeoutOption(timeout * 1e3));
|
|
55347
|
+
const settled = yield* resumeOrganizationSetup(operation, scoped, deadline).pipe(Effect.onInterrupt(() => Effect.sync(() => deadline.abort()))).pipe(Effect.timeoutOption(timeout * 1e3));
|
|
54862
55348
|
if (Option.isNone(settled)) return yield* Effect.fail(organizationWaitTimeout());
|
|
54863
55349
|
return {
|
|
54864
55350
|
data: {
|
|
@@ -55926,7 +56412,7 @@ const create = Command.make("create", {
|
|
|
55926
56412
|
size: Option.getOrUndefined(size),
|
|
55927
56413
|
confirm,
|
|
55928
56414
|
timeoutSeconds
|
|
55929
|
-
}))).pipe(Command.annotate(CliCommandMetadata, metadata(CAPXUL_OPERATIONS.org.create)), Command.withDescription("Create one Organization
|
|
56415
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata(CAPXUL_OPERATIONS.org.create)), Command.withDescription("Create one Organization, or resume the exact one this machine recorded"));
|
|
55930
56416
|
const retry = Command.make("retry", {
|
|
55931
56417
|
...orgScope,
|
|
55932
56418
|
email: emailFlag,
|
|
@@ -55941,7 +56427,7 @@ const retry = Command.make("retry", {
|
|
|
55941
56427
|
confirm,
|
|
55942
56428
|
timeoutSeconds
|
|
55943
56429
|
}))).pipe(Command.annotate(CliCommandMetadata, metadata(CAPXUL_OPERATIONS.org.retry)), Command.withDescription("Resume this exact Organization setup lane; never creates one"));
|
|
55944
|
-
const org = Command.make("org").pipe(Command.annotate(CliCommandMetadata, metadata("org")), Command.withDescription("Organization reads, writes, and local read defaults"), Command.withSubcommands([
|
|
56430
|
+
const org = Command.make("org").pipe(Command.annotate(CliCommandMetadata, metadata("org")), Command.withDescription("Organization reads, writes, recovery, and local read defaults"), Command.withSubcommands([
|
|
55945
56431
|
list,
|
|
55946
56432
|
use,
|
|
55947
56433
|
status,
|
|
@@ -56103,6 +56589,7 @@ const runCli = (platform) => Effect.uninterruptibleMask((restore) => Effect.gen(
|
|
|
56103
56589
|
const ci = yield* Config.string("CI").pipe(Config.withDefault("false"), Effect.map((value) => value !== "" && value !== "false" && value !== "0"), Effect.catch(() => Effect.succeed(false)));
|
|
56104
56590
|
const runtime = {
|
|
56105
56591
|
mode,
|
|
56592
|
+
args,
|
|
56106
56593
|
current,
|
|
56107
56594
|
invocationId,
|
|
56108
56595
|
observation,
|