@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.cjs CHANGED
@@ -21,6 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
+ let node_crypto = require("node:crypto");
24
25
  let dockerode = require("dockerode");
25
26
  dockerode = __toESM(dockerode, 1);
26
27
  let node_fs_promises = require("node:fs/promises");
@@ -645,6 +646,7 @@ const string$1 = (params) => {
645
646
  const integer = /^-?\d+$/;
646
647
  const number$2 = /^-?\d+(?:\.\d+)?$/;
647
648
  const boolean$1 = /^(?:true|false)$/i;
649
+ const _null$2 = /^null$/i;
648
650
  const lowercase = /^[^A-Z]*$/;
649
651
  const uppercase = /^[^a-z]*$/;
650
652
  //#endregion
@@ -1457,6 +1459,22 @@ const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
1457
1459
  return payload;
1458
1460
  };
1459
1461
  });
1462
+ const $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
1463
+ $ZodType.init(inst, def);
1464
+ inst._zod.pattern = _null$2;
1465
+ inst._zod.values = new Set([null]);
1466
+ inst._zod.parse = (payload, _ctx) => {
1467
+ const input = payload.value;
1468
+ if (input === null) return payload;
1469
+ payload.issues.push({
1470
+ expected: "null",
1471
+ code: "invalid_type",
1472
+ input,
1473
+ inst
1474
+ });
1475
+ return payload;
1476
+ };
1477
+ });
1460
1478
  const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
1461
1479
  $ZodType.init(inst, def);
1462
1480
  inst._zod.parse = (payload) => payload;
@@ -2703,6 +2721,13 @@ function _boolean(Class, params) {
2703
2721
  });
2704
2722
  }
2705
2723
  /* @__NO_SIDE_EFFECTS__ */
2724
+ function _null$1(Class, params) {
2725
+ return new Class({
2726
+ type: "null",
2727
+ ...normalizeParams(params)
2728
+ });
2729
+ }
2730
+ /* @__NO_SIDE_EFFECTS__ */
2706
2731
  function _unknown(Class) {
2707
2732
  return new Class({ type: "unknown" });
2708
2733
  }
@@ -3251,6 +3276,13 @@ const numberProcessor = (schema, ctx, _json, _params) => {
3251
3276
  const booleanProcessor = (_schema, _ctx, json, _params) => {
3252
3277
  json.type = "boolean";
3253
3278
  };
3279
+ const nullProcessor = (_schema, ctx, json, _params) => {
3280
+ if (ctx.target === "openapi-3.0") {
3281
+ json.type = "string";
3282
+ json.nullable = true;
3283
+ json.enum = [null];
3284
+ } else json.type = "null";
3285
+ };
3254
3286
  const neverProcessor = (_schema, _ctx, json, _params) => {
3255
3287
  json.not = {};
3256
3288
  };
@@ -3950,6 +3982,14 @@ const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
3950
3982
  function boolean(params) {
3951
3983
  return /* @__PURE__ */ _boolean(ZodBoolean, params);
3952
3984
  }
3985
+ const ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
3986
+ $ZodNull.init(inst, def);
3987
+ ZodType.init(inst, def);
3988
+ inst._zod.processJSONSchema = (ctx, json, params) => nullProcessor(inst, ctx, json, params);
3989
+ });
3990
+ function _null(params) {
3991
+ return /* @__PURE__ */ _null$1(ZodNull, params);
3992
+ }
3953
3993
  const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
3954
3994
  $ZodUnknown.init(inst, def);
3955
3995
  ZodType.init(inst, def);
