@crossdelta/infrastructure 0.2.20 → 0.2.22

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.
@@ -1,11 +1,27 @@
1
1
  import type { Output } from '@pulumi/pulumi';
2
+ /**
3
+ * Gets the full GHCR image URL for a service.
4
+ *
5
+ * @param registry - The GHCR registry/org name (e.g., 'orderboss')
6
+ * @param serviceName - The service name (e.g., 'storefront', 'api-gateway')
7
+ * @returns Full image URL (e.g., 'ghcr.io/orderboss/storefront:abc123')
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const config: K8sServiceConfig = {
12
+ * name: 'storefront',
13
+ * image: ghcrImage('orderboss', 'storefront'),
14
+ * }
15
+ * ```
16
+ */
17
+ export declare const ghcrImage: (registry: string, serviceName: string) => string;
2
18
  /**
3
19
  * Gets the image configuration for a given repository.
4
20
  * @param repository - The name of the repository.
5
21
  * @returns The image configuration.
6
- * @deprecated Use project-specific config helper instead
22
+ * @deprecated Use ghcrImage instead
7
23
  */
8
- export declare const getImage: (repository: string, registryCredentials: Output<string>) => {
24
+ export declare const getImage: (registry: string, repository: string, registryCredentials: Output<string>) => {
9
25
  registryType: any;
10
26
  registry: string;
11
27
  repository: string;
@@ -5,6 +5,8 @@ export interface BuildServicesOptions {
5
5
  serviceConfigs: ServiceConfig[];
6
6
  registryCredentials: Output<string>;
7
7
  logtailToken: Output<string>;
8
+ /** GHCR registry/org name (e.g., 'orderboss') */
9
+ registry: string;
8
10
  }
9
11
  /**
10
12
  * Builds the services array from service configs.
package/dist/index.cjs CHANGED
@@ -337013,6 +337013,7 @@ var require_kubernetes = __commonJS((exports2) => {
337013
337013
  // lib/index.ts
337014
337014
  var exports_lib = {};
337015
337015
  __export(exports_lib, {
337016
+ ghcrImage: () => ghcrImage,
337016
337017
  getServiceUrl: () => getServiceUrl,
337017
337018
  getServicePort: () => getServicePort2,
337018
337019
  getImage: () => getImage,
@@ -337360,19 +337361,22 @@ var scopeImageTags = (() => {
337360
337361
  var resolveImageTag = (scopeName) => {
337361
337362
  const tag = scopeImageTags[scopeName];
337362
337363
  if (!tag) {
337363
- console.warn(`No image tag for "${scopeName}", using "latest" as fallback`);
337364
337364
  return "latest";
337365
337365
  }
337366
337366
  return tag;
337367
337367
  };
337368
- var getImage = (repository, registryCredentials) => {
337368
+ var ghcrImage = (registry, serviceName) => {
337369
+ const tag = resolveImageTag(serviceName);
337370
+ return `ghcr.io/${registry}/${serviceName}:${tag}`;
337371
+ };
337372
+ var getImage = (registry, repository, registryCredentials) => {
337369
337373
  const scopeName = repository.split("/").pop();
337370
337374
  if (!scopeName) {
337371
337375
  throw new Error(`Invalid repository name: ${repository}`);
337372
337376
  }
337373
337377
  return {
337374
337378
  registryType: "GHCR",
337375
- registry: "orderboss",
337379
+ registry,
337376
337380
  repository,
337377
337381
  registryCredentials,
337378
337382
  tag: resolveImageTag(scopeName)
@@ -337380,7 +337384,7 @@ var getImage = (repository, registryCredentials) => {
337380
337384
  };
337381
337385
  // lib/helpers/service-builder.ts
337382
337386
  function buildServices(options) {
337383
- const { serviceConfigs, registryCredentials, logtailToken } = options;
337387
+ const { serviceConfigs, registryCredentials, logtailToken, registry } = options;
337384
337388
  const logDestinations = createLogDestinations(logtailToken);
337385
337389
  const sortedConfigs = [...serviceConfigs].sort((a, b) => {
337386
337390
  if (a.ingressPrefix === "/")
@@ -337400,7 +337404,7 @@ function buildServices(options) {
337400
337404
  runCommand: _runCommand,
337401
337405
  ...serviceConfig
337402
337406
  } = config;
337403
- const image = configImage ?? getImage(`platform/${config.name}`, registryCredentials);
337407
+ const image = configImage ?? getImage(registry, config.name, registryCredentials);
337404
337408
  return {
337405
337409
  healthCheck: defaultHealthCheck,
337406
337410
  alerts: defaultAlerts,
@@ -338028,6 +338032,15 @@ function deployK8sService(provider, namespace, config2) {
338028
338032
  if (config2.ingress.tls?.enabled) {
338029
338033
  ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
338030
338034
  }
338035
+ let ingressPath = config2.ingress.path;
338036
+ let ingressPathType = config2.ingress.pathType ?? "Prefix";
338037
+ const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
338038
+ if (shouldStripPrefix) {
338039
+ ingressPath = `${config2.ingress.path}(/|$)(.*)`;
338040
+ ingressPathType = "ImplementationSpecific";
338041
+ ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
338042
+ ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
338043
+ }
338031
338044
  const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
338032
338045
  const ingressRules = [];
338033
338046
  const createRule = (host) => ({
@@ -338035,8 +338048,8 @@ function deployK8sService(provider, namespace, config2) {
338035
338048
  http: {
338036
338049
  paths: [
338037
338050
  {
338038
- path: config2.ingress.path,
338039
- pathType: config2.ingress.pathType ?? "Prefix",
338051
+ path: ingressPath,
338052
+ pathType: ingressPathType,
338040
338053
  backend: {
338041
338054
  service: {
338042
338055
  name: config2.name,
package/dist/index.js CHANGED
@@ -337285,19 +337285,22 @@ var scopeImageTags = (() => {
337285
337285
  var resolveImageTag = (scopeName) => {
337286
337286
  const tag = scopeImageTags[scopeName];
337287
337287
  if (!tag) {
337288
- console.warn(`No image tag for "${scopeName}", using "latest" as fallback`);
337289
337288
  return "latest";
337290
337289
  }
337291
337290
  return tag;
337292
337291
  };
337293
- var getImage = (repository, registryCredentials) => {
337292
+ var ghcrImage = (registry, serviceName) => {
337293
+ const tag = resolveImageTag(serviceName);
337294
+ return `ghcr.io/${registry}/${serviceName}:${tag}`;
337295
+ };
337296
+ var getImage = (registry, repository, registryCredentials) => {
337294
337297
  const scopeName = repository.split("/").pop();
337295
337298
  if (!scopeName) {
337296
337299
  throw new Error(`Invalid repository name: ${repository}`);
337297
337300
  }
337298
337301
  return {
337299
337302
  registryType: "GHCR",
337300
- registry: "orderboss",
337303
+ registry,
337301
337304
  repository,
337302
337305
  registryCredentials,
337303
337306
  tag: resolveImageTag(scopeName)
@@ -337305,7 +337308,7 @@ var getImage = (repository, registryCredentials) => {
337305
337308
  };
337306
337309
  // lib/helpers/service-builder.ts
337307
337310
  function buildServices(options) {
337308
- const { serviceConfigs, registryCredentials, logtailToken } = options;
337311
+ const { serviceConfigs, registryCredentials, logtailToken, registry } = options;
337309
337312
  const logDestinations = createLogDestinations(logtailToken);
337310
337313
  const sortedConfigs = [...serviceConfigs].sort((a, b) => {
337311
337314
  if (a.ingressPrefix === "/")
@@ -337325,7 +337328,7 @@ function buildServices(options) {
337325
337328
  runCommand: _runCommand,
337326
337329
  ...serviceConfig
337327
337330
  } = config;
337328
- const image = configImage ?? getImage(`platform/${config.name}`, registryCredentials);
337331
+ const image = configImage ?? getImage(registry, config.name, registryCredentials);
337329
337332
  return {
337330
337333
  healthCheck: defaultHealthCheck,
337331
337334
  alerts: defaultAlerts,
@@ -337953,6 +337956,15 @@ function deployK8sService(provider, namespace, config2) {
337953
337956
  if (config2.ingress.tls?.enabled) {
337954
337957
  ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
337955
337958
  }
337959
+ let ingressPath = config2.ingress.path;
337960
+ let ingressPathType = config2.ingress.pathType ?? "Prefix";
337961
+ const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
337962
+ if (shouldStripPrefix) {
337963
+ ingressPath = `${config2.ingress.path}(/|$)(.*)`;
337964
+ ingressPathType = "ImplementationSpecific";
337965
+ ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
337966
+ ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
337967
+ }
337956
337968
  const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
337957
337969
  const ingressRules = [];
337958
337970
  const createRule = (host) => ({
@@ -337960,8 +337972,8 @@ function deployK8sService(provider, namespace, config2) {
337960
337972
  http: {
337961
337973
  paths: [
337962
337974
  {
337963
- path: config2.ingress.path,
337964
- pathType: config2.ingress.pathType ?? "Prefix",
337975
+ path: ingressPath,
337976
+ pathType: ingressPathType,
337965
337977
  backend: {
337966
337978
  service: {
337967
337979
  name: config2.name,
@@ -338046,6 +338058,7 @@ function buildInternalUrl(serviceName, namespace, port) {
338046
338058
  return `http://${serviceName}.${namespace}.svc.cluster.local:${port}`;
338047
338059
  }
338048
338060
  export {
338061
+ ghcrImage,
338049
338062
  getServiceUrl,
338050
338063
  getServicePort2 as getServicePort,
338051
338064
  getImage,
@@ -116,8 +116,18 @@ export interface K8sHealthCheck {
116
116
  export interface K8sIngressConfig {
117
117
  /** Path prefix for routing (e.g., '/', '/api') */
118
118
  path: string;
119
- /** Path type: 'Prefix' (default) or 'Exact' */
120
- pathType?: 'Prefix' | 'Exact';
119
+ /** Path type: 'Prefix' (default), 'Exact', or 'ImplementationSpecific' (for regex) */
120
+ pathType?: 'Prefix' | 'Exact' | 'ImplementationSpecific';
121
+ /**
122
+ * Keep the path prefix when forwarding to the service (default: false).
123
+ *
124
+ * By default, the path prefix is stripped:
125
+ * path='/api': /api/health -> /health
126
+ *
127
+ * With keepPrefix=true:
128
+ * path='/api': /api/health -> /api/health
129
+ */
130
+ keepPrefix?: boolean;
121
131
  /** Custom annotations for the ingress */
122
132
  annotations?: Record<string, string>;
123
133
  /** Hostname for the ingress (required for TLS) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/infrastructure",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {