@keystrokehq/cli 0.0.134 → 0.0.137
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/index.mjs +66 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2105,7 +2105,6 @@ const UserOrganizationSchema = object({
|
|
|
2105
2105
|
});
|
|
2106
2106
|
const ActiveOrganizationResponseSchema = object({ organization: UserOrganizationSchema.nullable() });
|
|
2107
2107
|
const ListOrganizationsResponseSchema = object({ organizations: array(UserOrganizationSchema) });
|
|
2108
|
-
const SetActiveOrganizationRequestSchema = object({ organizationId: string().min(1) });
|
|
2109
2108
|
const CreateOrganizationRequestSchema = object({
|
|
2110
2109
|
name: string().trim().min(1),
|
|
2111
2110
|
/** Format-only at the wire boundary; reserved-name checks run in platform-database. */
|
|
@@ -4782,9 +4781,11 @@ async function runDeviceLogin(options) {
|
|
|
4782
4781
|
});
|
|
4783
4782
|
if (!tokenResult.error) {
|
|
4784
4783
|
const token = tokenResult.data;
|
|
4784
|
+
const organizationId = token.scope?.trim();
|
|
4785
4785
|
return {
|
|
4786
4786
|
accessToken: token.access_token,
|
|
4787
|
-
expiresIn: token.expires_in
|
|
4787
|
+
expiresIn: token.expires_in,
|
|
4788
|
+
organizationId: organizationId || void 0
|
|
4788
4789
|
};
|
|
4789
4790
|
}
|
|
4790
4791
|
const errorPayload = tokenResult.error;
|
|
@@ -5071,10 +5072,22 @@ function createHealthResource(http) {
|
|
|
5071
5072
|
} };
|
|
5072
5073
|
}
|
|
5073
5074
|
function createOrganizationsResource(http, options = {}) {
|
|
5075
|
+
async function get(organizationId) {
|
|
5076
|
+
try {
|
|
5077
|
+
const data = await http.get(`/api/organizations/${organizationId}`).json();
|
|
5078
|
+
const organization = ActiveOrganizationResponseSchema.parse(data).organization;
|
|
5079
|
+
if (!organization) throw new Error("Organization was not returned");
|
|
5080
|
+
return organization;
|
|
5081
|
+
} catch (error) {
|
|
5082
|
+
throw await toPlatformError(error);
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5074
5085
|
async function update(input) {
|
|
5075
5086
|
const body = UpdateOrganizationRequestSchema.parse(input);
|
|
5087
|
+
const organizationId = options.getActiveOrganizationId?.();
|
|
5088
|
+
if (!organizationId) throw new Error("No active organization");
|
|
5076
5089
|
try {
|
|
5077
|
-
const data = await http.patch(
|
|
5090
|
+
const data = await http.patch(`/api/organizations/${organizationId}`, { json: body }).json();
|
|
5078
5091
|
const organization = ActiveOrganizationResponseSchema.parse(data).organization;
|
|
5079
5092
|
if (!organization) throw new Error("Active organization was not returned");
|
|
5080
5093
|
return organization;
|
|
@@ -5091,34 +5104,27 @@ function createOrganizationsResource(http, options = {}) {
|
|
|
5091
5104
|
throw await toPlatformError(error);
|
|
5092
5105
|
}
|
|
5093
5106
|
},
|
|
5107
|
+
get,
|
|
5094
5108
|
async getActive() {
|
|
5109
|
+
const organizationId = options.getActiveOrganizationId?.();
|
|
5110
|
+
if (!organizationId) return null;
|
|
5095
5111
|
try {
|
|
5096
|
-
|
|
5097
|
-
return ActiveOrganizationResponseSchema.parse(data).organization;
|
|
5112
|
+
return await get(organizationId);
|
|
5098
5113
|
} catch (error) {
|
|
5099
|
-
if (
|
|
5100
|
-
|
|
5114
|
+
if (error instanceof PlatformError && (error.status === 401 || error.status === 403)) return null;
|
|
5115
|
+
if (isHTTPError(error) && (error.response.status === 401 || error.response.status === 403)) return null;
|
|
5116
|
+
throw error instanceof PlatformError ? error : await toPlatformError(error);
|
|
5101
5117
|
}
|
|
5102
5118
|
},
|
|
5103
5119
|
async setActive(input) {
|
|
5104
|
-
const
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
options.onActiveOrganizationChange?.(organization.organization.id);
|
|
5110
|
-
return organization;
|
|
5111
|
-
} catch (error) {
|
|
5112
|
-
throw await toPlatformError(error);
|
|
5113
|
-
}
|
|
5120
|
+
const organizationId = input.organizationId.trim();
|
|
5121
|
+
if (!organizationId) throw new Error("Organization id is required");
|
|
5122
|
+
const membership = await get(organizationId);
|
|
5123
|
+
options.onActiveOrganizationChange?.(organizationId);
|
|
5124
|
+
return membership;
|
|
5114
5125
|
},
|
|
5115
5126
|
async clearActive() {
|
|
5116
|
-
|
|
5117
|
-
await http.delete("/api/organizations/active");
|
|
5118
|
-
options.onActiveOrganizationChange?.(null);
|
|
5119
|
-
} catch (error) {
|
|
5120
|
-
throw await toPlatformError(error);
|
|
5121
|
-
}
|
|
5127
|
+
options.onActiveOrganizationChange?.(null);
|
|
5122
5128
|
},
|
|
5123
5129
|
update,
|
|
5124
5130
|
async create(input) {
|
|
@@ -5130,9 +5136,9 @@ function createOrganizationsResource(http, options = {}) {
|
|
|
5130
5136
|
throw await toPlatformError(error);
|
|
5131
5137
|
}
|
|
5132
5138
|
},
|
|
5133
|
-
async checkSlug(slug,
|
|
5139
|
+
async checkSlug(slug, slugOptions = {}) {
|
|
5134
5140
|
const searchParams = new URLSearchParams({ slug });
|
|
5135
|
-
if (
|
|
5141
|
+
if (slugOptions.excludeOrganizationId) searchParams.set("excludeOrganizationId", slugOptions.excludeOrganizationId);
|
|
5136
5142
|
try {
|
|
5137
5143
|
const data = await http.get(`/api/organizations/slug-available?${searchParams}`).json();
|
|
5138
5144
|
return SlugAvailabilityResponseSchema.parse(data);
|
|
@@ -7740,19 +7746,24 @@ async function presignPutAndFinalize(input) {
|
|
|
7740
7746
|
throw await input.toPlatformError(error);
|
|
7741
7747
|
}
|
|
7742
7748
|
}
|
|
7743
|
-
function createOrganizationSidebarBrandingResource(http) {
|
|
7749
|
+
function createOrganizationSidebarBrandingResource(http, options = {}) {
|
|
7750
|
+
function brandingPath() {
|
|
7751
|
+
const organizationId = options.getActiveOrganizationId?.();
|
|
7752
|
+
if (!organizationId) throw new Error("No active organization");
|
|
7753
|
+
return `/api/organizations/${organizationId}/branding`;
|
|
7754
|
+
}
|
|
7744
7755
|
async function presignLogoUpload(variant, contentType) {
|
|
7745
7756
|
const body = PresignOrgLogoRequestSchema.parse({
|
|
7746
7757
|
variant,
|
|
7747
7758
|
contentType
|
|
7748
7759
|
});
|
|
7749
|
-
const data = await http.post(
|
|
7760
|
+
const data = await http.post(`${brandingPath()}/logo/presign`, { json: body }).json();
|
|
7750
7761
|
return PresignOrgLogoResponseSchema.parse(data);
|
|
7751
7762
|
}
|
|
7752
7763
|
return {
|
|
7753
7764
|
async get() {
|
|
7754
7765
|
try {
|
|
7755
|
-
const data = await http.get(
|
|
7766
|
+
const data = await http.get(brandingPath()).json();
|
|
7756
7767
|
return OrganizationSidebarBrandingSchema.parse(data);
|
|
7757
7768
|
} catch (error) {
|
|
7758
7769
|
throw await toPlatformError(error);
|
|
@@ -7779,7 +7790,7 @@ function createOrganizationSidebarBrandingResource(http) {
|
|
|
7779
7790
|
async update(patch) {
|
|
7780
7791
|
const body = OrganizationSidebarBrandingPatchSchema.parse(patch);
|
|
7781
7792
|
try {
|
|
7782
|
-
const data = await http.patch(
|
|
7793
|
+
const data = await http.patch(brandingPath(), { json: body }).json();
|
|
7783
7794
|
return OrganizationSidebarBrandingSchema.parse(data);
|
|
7784
7795
|
} catch (error) {
|
|
7785
7796
|
throw await toPlatformError(error);
|
|
@@ -8596,7 +8607,7 @@ function createPlatformClient(options) {
|
|
|
8596
8607
|
recents: createRecentsResource(http),
|
|
8597
8608
|
userPreferences: createUserPreferencesResource({ getCurrentUserId: options.getCurrentUserId }),
|
|
8598
8609
|
userAvatar: createUserAvatarResource(http),
|
|
8599
|
-
organizationSidebarBranding: createOrganizationSidebarBrandingResource(http),
|
|
8610
|
+
organizationSidebarBranding: createOrganizationSidebarBrandingResource(http, { getActiveOrganizationId: () => activeOrganizationId }),
|
|
8600
8611
|
getActiveOrganizationId: () => activeOrganizationId,
|
|
8601
8612
|
setActiveOrganizationId
|
|
8602
8613
|
};
|
|
@@ -8665,6 +8676,15 @@ async function activateOrganization(config, organizationId) {
|
|
|
8665
8676
|
platform.setActiveOrganizationId(membership.organization.id);
|
|
8666
8677
|
return membership;
|
|
8667
8678
|
}
|
|
8679
|
+
function resolveOrganizationIdForLogin(organizations, options = {}) {
|
|
8680
|
+
if (options.organizationRef ?? options.organizationId) return resolveOrganizationRef(organizations, options.organizationRef ?? options.organizationId).organization.id;
|
|
8681
|
+
for (const candidateId of [options.deviceOrganizationId, options.storedOrganizationId]) {
|
|
8682
|
+
const organizationId = candidateId?.trim();
|
|
8683
|
+
if (organizationId && organizations.some((entry) => entry.organization.id === organizationId)) return organizationId;
|
|
8684
|
+
}
|
|
8685
|
+
if (organizations.length === 1) return organizations[0].organization.id;
|
|
8686
|
+
return [...organizations].sort((left, right) => left.organization.slug.localeCompare(right.organization.slug))[0].organization.id;
|
|
8687
|
+
}
|
|
8668
8688
|
async function pickOrganization(config, organizations, organizationRef) {
|
|
8669
8689
|
if (organizationRef) return activateOrganization(config, resolveOrganizationRef(organizations, organizationRef).organization.id);
|
|
8670
8690
|
if (!process.stdin.isTTY) {
|
|
@@ -8688,33 +8708,21 @@ async function selectActiveOrganization(config, options = {}) {
|
|
|
8688
8708
|
async function syncActiveOrganizationAfterLogin(config, options = {}) {
|
|
8689
8709
|
const organizations = await listOrganizations(config);
|
|
8690
8710
|
if (organizations.length === 0) throw new Error(`No organization found — create one at ${getWebUrl(config)}`);
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
}
|
|
8697
|
-
if (organizations.length === 1) {
|
|
8698
|
-
const membership = await activateOrganization(config, organizations[0].organization.id);
|
|
8699
|
-
process.stdout.write(`Using organization ${membership.organization.name}\n`);
|
|
8700
|
-
return membership;
|
|
8701
|
-
}
|
|
8702
|
-
if (options.organizationRef ?? options.organizationId) {
|
|
8703
|
-
const membership = await pickOrganization(config, organizations, options.organizationRef ?? options.organizationId);
|
|
8704
|
-
process.stdout.write(`Using organization ${membership.organization.name}\n`);
|
|
8705
|
-
return membership;
|
|
8706
|
-
}
|
|
8707
|
-
const membership = await pickOrganization(config, organizations);
|
|
8708
|
-
process.stdout.write(`Using organization ${membership.organization.name}\n`);
|
|
8709
|
-
return membership;
|
|
8711
|
+
return activateOrganization(config, resolveOrganizationIdForLogin(organizations, {
|
|
8712
|
+
organizationRef: options.organizationRef,
|
|
8713
|
+
organizationId: options.organizationId,
|
|
8714
|
+
deviceOrganizationId: options.deviceOrganizationId,
|
|
8715
|
+
storedOrganizationId: config.get("activeOrganizationId")
|
|
8716
|
+
}));
|
|
8710
8717
|
}
|
|
8711
8718
|
async function ensureActiveOrganization(config) {
|
|
8719
|
+
const organizations = await listOrganizations(config);
|
|
8720
|
+
if (organizations.length === 0) throw new Error("No organization found. Run `keystroke auth login` after creating one in the dashboard.");
|
|
8712
8721
|
const storedId = config.get("activeOrganizationId");
|
|
8713
|
-
if (storedId) {
|
|
8722
|
+
if (storedId && organizations.some((entry) => entry.organization.id === storedId)) {
|
|
8714
8723
|
await activateOrganization(config, storedId);
|
|
8715
8724
|
return;
|
|
8716
8725
|
}
|
|
8717
|
-
const organizations = await listOrganizations(config);
|
|
8718
8726
|
if (organizations.length === 1) {
|
|
8719
8727
|
await activateOrganization(config, organizations[0].organization.id);
|
|
8720
8728
|
return;
|
|
@@ -9290,7 +9298,7 @@ function resolveAuthLoginTargets(options, config) {
|
|
|
9290
9298
|
//#endregion
|
|
9291
9299
|
//#region src/commands/auth/login.ts
|
|
9292
9300
|
function registerAuthLoginCommand(auth) {
|
|
9293
|
-
auth.command("login").description("Authenticate via browser device flow").option("--web-url <url>", "Web dashboard origin (omit to use production defaults; local dev: http://localhost:3000)").option("--platform-url <url>", "Platform API origin (derived from web URL when omitted)").option("--org <slug>", "Active organization slug (
|
|
9301
|
+
auth.command("login").description("Authenticate via browser device flow").option("--web-url <url>", "Web dashboard origin (omit to use production defaults; local dev: http://localhost:3000)").option("--platform-url <url>", "Platform API origin (derived from web URL when omitted)").option("--org <slug>", "Active organization slug (overrides browser default)").action(async (options) => {
|
|
9294
9302
|
const config = createCliConfig();
|
|
9295
9303
|
const { webUrl, platformUrl } = resolveAuthLoginTargets(options, config);
|
|
9296
9304
|
config.set("webUrl", webUrl);
|
|
@@ -9303,9 +9311,12 @@ function registerAuthLoginCommand(auth) {
|
|
|
9303
9311
|
});
|
|
9304
9312
|
setAccessToken(platformUrl, result.accessToken);
|
|
9305
9313
|
const user = await getSessionWithBearer(platformUrl, result.accessToken);
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9314
|
+
const membership = await syncActiveOrganizationAfterLogin(config, {
|
|
9315
|
+
organizationRef: options.org,
|
|
9316
|
+
deviceOrganizationId: result.organizationId
|
|
9317
|
+
});
|
|
9318
|
+
if (user) process.stdout.write(`Logged in as ${user.name} (${user.email}) — organization ${membership.organization.name}\n`);
|
|
9319
|
+
else process.stdout.write(`Logged in to ${webUrl} — organization ${membership.organization.name}\n`);
|
|
9309
9320
|
} catch (error) {
|
|
9310
9321
|
process.stderr.write(`${formatCliError(error, "Login failed", {
|
|
9311
9322
|
webUrl,
|