@keystrokehq/hosting 0.1.9 → 0.1.11

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 CHANGED
@@ -1,3 +1,4 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
1
2
  import Docker from "dockerode";
2
3
  import { mkdir } from "node:fs/promises";
3
4
  //#region src/constants.ts
@@ -621,6 +622,7 @@ const string$1 = (params) => {
621
622
  const integer = /^-?\d+$/;
622
623
  const number$2 = /^-?\d+(?:\.\d+)?$/;
623
624
  const boolean$1 = /^(?:true|false)$/i;
625
+ const _null$2 = /^null$/i;
624
626
  const lowercase = /^[^A-Z]*$/;
625
627
  const uppercase = /^[^a-z]*$/;
626
628
  //#endregion
@@ -1433,6 +1435,22 @@ const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
1433
1435
  return payload;
1434
1436
  };
1435
1437
  });
1438
+ const $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
1439
+ $ZodType.init(inst, def);
1440
+ inst._zod.pattern = _null$2;
1441
+ inst._zod.values = new Set([null]);
1442
+ inst._zod.parse = (payload, _ctx) => {
1443
+ const input = payload.value;
1444
+ if (input === null) return payload;
1445
+ payload.issues.push({
1446
+ expected: "null",
1447
+ code: "invalid_type",
1448
+ input,
1449
+ inst
1450
+ });
1451
+ return payload;
1452
+ };
1453
+ });
1436
1454
  const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
1437
1455
  $ZodType.init(inst, def);
1438
1456
  inst._zod.parse = (payload) => payload;
@@ -2679,6 +2697,13 @@ function _boolean(Class, params) {
2679
2697
  });
2680
2698
  }
2681
2699
  /* @__NO_SIDE_EFFECTS__ */
2700
+ function _null$1(Class, params) {
2701
+ return new Class({
2702
+ type: "null",
2703
+ ...normalizeParams(params)
2704
+ });
2705
+ }
2706
+ /* @__NO_SIDE_EFFECTS__ */
2682
2707
  function _unknown(Class) {
2683
2708
  return new Class({ type: "unknown" });
2684
2709
  }
@@ -3227,6 +3252,13 @@ const numberProcessor = (schema, ctx, _json, _params) => {
3227
3252
  const booleanProcessor = (_schema, _ctx, json, _params) => {
3228
3253
  json.type = "boolean";
3229
3254
  };
3255
+ const nullProcessor = (_schema, ctx, json, _params) => {
3256
+ if (ctx.target === "openapi-3.0") {
3257
+ json.type = "string";
3258
+ json.nullable = true;
3259
+ json.enum = [null];
3260
+ } else json.type = "null";
3261
+ };
3230
3262
  const neverProcessor = (_schema, _ctx, json, _params) => {
3231
3263
  json.not = {};
3232
3264
  };
@@ -3926,6 +3958,14 @@ const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
3926
3958
  function boolean(params) {
3927
3959
  return /* @__PURE__ */ _boolean(ZodBoolean, params);
3928
3960
  }
3961
+ const ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
3962
+ $ZodNull.init(inst, def);
3963
+ ZodType.init(inst, def);
3964
+ inst._zod.processJSONSchema = (ctx, json, params) => nullProcessor(inst, ctx, json, params);
3965
+ });
3966
+ function _null(params) {
3967
+ return /* @__PURE__ */ _null$1(ZodNull, params);
3968
+ }
3929
3969
  const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
3930
3970
  $ZodUnknown.init(inst, def);
3931
3971
  ZodType.init(inst, def);
@@ -4768,6 +4808,7 @@ const INFRA_SYSTEM_SLUGS = [
4768
4808
  "health",
4769
4809
  "healthcheck",
4770
4810
  "healthz",
4811
+ "hook-resume",
4771
4812
  "hooks",
4772
4813
  "internal",
4773
4814
  "item",
@@ -4933,14 +4974,14 @@ const OrganizationUserRoleSchema = _enum([
4933
4974
  "admin",
4934
4975
  "builder"
4935
4976
  ]);
4936
- const isoDateTime$5 = string().datetime();
4977
+ const isoDateTime$7 = string().datetime();
4937
4978
  const OrganizationSchema = object({
4938
4979
  id: string(),
4939
4980
  name: string(),
4940
4981
  slug: OrganizationSlugSchema,
4941
4982
  verified: boolean(),
4942
- createdAt: isoDateTime$5,
4943
- updatedAt: isoDateTime$5
4983
+ createdAt: isoDateTime$7,
4984
+ updatedAt: isoDateTime$7
4944
4985
  });
4945
4986
  const ProjectSchema = object({
4946
4987
  id: string(),
@@ -4952,8 +4993,8 @@ const ProjectSchema = object({
4952
4993
  baseUrl: string().nullable(),
4953
4994
  runtimeId: string().nullable(),
4954
4995
  lastError: string().nullable(),
4955
- createdAt: isoDateTime$5,
4956
- updatedAt: isoDateTime$5
4996
+ createdAt: isoDateTime$7,
4997
+ updatedAt: isoDateTime$7
4957
4998
  });
4958
4999
  object({
4959
5000
  organization: OrganizationSchema,
@@ -4973,7 +5014,7 @@ const ProjectListMetricsSchema = object({
4973
5014
  workflowCount: number$1(),
4974
5015
  skillCount: number$1(),
4975
5016
  credentialCount: number$1(),
4976
- lastDeploymentAt: isoDateTime$5.nullable()
5017
+ lastDeploymentAt: isoDateTime$7.nullable()
4977
5018
  });
4978
5019
  record(string(), ProjectListMetricsSchema);
4979
5020
  object({
@@ -5328,6 +5369,130 @@ object({
5328
5369
  skills: array(StoredRouteManifestSkillSchema).default([]),
5329
5370
  integrations: array(string()).optional()
5330
5371
  });
5372
+ const isoDateTime$6 = string().datetime();
5373
+ const subscriptionStatusSchema = _enum([
5374
+ "none",
5375
+ "trialing",
5376
+ "active",
5377
+ "past_due",
5378
+ "canceled"
5379
+ ]);
5380
+ const CreditPackSchema = object({
5381
+ id: string(),
5382
+ usd: number$1(),
5383
+ microCredits: number$1(),
5384
+ label: string()
5385
+ });
5386
+ const AutoTopupSummarySchema = object({
5387
+ enabled: boolean(),
5388
+ thresholdMicroCredits: number$1().nullable(),
5389
+ amountMicroCredits: number$1().nullable(),
5390
+ /** A saved payment method exists to charge off-session. */
5391
+ hasPaymentMethod: boolean(),
5392
+ /** A top-up invoice payment is in flight. */
5393
+ pending: boolean()
5394
+ });
5395
+ /**
5396
+ * The plan's resolved limits. Storage overage is billed from the wallet's
5397
+ * pushed-down `includedStorageGb`; concurrency, per-pass run timeouts, and
5398
+ * API/MCP rate limits are enforced from the wallet (timeouts/concurrency) or
5399
+ * plan preset (rate limits). Log retention is configured but not pruned yet.
5400
+ */
5401
+ const PlanLimitsSchema = object({
5402
+ includedStorageGb: number$1(),
5403
+ concurrencyLimit: number$1(),
5404
+ agentTimeoutMs: number$1(),
5405
+ workflowTimeoutMs: number$1(),
5406
+ pollTimeoutMs: number$1(),
5407
+ /** Configured retention window; pruning not implemented yet. */
5408
+ logRetentionDays: number$1(),
5409
+ apiRateLimitCapacity: number$1(),
5410
+ apiRateLimitRefillPerSec: number$1(),
5411
+ mcpRateLimitCapacity: number$1(),
5412
+ mcpRateLimitRefillPerSec: number$1()
5413
+ });
5414
+ object({
5415
+ planKey: string(),
5416
+ subscriptionStatus: subscriptionStatusSchema,
5417
+ planCreditMicroCredits: number$1(),
5418
+ prepaidCreditMicroCredits: number$1(),
5419
+ periodStart: isoDateTime$6.nullable(),
5420
+ periodEnd: isoDateTime$6.nullable(),
5421
+ autoTopup: AutoTopupSummarySchema,
5422
+ creditPacks: array(CreditPackSchema),
5423
+ limits: PlanLimitsSchema
5424
+ });
5425
+ const BillingUsageMeterSchema = object({
5426
+ /** Meter key (`llm`, `vm_second`, …); null groups uncategorized rows. */
5427
+ meterKey: string().nullable(),
5428
+ /** Charged this period, µc. */
5429
+ microCredits: number$1(),
5430
+ /** Tracked-but-not-charged usage (e.g. BYOK LLM calls), display USD. */
5431
+ unchargedUsd: number$1()
5432
+ });
5433
+ object({
5434
+ periodStart: isoDateTime$6.nullable(),
5435
+ periodEnd: isoDateTime$6.nullable(),
5436
+ totalMicroCredits: number$1(),
5437
+ byMeter: array(BillingUsageMeterSchema)
5438
+ });
5439
+ const billingLedgerEntryTypeSchema = _enum([
5440
+ "grant_plan",
5441
+ "grant_prepaid",
5442
+ "expire_plan",
5443
+ "adjustment"
5444
+ ]);
5445
+ object({
5446
+ entries: array(object({
5447
+ id: string(),
5448
+ entryType: billingLedgerEntryTypeSchema,
5449
+ label: string(),
5450
+ /** Signed: positive grants, negative expirations/adjustments. */
5451
+ microCredits: number$1(),
5452
+ bucket: _enum(["plan", "prepaid"]).nullable(),
5453
+ /** Stripe invoice behind the entry, when there is one — powers "View invoice". */
5454
+ stripeInvoiceId: string().nullable(),
5455
+ createdAt: isoDateTime$6
5456
+ })),
5457
+ /** Set only when the latest payment failure is newer than the latest successful payment. */
5458
+ lastPaymentFailureAt: isoDateTime$6.nullable()
5459
+ });
5460
+ object({
5461
+ /** Web-app path to land on after Checkout (must be a path, not a URL). */
5462
+ returnPath: string().startsWith("/").max(512).optional() });
5463
+ object({
5464
+ packId: string(),
5465
+ returnPath: string().startsWith("/").max(512).optional()
5466
+ });
5467
+ object({ returnPath: string().startsWith("/").max(512).optional() });
5468
+ object({ url: string().url() });
5469
+ object({
5470
+ /** Hosted invoice page (view, download, receipt). */
5471
+ url: string().url(),
5472
+ /** Direct PDF download when Stripe provides one. */
5473
+ pdf: string().url().nullable()
5474
+ });
5475
+ object({
5476
+ /** Stripe Checkout Session id from the `session_id` success-URL param. */
5477
+ sessionId: string().min(1).max(255) });
5478
+ object({
5479
+ /**
5480
+ * `granted` — credits are in the wallet now; `processing` — payment not
5481
+ * complete yet, the webhook will finish it; `ignored` — not a confirmable
5482
+ * session for this org.
5483
+ */
5484
+ status: _enum([
5485
+ "granted",
5486
+ "processing",
5487
+ "ignored"
5488
+ ]),
5489
+ reason: string().optional()
5490
+ });
5491
+ object({
5492
+ enabled: boolean(),
5493
+ thresholdMicroCredits: number$1().int().positive().optional(),
5494
+ packId: string().optional()
5495
+ });
5331
5496
  /** Messaging platforms that support agent gateway bindings. */
5332
5497
  const ChannelPlatformKeySchema = _enum(["slack"]);
5333
5498
  const ChannelReactionSupportSchema = _enum([
@@ -5848,7 +6013,11 @@ object({
5848
6013
  isDefault: boolean().optional(),
5849
6014
  value: credentialSecretValueSchema.optional()
5850
6015
  }).refine((input) => input.label !== void 0 || input.isDefault !== void 0 || input.value !== void 0, { message: "At least one field is required" });
5851
- const CredentialAssignmentTargetTypeSchema = _enum(["workflow", "agent"]);
6016
+ const CredentialAssignmentTargetTypeSchema = _enum([
6017
+ "workflow",
6018
+ "agent",
6019
+ "poll"
6020
+ ]);
5852
6021
  object({ assignments: array(object({
5853
6022
  id: string(),
5854
6023
  targetType: CredentialAssignmentTargetTypeSchema,
@@ -5963,7 +6132,11 @@ const ValidationErrorDetailSchema = object({
5963
6132
  message: string()
5964
6133
  });
5965
6134
  /** Machine-readable codes returned in standard API error bodies. */
5966
- const ErrorResponseCodeSchema = OrganizationSlugErrorCodeSchema.or(_enum(["needs_org_selection", "org_unverified"]));
6135
+ const ErrorResponseCodeSchema = OrganizationSlugErrorCodeSchema.or(_enum([
6136
+ "needs_org_selection",
6137
+ "org_unverified",
6138
+ "connector_unavailable"
6139
+ ]));
5967
6140
  object({
5968
6141
  error: string(),
5969
6142
  code: ErrorResponseCodeSchema.optional(),
@@ -6074,6 +6247,17 @@ union([
6074
6247
  SkipResponseSchema,
6075
6248
  object({ runId: string() })
6076
6249
  ]);
6250
+ object({
6251
+ sql: string().min(1),
6252
+ params: array(unknown()).default([]),
6253
+ method: string().min(1).optional()
6254
+ });
6255
+ object({ migrations: array(object({
6256
+ sql: array(string().min(1)),
6257
+ hash: string().min(1),
6258
+ folderMillis: number$1()
6259
+ })) });
6260
+ object({ results: array(object({ rows: array(unknown()) })) });
6077
6261
  const RunSourceKindSchema = _enum([
6078
6262
  "api",
6079
6263
  "trigger",
@@ -6394,12 +6578,19 @@ const HistoryRunActorSchema = object({
6394
6578
  const HistoryRunUsageLineItemSchema = object({
6395
6579
  id: string(),
6396
6580
  label: string(),
6397
- amountUsd: number$1()
6581
+ /** Amount debited from the org's Keystroke balance for this line. */
6582
+ billedUsd: number$1(),
6583
+ /** Provider cost for LLM usage on the org's API key (informational; not billed by Keystroke). */
6584
+ providerCostUsd: number$1().nullable().optional(),
6585
+ keySource: _enum(["byok", "platform"]).nullable().optional()
6398
6586
  });
6399
6587
  const HistoryRunUsageSchema = object({
6400
6588
  runDurationMs: number$1().nullable(),
6401
6589
  lineItems: array(HistoryRunUsageLineItemSchema),
6402
- totalExcludingDurationUsd: number$1().nullable()
6590
+ /** Sum of `billedUsd` — what Keystroke charged for this run. */
6591
+ totalBilledUsd: number$1().nullable(),
6592
+ /** Sum of BYOK LLM provider costs (billed externally by the org's provider). */
6593
+ externalProviderCostUsd: number$1().nullable().optional()
6403
6594
  });
6404
6595
  const HistoryRunSchema = object({
6405
6596
  id: string(),
@@ -6530,6 +6721,7 @@ const HistoryRunDetailSchema = discriminatedUnion("kind", [object({
6530
6721
  attachmentSlug: string().nullable()
6531
6722
  }).nullable(),
6532
6723
  messages: array(record(string(), unknown())),
6724
+ live: record(string(), unknown()).nullable().default(null),
6533
6725
  trace: HistoryTraceSchema.nullable(),
6534
6726
  ranAs: HistoryRunActorSchema.nullable().optional(),
6535
6727
  usage: HistoryRunUsageSchema.nullable().optional()
@@ -6819,7 +7011,7 @@ const OrganizationMemberStatusSchema = _enum([
6819
7011
  "suspended"
6820
7012
  ]);
6821
7013
  const InvitableOrganizationMemberRoleSchema = _enum(["admin", "builder"]);
6822
- const isoDateTime$4 = string().datetime();
7014
+ const isoDateTime$5 = string().datetime();
6823
7015
  object({
6824
7016
  id: string(),
6825
7017
  name: string(),
@@ -6827,8 +7019,8 @@ object({
6827
7019
  role: OrganizationMemberRoleSchema,
6828
7020
  status: OrganizationMemberStatusSchema,
6829
7021
  avatarUrl: string().optional(),
6830
- joinedAt: isoDateTime$4.optional(),
6831
- lastActiveAt: isoDateTime$4.nullable().optional()
7022
+ joinedAt: isoDateTime$5.optional(),
7023
+ lastActiveAt: isoDateTime$5.nullable().optional()
6832
7024
  });
6833
7025
  object({
6834
7026
  emails: array(string().trim().email()).min(1),
@@ -6855,7 +7047,7 @@ object({
6855
7047
  role: OrganizationMemberRoleSchema
6856
7048
  });
6857
7049
  object({ success: literal(true) });
6858
- const isoDateTime$3 = string().datetime();
7050
+ const isoDateTime$4 = string().datetime();
6859
7051
  const ApiKeyCreatorSchema = object({
6860
7052
  id: string(),
6861
7053
  name: string(),
@@ -6868,12 +7060,37 @@ const ApiKeySummarySchema = object({
6868
7060
  id: string(),
6869
7061
  name: string(),
6870
7062
  keyPreview: string(),
6871
- createdAt: isoDateTime$3,
7063
+ createdAt: isoDateTime$4,
6872
7064
  createdBy: ApiKeyCreatorSchema,
6873
7065
  isCreatedByCurrentUser: boolean()
6874
7066
  });
6875
7067
  object({ name: string().trim().min(1).max(128) });
6876
7068
  ApiKeySummarySchema.extend({ secret: string() });
7069
+ const isoDateTime$3 = string().datetime();
7070
+ const ManagedServiceKindSchema = _enum(["llm"]);
7071
+ _enum([
7072
+ "openai",
7073
+ "anthropic",
7074
+ "google",
7075
+ "groq",
7076
+ "xai"
7077
+ ]);
7078
+ object({
7079
+ id: string(),
7080
+ kind: ManagedServiceKindSchema,
7081
+ provider: string(),
7082
+ keyPreview: string(),
7083
+ createdAt: isoDateTime$3,
7084
+ updatedAt: isoDateTime$3,
7085
+ createdBy: ApiKeyCreatorSchema,
7086
+ isCreatedByCurrentUser: boolean()
7087
+ });
7088
+ object({
7089
+ kind: ManagedServiceKindSchema.default("llm"),
7090
+ provider: string().trim().min(1),
7091
+ apiKey: string().trim().min(1)
7092
+ });
7093
+ object({ apiKey: string().trim().min(1) });
6877
7094
  const ProjectUserRoleSchema = _enum(["admin", "builder"]);
6878
7095
  const ProjectInvitePermissionSchema = _enum(["admin", "all"]);
6879
7096
  const ProjectMemberStatusSchema = _enum(["active", "invited"]);
@@ -6923,6 +7140,14 @@ object({
6923
7140
  uploadUrl: url(),
6924
7141
  storageKey: string().min(1)
6925
7142
  });
7143
+ function isValidIanaTimezone(value) {
7144
+ try {
7145
+ Intl.DateTimeFormat(void 0, { timeZone: value });
7146
+ return true;
7147
+ } catch {
7148
+ return false;
7149
+ }
7150
+ }
6926
7151
  const UserInterfaceThemeSchema = _enum([
6927
7152
  "system",
6928
7153
  "light",
@@ -6942,22 +7167,25 @@ const UserWorkspaceFavoriteSchema = object({
6942
7167
  ]),
6943
7168
  resourceId: string().min(1)
6944
7169
  });
7170
+ const UserSidebarPreferencesSchema = object({
7171
+ navIconVisibility: UserSidebarNavIconVisibilitySchema,
7172
+ footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
7173
+ hiddenNavItemIds: array(string()),
7174
+ topNavItemOrderIds: array(string()),
7175
+ workspaceNavItemOrderIds: array(string())
7176
+ });
7177
+ const UserTimezoneSchema = string().refine(isValidIanaTimezone, { message: "Invalid IANA timezone" });
6945
7178
  object({
6946
7179
  interfaceTheme: UserInterfaceThemeSchema,
6947
7180
  surfaceContrast: UserSurfaceContrastSchema,
6948
7181
  layoutMode: UserWorkspaceLayoutModeSchema,
6949
7182
  fontSize: UserWorkspaceFontSizeSchema,
6950
- sidebar: object({
6951
- navIconVisibility: UserSidebarNavIconVisibilitySchema,
6952
- footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
6953
- hiddenNavItemIds: array(string()),
6954
- topNavItemOrderIds: array(string()),
6955
- workspaceNavItemOrderIds: array(string())
6956
- }),
7183
+ sidebar: UserSidebarPreferencesSchema,
6957
7184
  favorites: array(UserWorkspaceFavoriteSchema),
6958
7185
  projectOrderIds: array(string()),
6959
7186
  projectDotColors: record(string(), string()),
6960
- onboardingTabVisible: boolean()
7187
+ onboardingTabVisible: boolean(),
7188
+ timezone: union([UserTimezoneSchema, _null()])
6961
7189
  });
6962
7190
  const UserSidebarPreferencesPatchSchema = object({
6963
7191
  navIconVisibility: UserSidebarNavIconVisibilitySchema.optional(),
@@ -6975,8 +7203,9 @@ object({
6975
7203
  favorites: array(UserWorkspaceFavoriteSchema).optional(),
6976
7204
  projectOrderIds: array(string()).optional(),
6977
7205
  projectDotColors: record(string(), string()).optional(),
6978
- onboardingTabVisible: boolean().optional()
6979
- }).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, { message: "At least one preference field is required" });
7206
+ onboardingTabVisible: boolean().optional(),
7207
+ timezone: union([UserTimezoneSchema, _null()]).optional()
7208
+ }).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" });
6980
7209
  const OrganizationLogoVariantSchema = _enum(["light", "dark"]);
6981
7210
  object({
6982
7211
  customLogoEnabled: boolean(),
@@ -7439,13 +7668,35 @@ function parseOrgArtifactsFromEnv(env = process.env) {
7439
7668
  });
7440
7669
  }
7441
7670
  //#endregion
7671
+ //#region src/org-worker-token.ts
7672
+ function sign(secret, organizationId) {
7673
+ return createHmac("sha256", secret).update(`org-worker:${organizationId}`).digest("base64url");
7674
+ }
7675
+ /**
7676
+ * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the
7677
+ * platform can tell which org a machine is calling as, and stateless — verified
7678
+ * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.
7679
+ */
7680
+ function mintOrgWorkerToken(secret, organizationId) {
7681
+ return `${organizationId}.${sign(secret, organizationId)}`;
7682
+ }
7683
+ function verifyOrgWorkerToken(secret, token) {
7684
+ if (!secret || !token) return;
7685
+ const separator = token.lastIndexOf(".");
7686
+ if (separator <= 0) return;
7687
+ const organizationId = token.slice(0, separator);
7688
+ const signature = Buffer.from(token.slice(separator + 1));
7689
+ const expected = Buffer.from(sign(secret, organizationId));
7690
+ if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) return;
7691
+ return { organizationId };
7692
+ }
7693
+ //#endregion
7442
7694
  //#region src/runtime-env.ts
7443
7695
  const RUNTIME_ENV_KEYS = [
7444
7696
  "BETTER_AUTH_SECRET",
7445
7697
  "PUBLIC_PLATFORM_URL",
7446
7698
  "PUBLIC_PLATFORM_PROXY_URL",
7447
7699
  "PUBLIC_WEB_URL",
7448
- "POSTGRES_SSL",
7449
7700
  "UPSTASH_REDIS_URL",
7450
7701
  "REDIS_URL",
7451
7702
  "KEYSTROKE_QUEUE_PREFIX"
@@ -7459,25 +7710,6 @@ const PROVIDER_ENV_KEYS = [
7459
7710
  ];
7460
7711
  /** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
7461
7712
  const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
7462
- const PROJECT_DATABASE_ENV_KEYS = [
7463
- "POSTGRES_HOST",
7464
- "POSTGRES_PORT",
7465
- "POSTGRES_DB",
7466
- "POSTGRES_USER",
7467
- "POSTGRES_PASSWORD",
7468
- "DATABASE_SEARCH_PATH"
7469
- ];
7470
- /** Per-project postgres env injected into every project server container/machine. */
7471
- function projectDatabaseRuntimeEnv(database) {
7472
- return {
7473
- POSTGRES_HOST: rewriteLoopbackHost(database.host),
7474
- POSTGRES_PORT: String(database.port),
7475
- POSTGRES_DB: database.database,
7476
- POSTGRES_USER: database.user,
7477
- POSTGRES_PASSWORD: database.password,
7478
- DATABASE_SEARCH_PATH: database.searchPath
7479
- };
7480
- }
7481
7713
  /**
7482
7714
  * Builds the launch spec for an org worker. Each deploy artifact is encoded in
7483
7715
  * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.
@@ -7504,10 +7736,7 @@ function buildRuntimeEnv(source, artifacts, database, extraEnv) {
7504
7736
  ]);
7505
7737
  for (const key of RUNTIME_ENV_KEYS) {
7506
7738
  const value = source[key]?.trim();
7507
- if (!value) {
7508
- if (key === "POSTGRES_SSL") throw new Error("POSTGRES_SSL is required");
7509
- continue;
7510
- }
7739
+ if (!value) continue;
7511
7740
  entries.set(key, value);
7512
7741
  }
7513
7742
  if (!extraEnv) for (const key of PROVIDER_ENV_KEYS) {
@@ -7516,8 +7745,7 @@ function buildRuntimeEnv(source, artifacts, database, extraEnv) {
7516
7745
  }
7517
7746
  const worker = resolveWorkerRuntimeConfig(source);
7518
7747
  entries.set("PLATFORM_URL", worker.platformUrl);
7519
- entries.set("WORKER_INTERNAL_TOKEN", worker.workerToken);
7520
- for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) entries.set(key, value);
7748
+ entries.set("WORKER_INTERNAL_TOKEN", mintOrgWorkerToken(worker.workerToken, database.organizationId));
7521
7749
  if (extraEnv) for (const [key, value] of Object.entries(extraEnv)) entries.set(key, value);
7522
7750
  return Object.fromEntries(entries);
7523
7751
  }
@@ -7605,55 +7833,63 @@ function sleep(ms) {
7605
7833
  const MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? "keystroke";
7606
7834
  function createDockerRuntime(options = {}) {
7607
7835
  const docker = options.docker ?? new Docker();
7608
- return { async start(input) {
7609
- if (input.projects.length === 0) throw new Error("Docker org runtime requires at least one project deploy");
7610
- let launch = resolveRuntimeLaunch(options, input.projects.map((project) => ({
7611
- projectId: project.projectId,
7612
- artifactStorageKey: project.artifactStorageKey
7613
- })), input.database, input.env);
7614
- if (options.workspacesMount) {
7615
- const { hostPath, containerPath } = options.workspacesMount;
7616
- await mkdir(hostPath, { recursive: true });
7617
- launch = {
7618
- ...launch,
7619
- env: {
7620
- ...launch.env,
7621
- KEYSTROKE_WORKSPACES_ROOT: containerPath
7622
- }
7836
+ return {
7837
+ async start(input) {
7838
+ if (input.projects.length === 0) throw new Error("Docker org runtime requires at least one project deploy");
7839
+ let launch = resolveRuntimeLaunch(options, input.projects.map((project) => ({
7840
+ projectId: project.projectId,
7841
+ artifactStorageKey: project.artifactStorageKey
7842
+ })), input.database, input.env);
7843
+ if (options.workspacesMount) {
7844
+ const { hostPath, containerPath } = options.workspacesMount;
7845
+ await mkdir(hostPath, { recursive: true });
7846
+ launch = {
7847
+ ...launch,
7848
+ env: {
7849
+ ...launch.env,
7850
+ KEYSTROKE_WORKSPACES_ROOT: containerPath
7851
+ }
7852
+ };
7853
+ }
7854
+ await ensureImage(docker, launch.image);
7855
+ await removeExistingContainer(docker, input.organizationId);
7856
+ const binds = [...options.workspacesMount ? [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] : [], ...options.extraBinds ?? []];
7857
+ const container = await docker.createContainer({
7858
+ Image: launch.image,
7859
+ name: containerName(input.organizationId),
7860
+ Labels: {
7861
+ "keystroke.organization.id": input.organizationId,
7862
+ "keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
7863
+ },
7864
+ ExposedPorts: { [`${launch.port}/tcp`]: {} },
7865
+ HostConfig: {
7866
+ ExtraHosts: ["host.docker.internal:host-gateway"],
7867
+ PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
7868
+ ...binds.length > 0 ? { Binds: binds } : {}
7869
+ },
7870
+ NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
7871
+ Env: formatDockerEnv(launch.env)
7872
+ });
7873
+ await container.start();
7874
+ const inspect = await container.inspect();
7875
+ const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
7876
+ if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
7877
+ const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
7878
+ await waitForHealth(baseUrl, {
7879
+ fetchImpl: options.fetchImpl,
7880
+ timeoutMs: options.healthTimeoutMs
7881
+ });
7882
+ return {
7883
+ runtimeId: inspect.Id,
7884
+ baseUrl
7623
7885
  };
7886
+ },
7887
+ async destroy(input) {
7888
+ try {
7889
+ await docker.getContainer(input.runtimeId).remove({ force: true });
7890
+ } catch {}
7624
7891
  }
7625
- await ensureImage(docker, launch.image);
7626
- await removeExistingContainer(docker, input.organizationId);
7627
- const container = await docker.createContainer({
7628
- Image: launch.image,
7629
- name: containerName(input.organizationId),
7630
- Labels: {
7631
- "keystroke.organization.id": input.organizationId,
7632
- "keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
7633
- },
7634
- ExposedPorts: { [`${launch.port}/tcp`]: {} },
7635
- HostConfig: {
7636
- ExtraHosts: ["host.docker.internal:host-gateway"],
7637
- PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
7638
- ...options.workspacesMount ? { Binds: [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] } : {}
7639
- },
7640
- NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
7641
- Env: formatDockerEnv(launch.env)
7642
- });
7643
- await container.start();
7644
- const inspect = await container.inspect();
7645
- const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
7646
- if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
7647
- const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
7648
- await waitForHealth(baseUrl, {
7649
- fetchImpl: options.fetchImpl,
7650
- timeoutMs: options.healthTimeoutMs
7651
- });
7652
- return {
7653
- runtimeId: inspect.Id,
7654
- baseUrl
7655
- };
7656
- } };
7892
+ };
7657
7893
  }
7658
7894
  function containerName(organizationId) {
7659
7895
  return `keystroke-org-${organizationId}`;
@@ -7761,6 +7997,6 @@ async function fetchDeployStatus(baseUrl, options = {}) {
7761
7997
  }
7762
7998
  }
7763
7999
  //#endregion
7764
- export { DEV_PLATFORM_WORKER_TOKEN, PROJECT_DATABASE_ENV_KEYS, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, RUNTIME_PING_TIMEOUT_MS, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, waitForHealth };
8000
+ export { DEV_PLATFORM_WORKER_TOKEN, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, RUNTIME_PING_TIMEOUT_MS, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, verifyOrgWorkerToken, waitForHealth };
7765
8001
 
7766
8002
  //# sourceMappingURL=index.mjs.map