@absolutejs/absolute 0.19.0-beta.674 → 0.19.0-beta.676

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/cli/index.js CHANGED
@@ -242,9 +242,9 @@ var RESERVED_TOP_LEVEL_KEYS, isObject = (value) => typeof value === "object" &&
242
242
  cwd: _cwd,
243
243
  dependsOn: _dependsOn,
244
244
  env: _env,
245
- healthcheck: _healthcheck,
246
245
  kind: _kind,
247
246
  port: _port,
247
+ ready: _ready,
248
248
  visibility: _visibility,
249
249
  ...serviceConfig
250
250
  } = service;
@@ -284,7 +284,6 @@ var init_loadConfig = __esm(() => {
284
284
  "dev",
285
285
  "entry",
286
286
  "env",
287
- "healthcheck",
288
287
  "htmlDirectory",
289
288
  "htmxDirectory",
290
289
  "images",
@@ -301,6 +300,7 @@ var init_loadConfig = __esm(() => {
301
300
  "stylesConfig",
302
301
  "svelteDirectory",
303
302
  "tailwind",
303
+ "ready",
304
304
  "visibility",
305
305
  "vueDirectory"
306
306
  ]);
@@ -2482,6 +2482,7 @@ init_constants();
2482
2482
  init_loadConfig();
2483
2483
  init_getDurationString();
2484
2484
  import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
2485
+ import { createConnection } from "net";
2485
2486
  import { resolve as resolve6 } from "path";
2486
2487
 
2487
2488
  // src/cli/workspaceTui.ts
@@ -3051,50 +3052,164 @@ var getServiceUrl = (service) => {
3051
3052
  if (!service.port) {
3052
3053
  return null;
3053
3054
  }
3054
- return `http://localhost:${service.port}/`;
3055
+ return `${getServiceProtocol(service)}://${getServicePublicHost(service)}:${service.port}/`;
3055
3056
  };
3056
- var getHealthcheckUrl = (service) => {
3057
- if (service.healthcheck) {
3058
- return service.healthcheck;
3059
- }
3057
+ var getDefaultReadyConfig = (service) => {
3060
3058
  if (isAbsoluteService(service) && service.port) {
3061
- return `http://127.0.0.1:${service.port}/hmr-status`;
3059
+ return "/hmr-status";
3062
3060
  }
3063
3061
  return;
3064
3062
  };
3065
- var resolveHealthcheck = (healthcheck) => {
3066
- if (!healthcheck) {
3067
- return null;
3063
+ var normalizeExpectedStatuses = (value) => Array.isArray(value) ? value : [value ?? 200];
3064
+ var resolveServiceHttpUrl = (service, path) => {
3065
+ if (!path.startsWith("/")) {
3066
+ throw new Error(`ready path must start with "/" for service probes. Received "${path}".`);
3067
+ }
3068
+ if (!service.port) {
3069
+ throw new Error(`ready path "${path}" requires the service to define a port.`);
3068
3070
  }
3069
- if (typeof healthcheck === "string") {
3071
+ return `${getServiceProtocol(service)}://${getServicePublicHost(service)}:${service.port}${path}`;
3072
+ };
3073
+ var resolveHttpReadyProbe = (service, ready) => {
3074
+ if (typeof ready === "string") {
3075
+ if (isAbsoluteService(service)) {
3076
+ return {
3077
+ type: "http",
3078
+ url: resolveServiceHttpUrl(service, ready),
3079
+ method: "GET",
3080
+ expectStatus: [200],
3081
+ headers: {},
3082
+ intervalMs: 250,
3083
+ timeoutMs: 30000
3084
+ };
3085
+ }
3070
3086
  return {
3087
+ type: "http",
3088
+ url: ready,
3089
+ method: "GET",
3090
+ expectStatus: [200],
3091
+ headers: {},
3071
3092
  intervalMs: 250,
3072
- timeoutMs: 30000,
3073
- url: healthcheck
3093
+ timeoutMs: 30000
3074
3094
  };
3075
3095
  }
3096
+ if (ready.path && ready.url) {
3097
+ throw new Error('ready HTTP probe cannot define both "path" and "url".');
3098
+ }
3099
+ const url = ready.path ? resolveServiceHttpUrl(service, ready.path) : ready.url ? ready.url : isAbsoluteService(service) ? resolveServiceHttpUrl(service, "/hmr-status") : null;
3100
+ if (!url) {
3101
+ throw new Error('ready HTTP probe requires either "url" or "path".');
3102
+ }
3076
3103
  return {
3077
- intervalMs: healthcheck.intervalMs ?? 250,
3078
- timeoutMs: healthcheck.timeoutMs ?? 30000,
3079
- url: healthcheck.url
3104
+ type: "http",
3105
+ url,
3106
+ method: ready.method ?? "GET",
3107
+ expectStatus: normalizeExpectedStatuses(ready.expectStatus),
3108
+ headers: ready.headers ?? {},
3109
+ intervalMs: ready.intervalMs ?? 250,
3110
+ timeoutMs: ready.timeoutMs ?? 30000
3080
3111
  };
3081
3112
  };
3082
- var waitForHealthcheck = async (healthcheck) => {
3083
- const resolved = resolveHealthcheck(healthcheck);
3113
+ var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig(service)) => {
3114
+ if (ready === false || !ready) {
3115
+ return null;
3116
+ }
3117
+ if (typeof ready === "string") {
3118
+ return resolveHttpReadyProbe(service, ready);
3119
+ }
3120
+ if (ready.type === "tcp") {
3121
+ return {
3122
+ type: "tcp",
3123
+ host: ready.host ?? getServicePublicHost(service),
3124
+ port: ready.port,
3125
+ intervalMs: ready.intervalMs ?? 250,
3126
+ timeoutMs: ready.timeoutMs ?? 30000
3127
+ };
3128
+ }
3129
+ if (ready.type === "command") {
3130
+ return {
3131
+ type: "command",
3132
+ command: ready.command,
3133
+ intervalMs: ready.intervalMs ?? 250,
3134
+ timeoutMs: ready.timeoutMs ?? 30000
3135
+ };
3136
+ }
3137
+ if (ready.type === "delay") {
3138
+ return {
3139
+ type: "delay",
3140
+ ms: ready.ms
3141
+ };
3142
+ }
3143
+ return resolveHttpReadyProbe(service, ready);
3144
+ };
3145
+ var probeHttpReady = async (ready) => {
3146
+ const response = await fetch(ready.url, {
3147
+ method: ready.method,
3148
+ headers: ready.headers,
3149
+ signal: AbortSignal.timeout(Math.min(ready.timeoutMs, 5000))
3150
+ });
3151
+ return ready.expectStatus.includes(response.status);
3152
+ };
3153
+ var probeTcpReady = async (ready) => new Promise((resolveProbe) => {
3154
+ const socket = createConnection({
3155
+ host: ready.host,
3156
+ port: ready.port
3157
+ });
3158
+ const timeout = setTimeout(() => {
3159
+ socket.destroy();
3160
+ resolveProbe(false);
3161
+ }, Math.min(ready.timeoutMs, 5000));
3162
+ socket.once("connect", () => {
3163
+ clearTimeout(timeout);
3164
+ socket.end();
3165
+ resolveProbe(true);
3166
+ });
3167
+ socket.once("error", () => {
3168
+ clearTimeout(timeout);
3169
+ socket.destroy();
3170
+ resolveProbe(false);
3171
+ });
3172
+ });
3173
+ var probeCommandReady = async (ready, service) => {
3174
+ const processHandle = Bun.spawn(ready.command, {
3175
+ cwd: service.cwd,
3176
+ env: service.env,
3177
+ stderr: "ignore",
3178
+ stdin: "ignore",
3179
+ stdout: "ignore"
3180
+ });
3181
+ const timeout = setTimeout(() => {
3182
+ try {
3183
+ processHandle.kill();
3184
+ } catch {}
3185
+ }, Math.min(ready.timeoutMs, 5000));
3186
+ try {
3187
+ const exitCode = await processHandle.exited;
3188
+ return exitCode === 0;
3189
+ } finally {
3190
+ clearTimeout(timeout);
3191
+ }
3192
+ };
3193
+ var waitForReady = async (service) => {
3194
+ const resolved = resolveReadyProbe(service.service);
3084
3195
  if (!resolved) {
3085
3196
  return;
3086
3197
  }
3198
+ if (resolved.type === "delay") {
3199
+ await sleep(resolved.ms);
3200
+ return;
3201
+ }
3087
3202
  const startedAt = Date.now();
3088
3203
  while (Date.now() - startedAt < resolved.timeoutMs) {
3089
3204
  try {
3090
- const response = await fetch(resolved.url);
3091
- if (response.ok) {
3205
+ const isReady = resolved.type === "http" ? await probeHttpReady(resolved) : resolved.type === "tcp" ? await probeTcpReady(resolved) : await probeCommandReady(resolved, service);
3206
+ if (isReady) {
3092
3207
  return;
3093
3208
  }
3094
3209
  } catch {}
3095
3210
  await sleep(resolved.intervalMs);
3096
3211
  }
3097
- throw new Error(`service did not become healthy within ${resolved.timeoutMs}ms (${resolved.url})`);
3212
+ throw new Error(resolved.type === "http" ? `service did not become ready within ${resolved.timeoutMs}ms (${resolved.url})` : resolved.type === "tcp" ? `service did not become ready within ${resolved.timeoutMs}ms (tcp://${resolved.host}:${resolved.port})` : `service did not become ready within ${resolved.timeoutMs}ms (${resolved.command.join(" ")})`);
3098
3213
  };
3099
3214
  var topologicallySortServices = (services) => {
3100
3215
  const ordered = [];
@@ -3161,10 +3276,30 @@ var pipeProcessLogs = (name, processHandle, appendLog) => {
3161
3276
  forward(processHandle.stdout, "info");
3162
3277
  forward(processHandle.stderr, "error");
3163
3278
  };
3164
- var resolveService = (name, service, options) => {
3279
+ var getServicePublicHost = (service) => {
3280
+ const host = service.env?.HOST ?? process.env.HOST ?? "localhost";
3281
+ if (host === "0.0.0.0" || host === "::") {
3282
+ return "localhost";
3283
+ }
3284
+ return host;
3285
+ };
3286
+ var getServiceProtocol = (service) => service.env?.ABSOLUTE_HTTPS === "true" || process.env.ABSOLUTE_HTTPS === "true" ? "https" : "http";
3287
+ var createWorkspaceServiceEnv = (services) => {
3288
+ const workspaceEnv = {};
3289
+ for (const [name, service] of Object.entries(services)) {
3290
+ if (!service.port) {
3291
+ continue;
3292
+ }
3293
+ const envKey = `ABSOLUTE_SERVICE_${name.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_URL`;
3294
+ workspaceEnv[envKey] = `${getServiceProtocol(service)}://${getServicePublicHost(service)}:${service.port}`;
3295
+ }
3296
+ return workspaceEnv;
3297
+ };
3298
+ var resolveService = (name, service, workspaceEnv, options) => {
3165
3299
  const cwd = resolve6(service.cwd ?? ".");
3166
3300
  const envVars = {
3167
3301
  ...process.env,
3302
+ ...workspaceEnv,
3168
3303
  ...service.env,
3169
3304
  ABSOLUTE_WORKSPACE_MANAGED: "1",
3170
3305
  ABSOLUTE_WORKSPACE_SERVICE_NAME: name,
@@ -3211,6 +3346,7 @@ var workspace = async (subcommand, options) => {
3211
3346
  }
3212
3347
  const config = await loadRawConfig(options.configPath);
3213
3348
  const services = getWorkspaceServices(config);
3349
+ const workspaceEnv = createWorkspaceServiceEnv(services);
3214
3350
  const orderedNames = topologicallySortServices(services);
3215
3351
  const running = [];
3216
3352
  const serviceBootStartedAt = new Map;
@@ -3283,7 +3419,7 @@ var workspace = async (subcommand, options) => {
3283
3419
  if (!service) {
3284
3420
  throw new Error(`services is missing "${name}"`);
3285
3421
  }
3286
- const resolved = resolveService(name, service, options);
3422
+ const resolved = resolveService(name, service, workspaceEnv, options);
3287
3423
  const port = (resolved.service.port ?? Number(resolved.env.PORT ?? "")) || DEFAULT_PORT;
3288
3424
  if (port > 0) {
3289
3425
  killStaleProcesses(port, (message) => {
@@ -3320,7 +3456,7 @@ var workspace = async (subcommand, options) => {
3320
3456
  tui.addLog("workspace", `${name} exited with code ${exitCode || 1}. Shutting down workspace.`, "error");
3321
3457
  shutdown(exitCode || 1);
3322
3458
  });
3323
- await waitForHealthcheck(getHealthcheckUrl(resolved.service));
3459
+ await waitForReady(resolved);
3324
3460
  const startedAt = serviceBootStartedAt.get(name);
3325
3461
  const readyDuration = typeof startedAt === "number" ? `ready in ${getDurationString(performance.now() - startedAt)}` : undefined;
3326
3462
  tui.setServiceStatus(name, "ready", readyDuration);
package/dist/index.js CHANGED
@@ -174803,7 +174803,7 @@ ${registrations}
174803
174803
  ({ tsLibDir } = cached);
174804
174804
  cached.lastUsed = Date.now();
174805
174805
  } else {
174806
- const tsPath = __require.resolve("/home/alexkahn/abs/absolutejs/node_modules/typescript/lib/typescript.js");
174806
+ const tsPath = __require.resolve("typescript");
174807
174807
  const tsRootDir = dirname9(tsPath);
174808
174808
  tsLibDir = tsRootDir.endsWith("lib") ? tsRootDir : resolve18(tsRootDir, "lib");
174809
174809
  const config = readConfiguration("./tsconfig.json");
@@ -181936,7 +181936,6 @@ var RESERVED_TOP_LEVEL_KEYS = new Set([
181936
181936
  "dev",
181937
181937
  "entry",
181938
181938
  "env",
181939
- "healthcheck",
181940
181939
  "htmlDirectory",
181941
181940
  "htmxDirectory",
181942
181941
  "images",
@@ -181953,6 +181952,7 @@ var RESERVED_TOP_LEVEL_KEYS = new Set([
181953
181952
  "stylesConfig",
181954
181953
  "svelteDirectory",
181955
181954
  "tailwind",
181955
+ "ready",
181956
181956
  "visibility",
181957
181957
  "vueDirectory"
181958
181958
  ]);
@@ -181993,9 +181993,9 @@ var projectServiceConfig = (config, serviceName) => {
181993
181993
  cwd: _cwd,
181994
181994
  dependsOn: _dependsOn,
181995
181995
  env: _env,
181996
- healthcheck: _healthcheck,
181997
181996
  kind: _kind,
181998
181997
  port: _port,
181998
+ ready: _ready,
181999
181999
  visibility: _visibility,
182000
182000
  ...serviceConfig
182001
182001
  } = service;
@@ -188898,5 +188898,5 @@ export {
188898
188898
  ANGULAR_INIT_TIMEOUT_MS
188899
188899
  };
188900
188900
 
188901
- //# debugId=98967D2F4839D93264756E2164756E21
188901
+ //# debugId=97D769D373BB628F64756E2164756E21
188902
188902
  //# sourceMappingURL=index.js.map