@keystrokehq/hosting 0.1.8 → 0.1.10
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.cjs +149 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +40 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +148 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,10 @@ const PROJECT_SERVER_HEALTH = {
|
|
|
34
34
|
path: "/health",
|
|
35
35
|
port: PROJECT_SERVER_PORT
|
|
36
36
|
};
|
|
37
|
+
const PROJECT_SERVER_DEPLOY_STATUS = {
|
|
38
|
+
path: "/deploy-status",
|
|
39
|
+
port: PROJECT_SERVER_PORT
|
|
40
|
+
};
|
|
37
41
|
//#endregion
|
|
38
42
|
//#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
39
43
|
var _a$1;
|
|
@@ -641,6 +645,7 @@ const string$1 = (params) => {
|
|
|
641
645
|
const integer = /^-?\d+$/;
|
|
642
646
|
const number$2 = /^-?\d+(?:\.\d+)?$/;
|
|
643
647
|
const boolean$1 = /^(?:true|false)$/i;
|
|
648
|
+
const _null$2 = /^null$/i;
|
|
644
649
|
const lowercase = /^[^A-Z]*$/;
|
|
645
650
|
const uppercase = /^[^a-z]*$/;
|
|
646
651
|
//#endregion
|
|
@@ -1453,6 +1458,22 @@ const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
|
|
|
1453
1458
|
return payload;
|
|
1454
1459
|
};
|
|
1455
1460
|
});
|
|
1461
|
+
const $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
|
|
1462
|
+
$ZodType.init(inst, def);
|
|
1463
|
+
inst._zod.pattern = _null$2;
|
|
1464
|
+
inst._zod.values = new Set([null]);
|
|
1465
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
1466
|
+
const input = payload.value;
|
|
1467
|
+
if (input === null) return payload;
|
|
1468
|
+
payload.issues.push({
|
|
1469
|
+
expected: "null",
|
|
1470
|
+
code: "invalid_type",
|
|
1471
|
+
input,
|
|
1472
|
+
inst
|
|
1473
|
+
});
|
|
1474
|
+
return payload;
|
|
1475
|
+
};
|
|
1476
|
+
});
|
|
1456
1477
|
const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
|
|
1457
1478
|
$ZodType.init(inst, def);
|
|
1458
1479
|
inst._zod.parse = (payload) => payload;
|
|
@@ -2699,6 +2720,13 @@ function _boolean(Class, params) {
|
|
|
2699
2720
|
});
|
|
2700
2721
|
}
|
|
2701
2722
|
/* @__NO_SIDE_EFFECTS__ */
|
|
2723
|
+
function _null$1(Class, params) {
|
|
2724
|
+
return new Class({
|
|
2725
|
+
type: "null",
|
|
2726
|
+
...normalizeParams(params)
|
|
2727
|
+
});
|
|
2728
|
+
}
|
|
2729
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
2702
2730
|
function _unknown(Class) {
|
|
2703
2731
|
return new Class({ type: "unknown" });
|
|
2704
2732
|
}
|
|
@@ -3247,6 +3275,13 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
3247
3275
|
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
3248
3276
|
json.type = "boolean";
|
|
3249
3277
|
};
|
|
3278
|
+
const nullProcessor = (_schema, ctx, json, _params) => {
|
|
3279
|
+
if (ctx.target === "openapi-3.0") {
|
|
3280
|
+
json.type = "string";
|
|
3281
|
+
json.nullable = true;
|
|
3282
|
+
json.enum = [null];
|
|
3283
|
+
} else json.type = "null";
|
|
3284
|
+
};
|
|
3250
3285
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
3251
3286
|
json.not = {};
|
|
3252
3287
|
};
|
|
@@ -3946,6 +3981,14 @@ const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
|
|
|
3946
3981
|
function boolean(params) {
|
|
3947
3982
|
return /* @__PURE__ */ _boolean(ZodBoolean, params);
|
|
3948
3983
|
}
|
|
3984
|
+
const ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
|
|
3985
|
+
$ZodNull.init(inst, def);
|
|
3986
|
+
ZodType.init(inst, def);
|
|
3987
|
+
inst._zod.processJSONSchema = (ctx, json, params) => nullProcessor(inst, ctx, json, params);
|
|
3988
|
+
});
|
|
3989
|
+
function _null(params) {
|
|
3990
|
+
return /* @__PURE__ */ _null$1(ZodNull, params);
|
|
3991
|
+
}
|
|
3949
3992
|
const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
|
|
3950
3993
|
$ZodUnknown.init(inst, def);
|
|
3951
3994
|
ZodType.init(inst, def);
|
|
@@ -5780,6 +5823,8 @@ const nullableOptionalTimestamp = string().nullable().optional();
|
|
|
5780
5823
|
object({
|
|
5781
5824
|
id: string().min(1),
|
|
5782
5825
|
appId: string().min(1),
|
|
5826
|
+
/** Stable per-scope identifier; pass to `--credential` to pin a specific instance. */
|
|
5827
|
+
slug: string().min(1),
|
|
5783
5828
|
label: string().min(1),
|
|
5784
5829
|
scope: AppCredentialScopeSchema,
|
|
5785
5830
|
lastRefreshedAt: string().nullable(),
|
|
@@ -5936,7 +5981,11 @@ object({
|
|
|
5936
5981
|
/** When set, platform MCP resolve checks credential assignments before scope defaults. */
|
|
5937
5982
|
assignmentTarget: McpCredentialAssignmentTargetSchema.optional(),
|
|
5938
5983
|
/** Tool/step consumer id for assignment lookup (action slug or workflow step correlation id). */
|
|
5939
|
-
consumerId: string().trim().min(1).optional()
|
|
5984
|
+
consumerId: string().trim().min(1).optional(),
|
|
5985
|
+
/** Explicit credential instance slug; overrides default resolution to pick that instance. */
|
|
5986
|
+
credentialSlug: string().trim().min(1).optional(),
|
|
5987
|
+
/** Project slug (CLI --project); the platform resolves it to a project and binds that scope. */
|
|
5988
|
+
projectSlug: string().trim().min(1).optional()
|
|
5940
5989
|
});
|
|
5941
5990
|
object({
|
|
5942
5991
|
error: _enum([
|
|
@@ -6937,6 +6986,14 @@ object({
|
|
|
6937
6986
|
uploadUrl: url(),
|
|
6938
6987
|
storageKey: string().min(1)
|
|
6939
6988
|
});
|
|
6989
|
+
function isValidIanaTimezone(value) {
|
|
6990
|
+
try {
|
|
6991
|
+
Intl.DateTimeFormat(void 0, { timeZone: value });
|
|
6992
|
+
return true;
|
|
6993
|
+
} catch {
|
|
6994
|
+
return false;
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6940
6997
|
const UserInterfaceThemeSchema = _enum([
|
|
6941
6998
|
"system",
|
|
6942
6999
|
"light",
|
|
@@ -6956,22 +7013,25 @@ const UserWorkspaceFavoriteSchema = object({
|
|
|
6956
7013
|
]),
|
|
6957
7014
|
resourceId: string().min(1)
|
|
6958
7015
|
});
|
|
7016
|
+
const UserSidebarPreferencesSchema = object({
|
|
7017
|
+
navIconVisibility: UserSidebarNavIconVisibilitySchema,
|
|
7018
|
+
footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
|
|
7019
|
+
hiddenNavItemIds: array(string()),
|
|
7020
|
+
topNavItemOrderIds: array(string()),
|
|
7021
|
+
workspaceNavItemOrderIds: array(string())
|
|
7022
|
+
});
|
|
7023
|
+
const UserTimezoneSchema = string().refine(isValidIanaTimezone, { message: "Invalid IANA timezone" });
|
|
6959
7024
|
object({
|
|
6960
7025
|
interfaceTheme: UserInterfaceThemeSchema,
|
|
6961
7026
|
surfaceContrast: UserSurfaceContrastSchema,
|
|
6962
7027
|
layoutMode: UserWorkspaceLayoutModeSchema,
|
|
6963
7028
|
fontSize: UserWorkspaceFontSizeSchema,
|
|
6964
|
-
sidebar:
|
|
6965
|
-
navIconVisibility: UserSidebarNavIconVisibilitySchema,
|
|
6966
|
-
footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
|
|
6967
|
-
hiddenNavItemIds: array(string()),
|
|
6968
|
-
topNavItemOrderIds: array(string()),
|
|
6969
|
-
workspaceNavItemOrderIds: array(string())
|
|
6970
|
-
}),
|
|
7029
|
+
sidebar: UserSidebarPreferencesSchema,
|
|
6971
7030
|
favorites: array(UserWorkspaceFavoriteSchema),
|
|
6972
7031
|
projectOrderIds: array(string()),
|
|
6973
7032
|
projectDotColors: record(string(), string()),
|
|
6974
|
-
onboardingTabVisible: boolean()
|
|
7033
|
+
onboardingTabVisible: boolean(),
|
|
7034
|
+
timezone: union([UserTimezoneSchema, _null()])
|
|
6975
7035
|
});
|
|
6976
7036
|
const UserSidebarPreferencesPatchSchema = object({
|
|
6977
7037
|
navIconVisibility: UserSidebarNavIconVisibilitySchema.optional(),
|
|
@@ -6989,8 +7049,9 @@ object({
|
|
|
6989
7049
|
favorites: array(UserWorkspaceFavoriteSchema).optional(),
|
|
6990
7050
|
projectOrderIds: array(string()).optional(),
|
|
6991
7051
|
projectDotColors: record(string(), string()).optional(),
|
|
6992
|
-
onboardingTabVisible: boolean().optional()
|
|
6993
|
-
|
|
7052
|
+
onboardingTabVisible: boolean().optional(),
|
|
7053
|
+
timezone: union([UserTimezoneSchema, _null()]).optional()
|
|
7054
|
+
}).refine((value) => value.interfaceTheme !== void 0 || value.surfaceContrast !== void 0 || value.layoutMode !== void 0 || value.fontSize !== void 0 || value.sidebar !== void 0 || value.favorites !== void 0 || value.projectOrderIds !== void 0 || value.projectDotColors !== void 0 || value.onboardingTabVisible !== void 0 || value.timezone !== void 0, { message: "At least one preference field is required" });
|
|
6994
7055
|
const OrganizationLogoVariantSchema = _enum(["light", "dark"]);
|
|
6995
7056
|
object({
|
|
6996
7057
|
customLogoEnabled: boolean(),
|
|
@@ -7619,55 +7680,63 @@ function sleep(ms) {
|
|
|
7619
7680
|
const MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? "keystroke";
|
|
7620
7681
|
function createDockerRuntime(options = {}) {
|
|
7621
7682
|
const docker = options.docker ?? new dockerode.default();
|
|
7622
|
-
return {
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7683
|
+
return {
|
|
7684
|
+
async start(input) {
|
|
7685
|
+
if (input.projects.length === 0) throw new Error("Docker org runtime requires at least one project deploy");
|
|
7686
|
+
let launch = resolveRuntimeLaunch(options, input.projects.map((project) => ({
|
|
7687
|
+
projectId: project.projectId,
|
|
7688
|
+
artifactStorageKey: project.artifactStorageKey
|
|
7689
|
+
})), input.database, input.env);
|
|
7690
|
+
if (options.workspacesMount) {
|
|
7691
|
+
const { hostPath, containerPath } = options.workspacesMount;
|
|
7692
|
+
await (0, node_fs_promises.mkdir)(hostPath, { recursive: true });
|
|
7693
|
+
launch = {
|
|
7694
|
+
...launch,
|
|
7695
|
+
env: {
|
|
7696
|
+
...launch.env,
|
|
7697
|
+
KEYSTROKE_WORKSPACES_ROOT: containerPath
|
|
7698
|
+
}
|
|
7699
|
+
};
|
|
7700
|
+
}
|
|
7701
|
+
await ensureImage(docker, launch.image);
|
|
7702
|
+
await removeExistingContainer(docker, input.organizationId);
|
|
7703
|
+
const binds = [...options.workspacesMount ? [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] : [], ...options.extraBinds ?? []];
|
|
7704
|
+
const container = await docker.createContainer({
|
|
7705
|
+
Image: launch.image,
|
|
7706
|
+
name: containerName(input.organizationId),
|
|
7707
|
+
Labels: {
|
|
7708
|
+
"keystroke.organization.id": input.organizationId,
|
|
7709
|
+
"keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
|
|
7710
|
+
},
|
|
7711
|
+
ExposedPorts: { [`${launch.port}/tcp`]: {} },
|
|
7712
|
+
HostConfig: {
|
|
7713
|
+
ExtraHosts: ["host.docker.internal:host-gateway"],
|
|
7714
|
+
PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
|
|
7715
|
+
...binds.length > 0 ? { Binds: binds } : {}
|
|
7716
|
+
},
|
|
7717
|
+
NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
|
|
7718
|
+
Env: formatDockerEnv(launch.env)
|
|
7719
|
+
});
|
|
7720
|
+
await container.start();
|
|
7721
|
+
const inspect = await container.inspect();
|
|
7722
|
+
const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
|
|
7723
|
+
if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
|
|
7724
|
+
const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
|
|
7725
|
+
await waitForHealth(baseUrl, {
|
|
7726
|
+
fetchImpl: options.fetchImpl,
|
|
7727
|
+
timeoutMs: options.healthTimeoutMs
|
|
7728
|
+
});
|
|
7729
|
+
return {
|
|
7730
|
+
runtimeId: inspect.Id,
|
|
7731
|
+
baseUrl
|
|
7637
7732
|
};
|
|
7733
|
+
},
|
|
7734
|
+
async destroy(input) {
|
|
7735
|
+
try {
|
|
7736
|
+
await docker.getContainer(input.runtimeId).remove({ force: true });
|
|
7737
|
+
} catch {}
|
|
7638
7738
|
}
|
|
7639
|
-
|
|
7640
|
-
await removeExistingContainer(docker, input.organizationId);
|
|
7641
|
-
const container = await docker.createContainer({
|
|
7642
|
-
Image: launch.image,
|
|
7643
|
-
name: containerName(input.organizationId),
|
|
7644
|
-
Labels: {
|
|
7645
|
-
"keystroke.organization.id": input.organizationId,
|
|
7646
|
-
"keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
|
|
7647
|
-
},
|
|
7648
|
-
ExposedPorts: { [`${launch.port}/tcp`]: {} },
|
|
7649
|
-
HostConfig: {
|
|
7650
|
-
ExtraHosts: ["host.docker.internal:host-gateway"],
|
|
7651
|
-
PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
|
|
7652
|
-
...options.workspacesMount ? { Binds: [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] } : {}
|
|
7653
|
-
},
|
|
7654
|
-
NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
|
|
7655
|
-
Env: formatDockerEnv(launch.env)
|
|
7656
|
-
});
|
|
7657
|
-
await container.start();
|
|
7658
|
-
const inspect = await container.inspect();
|
|
7659
|
-
const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
|
|
7660
|
-
if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
|
|
7661
|
-
const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
|
|
7662
|
-
await waitForHealth(baseUrl, {
|
|
7663
|
-
fetchImpl: options.fetchImpl,
|
|
7664
|
-
timeoutMs: options.healthTimeoutMs
|
|
7665
|
-
});
|
|
7666
|
-
return {
|
|
7667
|
-
runtimeId: inspect.Id,
|
|
7668
|
-
baseUrl
|
|
7669
|
-
};
|
|
7670
|
-
} };
|
|
7739
|
+
};
|
|
7671
7740
|
}
|
|
7672
7741
|
function containerName(organizationId) {
|
|
7673
7742
|
return `keystroke-org-${organizationId}`;
|
|
@@ -7755,8 +7824,29 @@ async function pingProjectTarget(target, options = {}) {
|
|
|
7755
7824
|
});
|
|
7756
7825
|
}
|
|
7757
7826
|
//#endregion
|
|
7827
|
+
//#region src/deploy-status.ts
|
|
7828
|
+
/**
|
|
7829
|
+
* Ask a running org machine which projects bootstrapped and which failed.
|
|
7830
|
+
* Best-effort: returns undefined on any error so callers can fall back to
|
|
7831
|
+
* treating every project as healthy (preserving pre-existing behavior).
|
|
7832
|
+
*/
|
|
7833
|
+
async function fetchDeployStatus(baseUrl, options = {}) {
|
|
7834
|
+
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
7835
|
+
try {
|
|
7836
|
+
const response = await (options.fetchImpl ?? fetch)(new URL(PROJECT_SERVER_DEPLOY_STATUS.path, baseUrl), { signal: AbortSignal.timeout(timeoutMs) });
|
|
7837
|
+
if (!response.ok) return;
|
|
7838
|
+
const data = await response.json();
|
|
7839
|
+
if (!data || !Array.isArray(data.projects)) return;
|
|
7840
|
+
return data;
|
|
7841
|
+
} catch (error) {
|
|
7842
|
+
console.warn(`[deploy-status] failed to fetch from ${baseUrl}:`, error);
|
|
7843
|
+
return;
|
|
7844
|
+
}
|
|
7845
|
+
}
|
|
7846
|
+
//#endregion
|
|
7758
7847
|
exports.DEV_PLATFORM_WORKER_TOKEN = DEV_PLATFORM_WORKER_TOKEN;
|
|
7759
7848
|
exports.PROJECT_DATABASE_ENV_KEYS = PROJECT_DATABASE_ENV_KEYS;
|
|
7849
|
+
exports.PROJECT_SERVER_DEPLOY_STATUS = PROJECT_SERVER_DEPLOY_STATUS;
|
|
7760
7850
|
exports.PROJECT_SERVER_FRAMEWORK_NODE_MODULES = PROJECT_SERVER_FRAMEWORK_NODE_MODULES;
|
|
7761
7851
|
exports.PROJECT_SERVER_FRAMEWORK_ROOT = PROJECT_SERVER_FRAMEWORK_ROOT;
|
|
7762
7852
|
exports.PROJECT_SERVER_HEALTH = PROJECT_SERVER_HEALTH;
|
|
@@ -7770,6 +7860,7 @@ exports.canPingProjectTarget = canPingProjectTarget;
|
|
|
7770
7860
|
exports.defaultHostingPlugin = defaultHostingPlugin;
|
|
7771
7861
|
exports.dockerPlugin = dockerPlugin;
|
|
7772
7862
|
exports.encodeOrgArtifacts = encodeOrgArtifacts;
|
|
7863
|
+
exports.fetchDeployStatus = fetchDeployStatus;
|
|
7773
7864
|
exports.formatDockerEnv = formatDockerEnv;
|
|
7774
7865
|
exports.parseOrgArtifactsFromEnv = parseOrgArtifactsFromEnv;
|
|
7775
7866
|
exports.pingProject = pingProject;
|