@crossdelta/infrastructure 0.8.1 → 0.8.3
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/core/runtime.d.ts +2 -0
- package/dist/helpers/stream-job.d.ts +5 -3
- package/dist/helpers/stream-setup.d.ts +3 -3
- package/dist/index.cjs +23 -7
- package/dist/index.js +23 -7
- package/package.json +2 -2
package/dist/core/runtime.d.ts
CHANGED
|
@@ -188,6 +188,8 @@ export interface RuntimeDeploymentConfig {
|
|
|
188
188
|
export interface RuntimeDeploymentResult {
|
|
189
189
|
/** NATS internal URL */
|
|
190
190
|
natsUrl?: pulumi.Output<string>;
|
|
191
|
+
/** NATS Helm release resource (for dependsOn in downstream jobs) */
|
|
192
|
+
natsRelease?: pulumi.Resource;
|
|
191
193
|
/** LoadBalancer IP (if ingress enabled) */
|
|
192
194
|
loadBalancerIp?: pulumi.Output<string>;
|
|
193
195
|
/** Cert manager ready */
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { Provider } from '@pulumi/kubernetes';
|
|
16
16
|
import * as k8s from '@pulumi/kubernetes';
|
|
17
|
-
import type { Output } from '@pulumi/pulumi';
|
|
17
|
+
import type { Output, Resource } from '@pulumi/pulumi';
|
|
18
18
|
import type { StreamPolicy } from './deploy-streams';
|
|
19
19
|
import { type ResolvedStream } from './stream-setup';
|
|
20
|
-
export type { ResolvedStream };
|
|
21
20
|
export { computeConfigHash, generateSetupScript, msToNatsDuration, resolveStreams } from './stream-setup';
|
|
21
|
+
export type { ResolvedStream };
|
|
22
22
|
export interface MaterializeStreamsConfig {
|
|
23
23
|
/** NATS connection URL (cluster-internal) */
|
|
24
24
|
natsUrl: Output<string>;
|
|
@@ -37,8 +37,10 @@ export interface MaterializeStreamsConfig {
|
|
|
37
37
|
image?: string;
|
|
38
38
|
/** Job TTL after completion in seconds (default: 300) */
|
|
39
39
|
ttlAfterFinished?: number;
|
|
40
|
-
/** Max retry attempts (default:
|
|
40
|
+
/** Max retry attempts (default: 6) */
|
|
41
41
|
backoffLimit?: number;
|
|
42
|
+
/** Pulumi resources the Job depends on (e.g., NATS Helm release) */
|
|
43
|
+
dependsOn?: Resource[];
|
|
42
44
|
}
|
|
43
45
|
/**
|
|
44
46
|
* Materialize NATS JetStream streams via a K8s Job.
|
|
@@ -35,7 +35,7 @@ export declare const resolveStreams: (definitions: StreamDefinition[], policies?
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const generateSetupScript: (streams: ResolvedStream[]) => string;
|
|
37
37
|
/**
|
|
38
|
-
* Compute a short hash from stream config for change detection.
|
|
39
|
-
* When config changes, the Job name changes → Pulumi recreates it.
|
|
38
|
+
* Compute a short hash from stream config + script for change detection.
|
|
39
|
+
* When config or script template changes, the Job name changes → Pulumi recreates it.
|
|
40
40
|
*/
|
|
41
|
-
export declare const computeConfigHash: (streams: ResolvedStream[]) => string;
|
|
41
|
+
export declare const computeConfigHash: (streams: ResolvedStream[], script?: string) => string;
|
package/dist/index.cjs
CHANGED
|
@@ -352,7 +352,7 @@ function deployNginxIngress(provider, config = {}) {
|
|
|
352
352
|
var k8s3 = __toESM(require("@pulumi/kubernetes"));
|
|
353
353
|
var pulumi2 = __toESM(require("@pulumi/pulumi"));
|
|
354
354
|
var NATS_DEFAULTS = {
|
|
355
|
-
replicas:
|
|
355
|
+
replicas: 1,
|
|
356
356
|
jetstream: {
|
|
357
357
|
enabled: true,
|
|
358
358
|
storageSize: "20Gi",
|
|
@@ -537,6 +537,7 @@ function deployRuntime(provider, namespace, config, runtimeProvider) {
|
|
|
537
537
|
if (config.nats?.enabled && providerName === "doks") {
|
|
538
538
|
const nats = deployNats(provider, namespace, config.nats.config || {});
|
|
539
539
|
result.natsUrl = pulumi3.output(nats.internalUrl);
|
|
540
|
+
result.natsRelease = nats.release;
|
|
540
541
|
}
|
|
541
542
|
if (config.ingress?.enabled && providerName === "doks") {
|
|
542
543
|
const ingress = deployNginxIngress(provider, config.ingress.config || {});
|
|
@@ -1011,6 +1012,20 @@ var generateSetupScript = (streams) => {
|
|
|
1011
1012
|
` NATS_OPTS="$NATS_OPTS --user $NATS_USER --password $NATS_PASSWORD"`,
|
|
1012
1013
|
`fi`,
|
|
1013
1014
|
``,
|
|
1015
|
+
`echo "⏳ Waiting for NATS to become available..."`,
|
|
1016
|
+
`RETRIES=0`,
|
|
1017
|
+
`MAX_RETRIES=30`,
|
|
1018
|
+
`until nats $NATS_OPTS server ping --count 1 > /dev/null 2>&1; do`,
|
|
1019
|
+
` RETRIES=$((RETRIES + 1))`,
|
|
1020
|
+
` if [ "$RETRIES" -ge "$MAX_RETRIES" ]; then`,
|
|
1021
|
+
` echo "❌ NATS not available after $MAX_RETRIES attempts"`,
|
|
1022
|
+
` exit 1`,
|
|
1023
|
+
` fi`,
|
|
1024
|
+
` echo " NATS not ready (attempt $RETRIES/$MAX_RETRIES), retrying in 2s..."`,
|
|
1025
|
+
` sleep 2`,
|
|
1026
|
+
`done`,
|
|
1027
|
+
`echo "✅ NATS is available"`,
|
|
1028
|
+
``,
|
|
1014
1029
|
`echo "\uD83D\uDE80 Materializing ${streams.length} stream(s)..."`,
|
|
1015
1030
|
`echo ""`,
|
|
1016
1031
|
``,
|
|
@@ -1020,8 +1035,8 @@ var generateSetupScript = (streams) => {
|
|
|
1020
1035
|
].join(`
|
|
1021
1036
|
`);
|
|
1022
1037
|
};
|
|
1023
|
-
var computeConfigHash = (streams) => {
|
|
1024
|
-
const data = JSON.stringify(streams);
|
|
1038
|
+
var computeConfigHash = (streams, script) => {
|
|
1039
|
+
const data = JSON.stringify(streams) + (script ?? "");
|
|
1025
1040
|
let hash = 0;
|
|
1026
1041
|
for (let i = 0;i < data.length; i++) {
|
|
1027
1042
|
const char = data.charCodeAt(i);
|
|
@@ -1045,13 +1060,14 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
1045
1060
|
defaults = DEFAULT_POLICY2,
|
|
1046
1061
|
image = NATS_BOX_IMAGE,
|
|
1047
1062
|
ttlAfterFinished = 300,
|
|
1048
|
-
backoffLimit =
|
|
1063
|
+
backoffLimit = 6,
|
|
1064
|
+
dependsOn: externalDeps = []
|
|
1049
1065
|
} = config;
|
|
1050
1066
|
validateStreamDefinitions(contracts);
|
|
1051
1067
|
const definitions = collectStreamDefinitions(contracts);
|
|
1052
1068
|
const resolved = resolveStreams(definitions, policies, defaults);
|
|
1053
1069
|
const script = generateSetupScript(resolved);
|
|
1054
|
-
const configHash = computeConfigHash(resolved);
|
|
1070
|
+
const configHash = computeConfigHash(resolved, script);
|
|
1055
1071
|
console.log(`\uD83D\uDCCB Collecting stream definitions from contracts...`);
|
|
1056
1072
|
console.log(`✅ Found ${definitions.length} stream(s):`);
|
|
1057
1073
|
for (const { stream, subjects } of definitions) {
|
|
@@ -1067,7 +1083,7 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
1067
1083
|
"setup.sh": script,
|
|
1068
1084
|
"streams.json": JSON.stringify(resolved, null, 2)
|
|
1069
1085
|
}
|
|
1070
|
-
}, { provider });
|
|
1086
|
+
}, { provider, deleteBeforeReplace: true });
|
|
1071
1087
|
const envVars = [{ name: "NATS_URL", value: config.natsUrl }];
|
|
1072
1088
|
if (config.credentials?.user) {
|
|
1073
1089
|
envVars.push({ name: "NATS_USER", value: config.credentials.user });
|
|
@@ -1110,7 +1126,7 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
1110
1126
|
}
|
|
1111
1127
|
}, {
|
|
1112
1128
|
provider,
|
|
1113
|
-
dependsOn: [configMap],
|
|
1129
|
+
dependsOn: [configMap, ...externalDeps],
|
|
1114
1130
|
deleteBeforeReplace: true
|
|
1115
1131
|
});
|
|
1116
1132
|
return job;
|
package/dist/index.js
CHANGED
|
@@ -258,7 +258,7 @@ function deployNginxIngress(provider, config = {}) {
|
|
|
258
258
|
import * as k8s3 from "@pulumi/kubernetes";
|
|
259
259
|
import * as pulumi2 from "@pulumi/pulumi";
|
|
260
260
|
var NATS_DEFAULTS = {
|
|
261
|
-
replicas:
|
|
261
|
+
replicas: 1,
|
|
262
262
|
jetstream: {
|
|
263
263
|
enabled: true,
|
|
264
264
|
storageSize: "20Gi",
|
|
@@ -443,6 +443,7 @@ function deployRuntime(provider, namespace, config, runtimeProvider) {
|
|
|
443
443
|
if (config.nats?.enabled && providerName === "doks") {
|
|
444
444
|
const nats = deployNats(provider, namespace, config.nats.config || {});
|
|
445
445
|
result.natsUrl = pulumi3.output(nats.internalUrl);
|
|
446
|
+
result.natsRelease = nats.release;
|
|
446
447
|
}
|
|
447
448
|
if (config.ingress?.enabled && providerName === "doks") {
|
|
448
449
|
const ingress = deployNginxIngress(provider, config.ingress.config || {});
|
|
@@ -917,6 +918,20 @@ var generateSetupScript = (streams) => {
|
|
|
917
918
|
` NATS_OPTS="$NATS_OPTS --user $NATS_USER --password $NATS_PASSWORD"`,
|
|
918
919
|
`fi`,
|
|
919
920
|
``,
|
|
921
|
+
`echo "⏳ Waiting for NATS to become available..."`,
|
|
922
|
+
`RETRIES=0`,
|
|
923
|
+
`MAX_RETRIES=30`,
|
|
924
|
+
`until nats $NATS_OPTS server ping --count 1 > /dev/null 2>&1; do`,
|
|
925
|
+
` RETRIES=$((RETRIES + 1))`,
|
|
926
|
+
` if [ "$RETRIES" -ge "$MAX_RETRIES" ]; then`,
|
|
927
|
+
` echo "❌ NATS not available after $MAX_RETRIES attempts"`,
|
|
928
|
+
` exit 1`,
|
|
929
|
+
` fi`,
|
|
930
|
+
` echo " NATS not ready (attempt $RETRIES/$MAX_RETRIES), retrying in 2s..."`,
|
|
931
|
+
` sleep 2`,
|
|
932
|
+
`done`,
|
|
933
|
+
`echo "✅ NATS is available"`,
|
|
934
|
+
``,
|
|
920
935
|
`echo "\uD83D\uDE80 Materializing ${streams.length} stream(s)..."`,
|
|
921
936
|
`echo ""`,
|
|
922
937
|
``,
|
|
@@ -926,8 +941,8 @@ var generateSetupScript = (streams) => {
|
|
|
926
941
|
].join(`
|
|
927
942
|
`);
|
|
928
943
|
};
|
|
929
|
-
var computeConfigHash = (streams) => {
|
|
930
|
-
const data = JSON.stringify(streams);
|
|
944
|
+
var computeConfigHash = (streams, script) => {
|
|
945
|
+
const data = JSON.stringify(streams) + (script ?? "");
|
|
931
946
|
let hash = 0;
|
|
932
947
|
for (let i = 0;i < data.length; i++) {
|
|
933
948
|
const char = data.charCodeAt(i);
|
|
@@ -951,13 +966,14 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
951
966
|
defaults = DEFAULT_POLICY2,
|
|
952
967
|
image = NATS_BOX_IMAGE,
|
|
953
968
|
ttlAfterFinished = 300,
|
|
954
|
-
backoffLimit =
|
|
969
|
+
backoffLimit = 6,
|
|
970
|
+
dependsOn: externalDeps = []
|
|
955
971
|
} = config;
|
|
956
972
|
validateStreamDefinitions(contracts);
|
|
957
973
|
const definitions = collectStreamDefinitions(contracts);
|
|
958
974
|
const resolved = resolveStreams(definitions, policies, defaults);
|
|
959
975
|
const script = generateSetupScript(resolved);
|
|
960
|
-
const configHash = computeConfigHash(resolved);
|
|
976
|
+
const configHash = computeConfigHash(resolved, script);
|
|
961
977
|
console.log(`\uD83D\uDCCB Collecting stream definitions from contracts...`);
|
|
962
978
|
console.log(`✅ Found ${definitions.length} stream(s):`);
|
|
963
979
|
for (const { stream, subjects } of definitions) {
|
|
@@ -973,7 +989,7 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
973
989
|
"setup.sh": script,
|
|
974
990
|
"streams.json": JSON.stringify(resolved, null, 2)
|
|
975
991
|
}
|
|
976
|
-
}, { provider });
|
|
992
|
+
}, { provider, deleteBeforeReplace: true });
|
|
977
993
|
const envVars = [{ name: "NATS_URL", value: config.natsUrl }];
|
|
978
994
|
if (config.credentials?.user) {
|
|
979
995
|
envVars.push({ name: "NATS_USER", value: config.credentials.user });
|
|
@@ -1016,7 +1032,7 @@ var materializeStreams = (provider, namespace, config) => {
|
|
|
1016
1032
|
}
|
|
1017
1033
|
}, {
|
|
1018
1034
|
provider,
|
|
1019
|
-
dependsOn: [configMap],
|
|
1035
|
+
dependsOn: [configMap, ...externalDeps],
|
|
1020
1036
|
deleteBeforeReplace: true
|
|
1021
1037
|
});
|
|
1022
1038
|
return job;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/infrastructure",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@crossdelta/cloudevents": "^0.7.
|
|
38
|
+
"@crossdelta/cloudevents": "^0.7.18"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@pulumi/digitalocean": "^4.0.0",
|