@@ -4792,6 +4832,7 @@ const INFRA_SYSTEM_SLUGS = [
4792
4832
  "health",
4793
4833
  "healthcheck",
4794
4834
  "healthz",
4835
+ "hook-resume",
4795
4836
  "hooks",
4796
4837
  "internal",
4797
4838
  "item",
@@ -4957,14 +4998,14 @@ const OrganizationUserRoleSchema = _enum([
4957
4998
  "admin",
4958
4999
  "builder"
4959
5000
  ]);
4960
- const isoDateTime$5 = string().datetime();
5001
+ const isoDateTime$7 = string().datetime();
4961
5002
  const OrganizationSchema = object({
4962
5003
  id: string(),
4963
5004
  name: string(),
4964
5005
  slug: OrganizationSlugSchema,
4965
5006
  verified: boolean(),
4966
- createdAt: isoDateTime$5,
4967
- updatedAt: isoDateTime$5
5007
+ createdAt: isoDateTime$7,
5008
+ updatedAt: isoDateTime$7
4968
5009
  });
4969
5010
  const ProjectSchema = object({
4970
5011
  id: string(),
@@ -4976,8 +5017,8 @@ const ProjectSchema = object({
4976
5017
  baseUrl: string().nullable(),
4977
5018
  runtimeId: string().nullable(),
4978
5019
  lastError: string().nullable(),
4979
- createdAt: isoDateTime$5,
4980
- updatedAt: isoDateTime$5
5020
+ createdAt: isoDateTime$7,
5021
+ updatedAt: isoDateTime$7
4981
5022
  });
4982
5023
  object({
4983
5024
  organization: OrganizationSchema,
@@ -4997,7 +5038,7 @@ const ProjectListMetricsSchema = object({
4997
5038
  workflowCount: number$1(),
4998
5039
  skillCount: number$1(),
4999
5040
  credentialCount: number$1(),
5000
- lastDeploymentAt: isoDateTime$5.nullable()
5041
+ lastDeploymentAt: isoDateTime$7.nullable()
5001
5042
  });
5002
5043
  record(string(), ProjectListMetricsSchema);
5003
5044
  object({
@@ -5352,6 +5393,130 @@ object({
5352
5393
  skills: array(StoredRouteManifestSkillSchema).default([]),
5353
5394
  integrations: array(string()).optional()
5354
5395
  });
5396
+ const isoDateTime$6 = string().datetime();
5397
+ const subscriptionStatusSchema = _enum([
5398
+ "none",
5399
+ "trialing",
5400
+ "active",
5401
+ "past_due",
5402
+ "canceled"
5403
+ ]);
5404
+ const CreditPackSchema = object({
5405
+ id: string(),
5406
+ usd: number$1(),
5407
+ microCredits: number$1(),
5408
+ label: string()
5409
+ });
5410
+ const AutoTopupSummarySchema = object({
5411
+ enabled: boolean(),
5412
+ thresholdMicroCredits: number$1().nullable(),
5413
+ amountMicroCredits: number$1().nullable(),
5414
+ /** A saved payment method exists to charge off-session. */
5415
+ hasPaymentMethod: boolean(),
5416
+ /** A top-up invoice payment is in flight. */
5417
+ pending: boolean()
5418
+ });
5419
+ /**
5420
+ * The plan's resolved limits. Storage overage is billed from the wallet's
5421
+ * pushed-down `includedStorageGb`; concurrency, per-pass run timeouts, and
5422
+ * API/MCP rate limits are enforced from the wallet (timeouts/concurrency) or
5423
+ * plan preset (rate limits). Log retention is configured but not pruned yet.
5424
+ */
5425
+ const PlanLimitsSchema = object({
5426
+ includedStorageGb: number$1(),
5427
+ concurrencyLimit: number$1(),
5428
+ agentTimeoutMs: number$1(),
5429
+ workflowTimeoutMs: number$1(),
5430
+ pollTimeoutMs: number$1(),
5431
+ /** Configured retention window; pruning not implemented yet. */
5432
+ logRetentionDays: number$1(),
5433
+ apiRateLimitCapacity: number$1(),
5434
+ apiRateLimitRefillPerSec: number$1(),
5435
+ mcpRateLimitCapacity: number$1(),
5436
+ mcpRateLimitRefillPerSec: number$1()
5437
+ });
5438
+ object({
5439
+ planKey: string(),
5440
+ subscriptionStatus: subscriptionStatusSchema,
5441
+ planCreditMicroCredits: number$1(),
5442
+ prepaidCreditMicroCredits: number$1(),
5443
+ periodStart: isoDateTime$6.nullable(),
5444
+ periodEnd: isoDateTime$6.nullable(),
5445
+ autoTopup: AutoTopupSummarySchema,
5446
+ creditPacks: array(CreditPackSchema),
5447
+ limits: PlanLimitsSchema
5448
+ });
5449
+ const BillingUsageMeterSchema = object({
5450
+ /** Meter key (`llm`, `vm_second`, …); null groups uncategorized rows. */
5451
+ meterKey: string().nullable(),
5452
+ /** Charged this period, µc. */
5453
+ microCredits: number$1(),
5454
+ /** Tracked-but-not-charged usage (e.g. BYOK LLM calls), display USD. */
5455
+ unchargedUsd: number$1()
5456
+ });
5457
+ object({
5458
+ periodStart: isoDateTime$6.nullable(),
5459
+ periodEnd: isoDateTime$6.nullable(),
5460
+ totalMicroCredits: number$1(),
5461
+ byMeter: array(BillingUsageMeterSchema)
5462
+ });
5463
+ const billingLedgerEntryTypeSchema = _enum([
5464
+ "grant_plan",
5465
+ "grant_prepaid",
5466
+ "expire_plan",
5467
+ "adjustment"
5468
+ ]);
5469
+ object({
5470
+ entries: array(object({
5471
+ id: string(),
5472
+ entryType: billingLedgerEntryTypeSchema,
5473
+ label: string(),
5474
+ /** Signed: positive grants, negative expirations/adjustments. */
5475
+ microCredits: number$1(),
5476
+ bucket: _enum(["plan", "prepaid"]).nullable(),
5477
+ /** Stripe invoice behind the entry, when there is one — powers "View invoice". */
5478
+ stripeInvoiceId: string().nullable(),
5479
+ createdAt: isoDateTime$6
5480
+ })),
5481
+ /** Set only when the latest payment failure is newer than the latest successful payment. */
5482
+ lastPaymentFailureAt: isoDateTime$6.nullable()
5483
+ });
5484
+ object({
5485
+ /** Web-app path to land on after Checkout (must be a path, not a URL). */
5486
+ returnPath: string().startsWith("/").max(512).optional() });
5487
+ object({
5488
+ packId: string(),
5489
+ returnPath: string().startsWith("/").max(512).optional()
5490
+ });
5491
+ object({ returnPath: string().startsWith("/").max(512).optional() });
5492
+ object({ url: string().url() });
5493
+ object({
5494
+ /** Hosted invoice page (view, download, receipt). */
5495
+ url: string().url(),
5496
+ /** Direct PDF download when Stripe provides one. */
5497
+ pdf: string().url().nullable()
5498
+ });
5499
+ object({
5500
+ /** Stripe Checkout Session id from the `session_id` success-URL param. */
5501
+ sessionId: string().min(1).max(255) });
5502
+ object({
5503
+ /**
5504
+ * `granted` — credits are in the wallet now; `processing` — payment not
5505
+ * complete yet, the webhook will finish it; `ignored` — not a confirmable
5506
+ * session for this org.
5507
+ */
5508
+ status: _enum([
5509
+ "granted",
5510
+ "processing",
5511
+ "ignored"
5512
+ ]),
5513
+ reason: string().optional()
5514
+ });
5515
+ object({
5516
+ enabled: boolean(),
5517
+ thresholdMicroCredits: number$1().int().positive().optional(),
5518
+ packId: string().optional()
5519
+ });
5355
5520
  /** Messaging platforms that support agent gateway bindings. */
5356
5521
  const ChannelPlatformKeySchema = _enum(["slack"]);
5357
5522
  const ChannelReactionSupportSchema = _enum([
@@ -5872,7 +6037,11 @@ object({
5872
6037
  isDefault: boolean().optional(),
5873
6038
  value: credentialSecretValueSchema.optional()
5874
6039
  }).refine((input) => input.label !== void 0 || input.isDefault !== void 0 || input.value !== void 0, { message: "At least one field is required" });
5875
- const CredentialAssignmentTargetTypeSchema = _enum(["workflow", "agent"]);
6040
+ const CredentialAssignmentTargetTypeSchema = _enum([
6041
+ "workflow",
6042
+ "agent",
6043
+ "poll"
6044
+ ]);
5876
6045
  object({ assignments: array(object({
5877
6046
  id: string(),
5878
6047
  targetType: CredentialAssignmentTargetTypeSchema,
@@ -5987,7 +6156,11 @@ const ValidationErrorDetailSchema = object({
5987
6156
  message: string()
5988
6157
  });
5989
6158
  /** Machine-readable codes returned in standard API error bodies. */
5990
- const ErrorResponseCodeSchema = OrganizationSlugErrorCodeSchema.or(_enum(["needs_org_selection", "org_unverified"]));
6159
+ const ErrorResponseCodeSchema = OrganizationSlugErrorCodeSchema.or(_enum([
6160
+ "needs_org_selection",
6161
+ "org_unverified",
6162
+ "connector_unavailable"
6163
+ ]));
5991
6164
  object({
5992
6165
  error: string(),
5993
6166
  code: ErrorResponseCodeSchema.optional(),
@@ -6098,6 +6271,17 @@ union([
6098
6271
  SkipResponseSchema,
6099
6272
  object({ runId: string() })
6100
6273
  ]);
6274
+ object({
6275
+ sql: string().min(1),
6276
+ params: array(unknown()).default([]),
6277
+ method: string().min(1).optional()
6278
+ });
6279
+ object({ migrations: array(object({
6280
+ sql: array(string().min(1)),
6281
+ hash: string().min(1),
6282
+ folderMillis: number$1()
6283
+ })) });
6284
+ object({ results: array(object({ rows: array(unknown()) })) });
6101
6285
  const RunSourceKindSchema = _enum([
6102
6286
  "api",
6103
6287
  "trigger",
@@ -6418,12 +6602,19 @@ const HistoryRunActorSchema = object({
6418
6602
  const HistoryRunUsageLineItemSchema = object({
6419
6603
  id: string(),
6420
6604
  label: string(),
6421
- amountUsd: number$1()
6605
+ /** Amount debited from the org's Keystroke balance for this line. */
6606
+ billedUsd: number$1(),
6607
+ /** Provider cost for LLM usage on the org's API key (informational; not billed by Keystroke). */
6608
+ providerCostUsd: number$1().nullable().optional(),
6609
+ keySource: _enum(["byok", "platform"]).nullable().optional()
6422
6610
  });
6423
6611
  const HistoryRunUsageSchema = object({
6424
6612
  runDurationMs: number$1().nullable(),
6425
6613
  lineItems: array(HistoryRunUsageLineItemSchema),
6426
- totalExcludingDurationUsd: number$1().nullable()
6614
+ /** Sum of `billedUsd` — what Keystroke charged for this run. */
6615
+ totalBilledUsd: number$1().nullable(),
6616
+ /** Sum of BYOK LLM provider costs (billed externally by the org's provider). */
6617
+ externalProviderCostUsd: number$1().nullable().optional()
6427
6618
  });
6428
6619
  const HistoryRunSchema = object({
6429
6620
  id: string(),
@@ -6554,6 +6745,7 @@ const HistoryRunDetailSchema = discriminatedUnion("kind", [object({
6554
6745
  attachmentSlug: string().nullable()
6555
6746
  }).nullable(),
6556
6747
  messages: array(record(string(), unknown())),
6748
+ live: record(string(), unknown()).nullable().default(null),
6557
6749
  trace: HistoryTraceSchema.nullable(),
6558
6750
  ranAs: HistoryRunActorSchema.nullable().optional(),
6559
6751
  usage: HistoryRunUsageSchema.nullable().optional()
@@ -6843,7 +7035,7 @@ const OrganizationMemberStatusSchema = _enum([
6843
7035
  "suspended"
6844
7036
  ]);
6845
7037
  const InvitableOrganizationMemberRoleSchema = _enum(["admin", "builder"]);
6846
- const isoDateTime$4 = string().datetime();
7038
+ const isoDateTime$5 = string().datetime();
6847
7039
  object({
6848
7040
  id: string(),
6849
7041
  name: string(),
@@ -6851,8 +7043,8 @@ object({
6851
7043
  role: OrganizationMemberRoleSchema,
6852
7044
  status: OrganizationMemberStatusSchema,
6853
7045
  avatarUrl: string().optional(),
6854
- joinedAt: isoDateTime$4.optional(),
6855
- lastActiveAt: isoDateTime$4.nullable().optional()
7046
+ joinedAt: isoDateTime$5.optional(),
7047
+ lastActiveAt: isoDateTime$5.nullable().optional()
6856
7048
  });
6857
7049
  object({
6858
7050
  emails: array(string().trim().email()).min(1),
@@ -6879,7 +7071,7 @@ object({
6879
7071
  role: OrganizationMemberRoleSchema
6880
7072
  });
6881
7073
  object({ success: literal(true) });
6882
- const isoDateTime$3 = string().datetime();
7074
+ const isoDateTime$4 = string().datetime();
6883
7075
  const ApiKeyCreatorSchema = object({
6884
7076
  id: string(),
6885
7077
  name: string(),
@@ -6892,12 +7084,37 @@ const ApiKeySummarySchema = object({
6892
7084
  id: string(),
6893
7085
  name: string(),
6894
7086
  keyPreview: string(),
6895
- createdAt: isoDateTime$3,
7087
+ createdAt: isoDateTime$4,
6896
7088
  createdBy: ApiKeyCreatorSchema,
6897
7089
  isCreatedByCurrentUser: boolean()
6898
7090
  });
6899
7091
  object({ name: string().trim().min(1).max(128) });
6900
7092
  ApiKeySummarySchema.extend({ secret: string() });
7093
+ const isoDateTime$3 = string().datetime();
7094
+ const ManagedServiceKindSchema = _enum(["llm"]);
7095
+ _enum([
7096
+ "openai",
7097
+ "anthropic",
7098
+ "google",
7099
+ "groq",
7100
+ "xai"
7101
+ ]);
7102
+ object({
7103
+ id: string(),
7104
+ kind: ManagedServiceKindSchema,
7105
+ provider: string(),
7106
+ keyPreview: string(),
7107
+ createdAt: isoDateTime$3,
7108
+ updatedAt: isoDateTime$3,
7109
+ createdBy: ApiKeyCreatorSchema,
7110
+ isCreatedByCurrentUser: boolean()
7111
+ });
7112
+ object({
7113
+ kind: ManagedServiceKindSchema.default("llm"),
7114
+ provider: string().trim().min(1),
7115
+ apiKey: string().trim().min(1)
7116
+ });
7117
+ object({ apiKey: string().trim().min(1) });
6901
7118
  const ProjectUserRoleSchema = _enum(["admin", "builder"]);
6902
7119
  const ProjectInvitePermissionSchema = _enum(["admin", "all"]);
6903
7120
  const ProjectMemberStatusSchema = _enum(["active", "invited"]);
@@ -6947,6 +7164,14 @@ object({
6947
7164
  uploadUrl: url(),
6948
7165
  storageKey: string().min(1)
6949
7166
  });
7167
+ function isValidIanaTimezone(value) {
7168
+ try {
7169
+ Intl.DateTimeFormat(void 0, { timeZone: value });
7170
+ return true;
7171
+ } catch {
7172
+ return false;
7173
+ }
7174
+ }
6950
7175
  const UserInterfaceThemeSchema = _enum([
6951
7176
  "system",
6952
7177
  "light",
@@ -6966,22 +7191,25 @@ const UserWorkspaceFavoriteSchema = object({
6966
7191
  ]),
6967
7192
  resourceId: string().min(1)
6968
7193
  });
7194
+ const UserSidebarPreferencesSchema = object({
7195
+ navIconVisibility: UserSidebarNavIconVisibilitySchema,
7196
+ footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
7197
+ hiddenNavItemIds: array(string()),
7198
+ topNavItemOrderIds: array(string()),
7199
+ workspaceNavItemOrderIds: array(string())
7200
+ });
7201
+ const UserTimezoneSchema = string().refine(isValidIanaTimezone, { message: "Invalid IANA timezone" });
6969
7202
  object({
6970
7203
  interfaceTheme: UserInterfaceThemeSchema,
6971
7204
  surfaceContrast: UserSurfaceContrastSchema,
6972
7205
  layoutMode: UserWorkspaceLayoutModeSchema,
6973
7206
  fontSize: UserWorkspaceFontSizeSchema,
6974
- sidebar: object({
6975
- navIconVisibility: UserSidebarNavIconVisibilitySchema,
6976
- footerChatRowVisibility: UserSidebarFooterChatRowVisibilitySchema,
6977
- hiddenNavItemIds: array(string()),
6978
- topNavItemOrderIds: array(string()),
6979
- workspaceNavItemOrderIds: array(string())
6980
- }),
7207
+ sidebar: UserSidebarPreferencesSchema,
6981
7208
  favorites: array(UserWorkspaceFavoriteSchema),
6982
7209
  projectOrderIds: array(string()),
6983
7210
  projectDotColors: record(string(), string()),
6984
- onboardingTabVisible: boolean()
7211
+ onboardingTabVisible: boolean(),
7212
+ timezone: union([UserTimezoneSchema, _null()])
6985
7213
  });
6986
7214
  const UserSidebarPreferencesPatchSchema = object({
6987
7215
  navIconVisibility: UserSidebarNavIconVisibilitySchema.optional(),
@@ -6999,8 +7227,9 @@ object({
6999
7227
  favorites: array(UserWorkspaceFavoriteSchema).optional(),
7000
7228
  projectOrderIds: array(string()).optional(),
7001
7229
  projectDotColors: record(string(), string()).optional(),
7002
- onboardingTabVisible: boolean().optional()
7003
- }).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" });
7230
+ onboardingTabVisible: boolean().optional(),
7231
+ timezone: union([UserTimezoneSchema, _null()]).optional()
7232
+ }).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" });
7004
7233
  const OrganizationLogoVariantSchema = _enum(["light", "dark"]);
7005
7234
  object({
7006
7235
  customLogoEnabled: boolean(),
@@ -7463,13 +7692,35 @@ function parseOrgArtifactsFromEnv(env = process.env) {
7463
7692
  });
7464
7693
  }
7465
7694
  //#endregion
7695
+ //#region src/org-worker-token.ts
7696
+ function sign(secret, organizationId) {
7697
+ return (0, node_crypto.createHmac)("sha256", secret).update(`org-worker:${organizationId}`).digest("base64url");
7698
+ }
7699
+ /**
7700
+ * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the
7701
+ * platform can tell which org a machine is calling as, and stateless — verified
7702
+ * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.
7703
+ */
7704
+ function mintOrgWorkerToken(secret, organizationId) {
7705
+ return `${organizationId}.${sign(secret, organizationId)}`;
7706
+ }
7707
+ function verifyOrgWorkerToken(secret, token) {
7708
+ if (!secret || !token) return;
7709
+ const separator = token.lastIndexOf(".");
7710
+ if (separator <= 0) return;
7711
+ const organizationId = token.slice(0, separator);
7712
+ const signature = Buffer.from(token.slice(separator + 1));
7713
+ const expected = Buffer.from(sign(secret, organizationId));
7714
+ if (signature.length !== expected.length || !(0, node_crypto.timingSafeEqual)(signature, expected)) return;
7715
+ return { organizationId };
7716
+ }
7717
+ //#endregion
7466
7718
  //#region src/runtime-env.ts
7467
7719
  const RUNTIME_ENV_KEYS = [
7468
7720
  "BETTER_AUTH_SECRET",
7469
7721
  "PUBLIC_PLATFORM_URL",
7470
7722
  "PUBLIC_PLATFORM_PROXY_URL",
7471
7723
  "PUBLIC_WEB_URL",
7472
- "POSTGRES_SSL",
7473
7724
  "UPSTASH_REDIS_URL",
7474
7725
  "REDIS_URL",
7475
7726
  "KEYSTROKE_QUEUE_PREFIX"
@@ -7483,25 +7734,6 @@ const PROVIDER_ENV_KEYS = [
7483
7734
  ];
7484
7735
  /** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
7485
7736
  const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
7486
- const PROJECT_DATABASE_ENV_KEYS = [
7487
- "POSTGRES_HOST",
7488
- "POSTGRES_PORT",
7489
- "POSTGRES_DB",
7490
- "POSTGRES_USER",
7491
- "POSTGRES_PASSWORD",
7492
- "DATABASE_SEARCH_PATH"
7493
- ];
7494
- /** Per-project postgres env injected into every project server container/machine. */
7495
- function projectDatabaseRuntimeEnv(database) {
7496
- return {
7497
- POSTGRES_HOST: rewriteLoopbackHost(database.host),
7498
- POSTGRES_PORT: String(database.port),
7499
- POSTGRES_DB: database.database,
7500
- POSTGRES_USER: database.user,
7501
- POSTGRES_PASSWORD: database.password,
7502
- DATABASE_SEARCH_PATH: database.searchPath
7503
- };
7504
- }
7505
7737
  /**
7506
7738
  * Builds the launch spec for an org worker. Each deploy artifact is encoded in
7507
7739
  * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.
@@ -7528,10 +7760,7 @@ function buildRuntimeEnv(source, artifacts, database, extraEnv) {
7528
7760
  ]);
7529
7761
  for (const key of RUNTIME_ENV_KEYS) {
7530
7762
  const value = source[key]?.trim();
7531
- if (!value) {
7532
- if (key === "POSTGRES_SSL") throw new Error("POSTGRES_SSL is required");
7533
- continue;
7534
- }
7763
+ if (!value) continue;
7535
7764
  entries.set(key, value);
7536
7765
  }
7537
7766
  if (!extraEnv) for (const key of PROVIDER_ENV_KEYS) {
@@ -7540,8 +7769,7 @@ function buildRuntimeEnv(source, artifacts, database, extraEnv) {
7540
7769
  }
7541
7770
  const worker = resolveWorkerRuntimeConfig(source);
7542
7771
  entries.set("PLATFORM_URL", worker.platformUrl);
7543
- entries.set("WORKER_INTERNAL_TOKEN", worker.workerToken);
7544
- for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) entries.set(key, value);
7772
+ entries.set("WORKER_INTERNAL_TOKEN", mintOrgWorkerToken(worker.workerToken, database.organizationId));
7545
7773
  if (extraEnv) for (const [key, value] of Object.entries(extraEnv)) entries.set(key, value);
7546
7774
  return Object.fromEntries(entries);
7547
7775
  }
@@ -7629,55 +7857,63 @@ function sleep(ms) {
7629
7857
  const MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? "keystroke";
7630
7858
  function createDockerRuntime(options = {}) {
7631
7859
  const docker = options.docker ?? new dockerode.default();
7632
- return { async start(input) {
7633
- if (input.projects.length === 0) throw new Error("Docker org runtime requires at least one project deploy");
7634
- let launch = resolveRuntimeLaunch(options, input.projects.map((project) => ({
7635
- projectId: project.projectId,
7636
- artifactStorageKey: project.artifactStorageKey
7637
- })), input.database, input.env);
7638
- if (options.workspacesMount) {
7639
- const { hostPath, containerPath } = options.workspacesMount;
7640
- await (0, node_fs_promises.mkdir)(hostPath, { recursive: true });
7641
- launch = {
7642
- ...launch,
7643
- env: {
7644
- ...launch.env,
7645
- KEYSTROKE_WORKSPACES_ROOT: containerPath
7646
- }
7860
+ return {
7861
+ async start(input) {
7862
+ if (input.projects.length === 0) throw new Error("Docker org runtime requires at least one project deploy");
7863
+ let launch = resolveRuntimeLaunch(options, input.projects.map((project) => ({
7864
+ projectId: project.projectId,
7865
+ artifactStorageKey: project.artifactStorageKey
7866
+ })), input.database, input.env);
7867
+ if (options.workspacesMount) {
7868
+ const { hostPath, containerPath } = options.workspacesMount;
7869
+ await (0, node_fs_promises.mkdir)(hostPath, { recursive: true });
7870
+ launch = {
7871
+ ...launch,
7872
+ env: {
7873
+ ...launch.env,
7874
+ KEYSTROKE_WORKSPACES_ROOT: containerPath
7875
+ }
7876
+ };
7877
+ }
7878
+ await ensureImage(docker, launch.image);
7879
+ await removeExistingContainer(docker, input.organizationId);
7880
+ const binds = [...options.workspacesMount ? [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] : [], ...options.extraBinds ?? []];
7881
+ const container = await docker.createContainer({
7882
+ Image: launch.image,
7883
+ name: containerName(input.organizationId),
7884
+ Labels: {
7885
+ "keystroke.organization.id": input.organizationId,
7886
+ "keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
7887
+ },
7888
+ ExposedPorts: { [`${launch.port}/tcp`]: {} },
7889
+ HostConfig: {
7890
+ ExtraHosts: ["host.docker.internal:host-gateway"],
7891
+ PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
7892
+ ...binds.length > 0 ? { Binds: binds } : {}
7893
+ },
7894
+ NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
7895
+ Env: formatDockerEnv(launch.env)
7896
+ });
7897
+ await container.start();
7898
+ const inspect = await container.inspect();
7899
+ const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
7900
+ if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
7901
+ const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
7902
+ await waitForHealth(baseUrl, {
7903
+ fetchImpl: options.fetchImpl,
7904
+ timeoutMs: options.healthTimeoutMs
7905
+ });
7906
+ return {
7907
+ runtimeId: inspect.Id,
7908
+ baseUrl
7647
7909
  };
7910
+ },
7911
+ async destroy(input) {
7912
+ try {
7913
+ await docker.getContainer(input.runtimeId).remove({ force: true });
7914
+ } catch {}
7648
7915
  }
7649
- await ensureImage(docker, launch.image);
7650
- await removeExistingContainer(docker, input.organizationId);
7651
- const container = await docker.createContainer({
7652
- Image: launch.image,
7653
- name: containerName(input.organizationId),
7654
- Labels: {
7655
- "keystroke.organization.id": input.organizationId,
7656
- "keystroke.project.ids": input.projects.map((project) => project.projectId).join(",")
7657
- },
7658
- ExposedPorts: { [`${launch.port}/tcp`]: {} },
7659
- HostConfig: {
7660
- ExtraHosts: ["host.docker.internal:host-gateway"],
7661
- PortBindings: { [`${launch.port}/tcp`]: [{ HostPort: "0" }] },
7662
- ...options.workspacesMount ? { Binds: [`${options.workspacesMount.hostPath}:${options.workspacesMount.containerPath}`] } : {}
7663
- },
7664
- NetworkingConfig: { EndpointsConfig: { [MINIO_DOCKER_NETWORK]: {} } },
7665
- Env: formatDockerEnv(launch.env)
7666
- });
7667
- await container.start();
7668
- const inspect = await container.inspect();
7669
- const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];
7670
- if (!binding?.HostPort) throw new Error("Failed to resolve org container host port");
7671
- const baseUrl = `http://127.0.0.1:${binding.HostPort}`;
7672
- await waitForHealth(baseUrl, {
7673
- fetchImpl: options.fetchImpl,
7674
- timeoutMs: options.healthTimeoutMs
7675
- });
7676
- return {
7677
- runtimeId: inspect.Id,
7678
- baseUrl
7679
- };
7680
- } };
7916
+ };
7681
7917
  }
7682
7918
  function containerName(organizationId) {
7683
7919
  return `keystroke-org-${organizationId}`;
@@ -7786,7 +8022,6 @@ async function fetchDeployStatus(baseUrl, options = {}) {
7786
8022
  }
7787
8023
  //#endregion
7788
8024
  exports.DEV_PLATFORM_WORKER_TOKEN = DEV_PLATFORM_WORKER_TOKEN;
7789
- exports.PROJECT_DATABASE_ENV_KEYS = PROJECT_DATABASE_ENV_KEYS;
7790
8025
  exports.PROJECT_SERVER_DEPLOY_STATUS = PROJECT_SERVER_DEPLOY_STATUS;
7791
8026
  exports.PROJECT_SERVER_FRAMEWORK_NODE_MODULES = PROJECT_SERVER_FRAMEWORK_NODE_MODULES;
7792
8027
  exports.PROJECT_SERVER_FRAMEWORK_ROOT = PROJECT_SERVER_FRAMEWORK_ROOT;
@@ -7803,10 +8038,10 @@ exports.dockerPlugin = dockerPlugin;
7803
8038
  exports.encodeOrgArtifacts = encodeOrgArtifacts;
7804
8039
  exports.fetchDeployStatus = fetchDeployStatus;
7805
8040
  exports.formatDockerEnv = formatDockerEnv;
8041
+ exports.mintOrgWorkerToken = mintOrgWorkerToken;
7806
8042
  exports.parseOrgArtifactsFromEnv = parseOrgArtifactsFromEnv;
7807
8043
  exports.pingProject = pingProject;
7808
8044
  exports.pingProjectTarget = pingProjectTarget;
7809
- exports.projectDatabaseRuntimeEnv = projectDatabaseRuntimeEnv;
7810
8045
  exports.resolvePlatformWorkerToken = resolvePlatformWorkerToken;
7811
8046
  exports.resolveProjectServerImage = resolveProjectServerImage;
7812
8047
  exports.resolveRuntimeLaunch = resolveRuntimeLaunch;
@@ -7814,6 +8049,7 @@ exports.resolveWorkerPlatformUrl = resolveWorkerPlatformUrl;
7814
8049
  exports.resolveWorkerRuntimeConfig = resolveWorkerRuntimeConfig;
7815
8050
  exports.rewriteLoopbackHost = rewriteLoopbackHost;
7816
8051
  exports.rewriteLoopbackUrl = rewriteLoopbackUrl;
8052
+ exports.verifyOrgWorkerToken = verifyOrgWorkerToken;
7817
8053
  exports.waitForHealth = waitForHealth;
7818
8054
 
7819
8055
  //# sourceMappingURL=index.cjs.map