@wopr-network/platform-core 1.36.3 → 1.38.0

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.
@@ -41,6 +41,13 @@ export declare class FleetManager {
41
41
  create(params: Omit<BotProfile, "id"> & {
42
42
  id?: string;
43
43
  }, resourceLimits?: ContainerResourceLimits): Promise<BotProfile>;
44
+ /**
45
+ * Create and immediately start a bot container in one call.
46
+ * Combines create() + start() for ephemeral container workflows.
47
+ */
48
+ createAndStart(params: Omit<BotProfile, "id"> & {
49
+ id?: string;
50
+ }, resourceLimits?: ContainerResourceLimits): Promise<BotProfile>;
44
51
  /**
45
52
  * Start a stopped bot container.
46
53
  * Valid from: stopped, created, exited, dead, error states.
@@ -130,6 +130,15 @@ export class FleetManager {
130
130
  };
131
131
  return hasExplicitId ? this.withLock(id, doCreate) : doCreate();
132
132
  }
133
+ /**
134
+ * Create and immediately start a bot container in one call.
135
+ * Combines create() + start() for ephemeral container workflows.
136
+ */
137
+ async createAndStart(params, resourceLimits) {
138
+ const profile = await this.create(params, resourceLimits);
139
+ await this.start(profile.id);
140
+ return profile;
141
+ }
133
142
  /**
134
143
  * Start a stopped bot container.
135
144
  * Valid from: stopped, created, exited, dead, error states.
@@ -557,22 +566,28 @@ export class FleetManager {
557
566
  if (sharedVolConfig.enabled) {
558
567
  binds.push(`${sharedVolConfig.volumeName}:${sharedVolConfig.mountPath}:ro`);
559
568
  }
569
+ const isEphemeral = profile.ephemeral === true;
560
570
  const hostConfig = {
561
571
  RestartPolicy: {
562
572
  Name: restartPolicyMap[profile.restartPolicy] || "",
563
573
  },
564
574
  Binds: binds.length > 0 ? binds : undefined,
565
- SecurityOpt: ["no-new-privileges"],
566
- CapDrop: ["ALL"],
567
- CapAdd: ["NET_BIND_SERVICE"],
568
- ReadonlyRootfs: true,
569
- Tmpfs: {
570
- "/tmp": "rw,noexec,nosuid,size=64m",
571
- "/var/tmp": "rw,noexec,nosuid,size=64m",
572
- },
575
+ SecurityOpt: isEphemeral ? undefined : ["no-new-privileges"],
576
+ CapDrop: isEphemeral ? undefined : ["ALL"],
577
+ CapAdd: isEphemeral ? undefined : ["NET_BIND_SERVICE"],
578
+ ReadonlyRootfs: isEphemeral ? false : true,
579
+ Tmpfs: isEphemeral
580
+ ? undefined
581
+ : {
582
+ "/tmp": "rw,noexec,nosuid,size=64m",
583
+ "/var/tmp": "rw,noexec,nosuid,size=64m",
584
+ },
573
585
  };
574
- // Set tenant network isolation if NetworkPolicy is configured
575
- if (this.networkPolicy) {
586
+ // Set network: explicit profile.network takes precedence, then NetworkPolicy
587
+ if (profile.network) {
588
+ hostConfig.NetworkMode = profile.network;
589
+ }
590
+ else if (this.networkPolicy) {
576
591
  const networkMode = await this.networkPolicy.prepareForContainer(profile.tenantId);
577
592
  hostConfig.NetworkMode = networkMode;
578
593
  }
@@ -1,4 +1,5 @@
1
1
  export * from "./drizzle-tenant-update-config-repository.js";
2
+ export * from "./fleet-manager.js";
2
3
  export type { FleetNotificationListenerDeps } from "./fleet-notification-listener.js";
3
4
  export { initFleetNotificationListener } from "./fleet-notification-listener.js";
4
5
  export * from "./init-fleet-updater.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./drizzle-tenant-update-config-repository.js";
2
+ export * from "./fleet-manager.js";
2
3
  export { initFleetNotificationListener } from "./fleet-notification-listener.js";
3
4
  export * from "./init-fleet-updater.js";
4
5
  export * from "./repository-types.js";
@@ -53,6 +53,8 @@ export declare const botProfileSchema: z.ZodObject<{
53
53
  topics: z.ZodDefault<z.ZodArray<z.ZodString>>;
54
54
  }, z.core.$strip>>;
55
55
  nodeId: z.ZodOptional<z.ZodString>;
56
+ network: z.ZodOptional<z.ZodString>;
57
+ ephemeral: z.ZodOptional<z.ZodBoolean>;
56
58
  }, z.core.$strip>;
57
59
  export type BotProfile = z.infer<typeof botProfileSchema>;
58
60
  /** Schema for creating a bot via the API */
@@ -85,6 +87,8 @@ export declare const createBotSchema: z.ZodObject<{
85
87
  topics: z.ZodDefault<z.ZodArray<z.ZodString>>;
86
88
  }, z.core.$strip>>;
87
89
  nodeId: z.ZodOptional<z.ZodString>;
90
+ network: z.ZodOptional<z.ZodString>;
91
+ ephemeral: z.ZodOptional<z.ZodBoolean>;
88
92
  }, z.core.$strip>;
89
93
  /** Schema for updating a bot via the API */
90
94
  export declare const updateBotSchema: z.ZodObject<{
@@ -64,6 +64,10 @@ export const botProfileSchema = z.object({
64
64
  discovery: discoveryConfigSchema.optional(),
65
65
  /** Node this bot was placed on at creation time (optional, for future multi-node routing). */
66
66
  nodeId: z.string().uuid().optional(),
67
+ /** Docker network to attach the container to (bypasses NetworkPolicy). */
68
+ network: z.string().min(1).optional(),
69
+ /** When true, disables ReadonlyRootfs and CapDrop for containers that need write access (e.g., ephemeral workers). */
70
+ ephemeral: z.boolean().optional(),
67
71
  });
68
72
  /** Schema for creating a bot via the API */
69
73
  export const createBotSchema = z.object({
@@ -83,6 +87,10 @@ export const createBotSchema = z.object({
83
87
  discovery: discoveryConfigSchema.optional(),
84
88
  /** Node this bot was placed on at creation time (optional, for future multi-node routing). */
85
89
  nodeId: z.string().uuid().optional(),
90
+ /** Docker network to attach the container to. */
91
+ network: z.string().min(1).optional(),
92
+ /** When true, disables ReadonlyRootfs and CapDrop for ephemeral workers. */
93
+ ephemeral: z.boolean().optional(),
86
94
  });
87
95
  /** Schema for updating a bot via the API */
88
96
  export const updateBotSchema = z.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wopr-network/platform-core",
3
- "version": "1.36.3",
3
+ "version": "1.38.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -159,6 +159,19 @@ export class FleetManager {
159
159
  return hasExplicitId ? this.withLock(id, doCreate) : doCreate();
160
160
  }
161
161
 
162
+ /**
163
+ * Create and immediately start a bot container in one call.
164
+ * Combines create() + start() for ephemeral container workflows.
165
+ */
166
+ async createAndStart(
167
+ params: Omit<BotProfile, "id"> & { id?: string },
168
+ resourceLimits?: ContainerResourceLimits,
169
+ ): Promise<BotProfile> {
170
+ const profile = await this.create(params, resourceLimits);
171
+ await this.start(profile.id);
172
+ return profile;
173
+ }
174
+
162
175
  /**
163
176
  * Start a stopped bot container.
164
177
  * Valid from: stopped, created, exited, dead, error states.
@@ -608,23 +621,29 @@ export class FleetManager {
608
621
  binds.push(`${sharedVolConfig.volumeName}:${sharedVolConfig.mountPath}:ro`);
609
622
  }
610
623
 
624
+ const isEphemeral = profile.ephemeral === true;
625
+
611
626
  const hostConfig: Docker.ContainerCreateOptions["HostConfig"] = {
612
627
  RestartPolicy: {
613
628
  Name: restartPolicyMap[profile.restartPolicy] || "",
614
629
  },
615
630
  Binds: binds.length > 0 ? binds : undefined,
616
- SecurityOpt: ["no-new-privileges"],
617
- CapDrop: ["ALL"],
618
- CapAdd: ["NET_BIND_SERVICE"],
619
- ReadonlyRootfs: true,
620
- Tmpfs: {
621
- "/tmp": "rw,noexec,nosuid,size=64m",
622
- "/var/tmp": "rw,noexec,nosuid,size=64m",
623
- },
631
+ SecurityOpt: isEphemeral ? undefined : ["no-new-privileges"],
632
+ CapDrop: isEphemeral ? undefined : ["ALL"],
633
+ CapAdd: isEphemeral ? undefined : ["NET_BIND_SERVICE"],
634
+ ReadonlyRootfs: isEphemeral ? false : true,
635
+ Tmpfs: isEphemeral
636
+ ? undefined
637
+ : {
638
+ "/tmp": "rw,noexec,nosuid,size=64m",
639
+ "/var/tmp": "rw,noexec,nosuid,size=64m",
640
+ },
624
641
  };
625
642
 
626
- // Set tenant network isolation if NetworkPolicy is configured
627
- if (this.networkPolicy) {
643
+ // Set network: explicit profile.network takes precedence, then NetworkPolicy
644
+ if (profile.network) {
645
+ hostConfig.NetworkMode = profile.network;
646
+ } else if (this.networkPolicy) {
628
647
  const networkMode = await this.networkPolicy.prepareForContainer(profile.tenantId);
629
648
  hostConfig.NetworkMode = networkMode;
630
649
  }
@@ -1,4 +1,5 @@
1
1
  export * from "./drizzle-tenant-update-config-repository.js";
2
+ export * from "./fleet-manager.js";
2
3
  export type { FleetNotificationListenerDeps } from "./fleet-notification-listener.js";
3
4
  export { initFleetNotificationListener } from "./fleet-notification-listener.js";
4
5
  export * from "./init-fleet-updater.js";
@@ -74,6 +74,10 @@ export const botProfileSchema = z.object({
74
74
  discovery: discoveryConfigSchema.optional(),
75
75
  /** Node this bot was placed on at creation time (optional, for future multi-node routing). */
76
76
  nodeId: z.string().uuid().optional(),
77
+ /** Docker network to attach the container to (bypasses NetworkPolicy). */
78
+ network: z.string().min(1).optional(),
79
+ /** When true, disables ReadonlyRootfs and CapDrop for containers that need write access (e.g., ephemeral workers). */
80
+ ephemeral: z.boolean().optional(),
77
81
  });
78
82
 
79
83
  export type BotProfile = z.infer<typeof botProfileSchema>;
@@ -96,6 +100,10 @@ export const createBotSchema = z.object({
96
100
  discovery: discoveryConfigSchema.optional(),
97
101
  /** Node this bot was placed on at creation time (optional, for future multi-node routing). */
98
102
  nodeId: z.string().uuid().optional(),
103
+ /** Docker network to attach the container to. */
104
+ network: z.string().min(1).optional(),
105
+ /** When true, disables ReadonlyRootfs and CapDrop for ephemeral workers. */
106
+ ephemeral: z.boolean().optional(),
99
107
  });
100
108
 
101
109
  /** Schema for updating a bot via the API */