everything-dev 0.0.1

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/src/config.ts ADDED
@@ -0,0 +1,214 @@
1
+ import { dirname, join } from "path";
2
+
3
+ export type SourceMode = "local" | "remote";
4
+
5
+ export interface AppConfig {
6
+ host: SourceMode;
7
+ ui: SourceMode;
8
+ api: SourceMode;
9
+ proxy?: boolean;
10
+ }
11
+
12
+ export const DEFAULT_DEV_CONFIG: AppConfig = {
13
+ host: "local",
14
+ ui: "local",
15
+ api: "local",
16
+ };
17
+
18
+ export interface HostConfig {
19
+ title: string;
20
+ description?: string;
21
+ development: string;
22
+ production: string;
23
+ secrets?: string[];
24
+ }
25
+
26
+ export interface RemoteConfig {
27
+ name: string;
28
+ development: string;
29
+ production: string;
30
+ ssr?: string;
31
+ exposes?: Record<string, string>;
32
+ variables?: Record<string, string>;
33
+ secrets?: string[];
34
+ }
35
+
36
+ export interface GatewayConfig {
37
+ development: string;
38
+ production: string;
39
+ }
40
+
41
+ export interface BosConfig {
42
+ account: string;
43
+ gateway: GatewayConfig;
44
+ templates?: Record<string, string>;
45
+ create?: Record<string, string>;
46
+ cli?: {
47
+ remote?: string;
48
+ local?: string;
49
+ };
50
+ app: {
51
+ host: HostConfig;
52
+ [remoteName: string]: HostConfig | RemoteConfig;
53
+ };
54
+ }
55
+
56
+ let cachedConfig: BosConfig | null = null;
57
+ let configDir: string | null = null;
58
+
59
+ export function findConfigPath(startDir: string): string | null {
60
+ let dir = startDir;
61
+ while (dir !== "/") {
62
+ const configPath = join(dir, "bos.config.json");
63
+ if (Bun.file(configPath).size > 0) {
64
+ try {
65
+ Bun.file(configPath).text();
66
+ return configPath;
67
+ } catch {
68
+ // File doesn't exist or can't be read
69
+ }
70
+ }
71
+ dir = dirname(dir);
72
+ }
73
+ return null;
74
+ }
75
+
76
+ function findConfigPathSync(startDir: string): string | null {
77
+ let dir = startDir;
78
+ while (dir !== "/") {
79
+ const configPath = join(dir, "bos.config.json");
80
+ const file = Bun.file(configPath);
81
+ if (file.size > 0) {
82
+ return configPath;
83
+ }
84
+ dir = dirname(dir);
85
+ }
86
+ return null;
87
+ }
88
+
89
+ export function loadConfig(cwd?: string): BosConfig {
90
+ if (cachedConfig) return cachedConfig;
91
+
92
+ const startDir = cwd ?? process.cwd();
93
+ const configPath = findConfigPathSync(startDir);
94
+
95
+ if (!configPath) {
96
+ throw new Error("Could not find bos.config.json in current directory or parents");
97
+ }
98
+
99
+ configDir = dirname(configPath);
100
+ const file = Bun.file(configPath);
101
+ const content = require(configPath);
102
+ cachedConfig = content as BosConfig;
103
+ return cachedConfig;
104
+ }
105
+
106
+ export function getConfigDir(): string {
107
+ if (!configDir) {
108
+ loadConfig();
109
+ }
110
+ return configDir!;
111
+ }
112
+
113
+ export function getRemotes(): string[] {
114
+ const config = loadConfig();
115
+ return Object.keys(config.app).filter((k) => k !== "host");
116
+ }
117
+
118
+ export function getPackages(): string[] {
119
+ const config = loadConfig();
120
+ return Object.keys(config.app);
121
+ }
122
+
123
+ export function getRemote(name: string): RemoteConfig | undefined {
124
+ const config = loadConfig();
125
+ const remote = config.app[name];
126
+ if (remote && "name" in remote) {
127
+ return remote as RemoteConfig;
128
+ }
129
+ return undefined;
130
+ }
131
+
132
+ export function getHost(): HostConfig {
133
+ const config = loadConfig();
134
+ return config.app.host;
135
+ }
136
+
137
+ export function getUrl(
138
+ packageName: string,
139
+ env: "development" | "production" = "development"
140
+ ): string | undefined {
141
+ const config = loadConfig();
142
+ const pkg = config.app[packageName];
143
+ if (!pkg) return undefined;
144
+ return pkg[env];
145
+ }
146
+
147
+ export function getAccount(): string {
148
+ const config = loadConfig();
149
+ return config.account;
150
+ }
151
+
152
+ export function getTitle(): string {
153
+ const config = loadConfig();
154
+ return config.app.host.title;
155
+ }
156
+
157
+ export function getComponentUrl(
158
+ component: "host" | "ui" | "api",
159
+ source: SourceMode
160
+ ): string {
161
+ const config = loadConfig();
162
+
163
+ if (component === "host") {
164
+ return source === "remote" ? config.app.host.production : config.app.host.development;
165
+ }
166
+
167
+ const componentConfig = config.app[component];
168
+ if (!componentConfig || !("name" in componentConfig)) {
169
+ throw new Error(`Component ${component} not found in bos.config.json`);
170
+ }
171
+
172
+ return source === "remote" ? componentConfig.production : componentConfig.development;
173
+ }
174
+
175
+ export function parsePort(url: string): number {
176
+ try {
177
+ const parsed = new URL(url);
178
+ return parsed.port ? parseInt(parsed.port, 10) : (parsed.protocol === "https:" ? 443 : 80);
179
+ } catch {
180
+ return 3000;
181
+ }
182
+ }
183
+
184
+ export interface PortConfig {
185
+ host: number;
186
+ ui: number;
187
+ api: number;
188
+ }
189
+
190
+ export function getPortsFromConfig(): PortConfig {
191
+ const config = loadConfig();
192
+ return {
193
+ host: parsePort(config.app.host.development),
194
+ ui: config.app.ui ? parsePort((config.app.ui as RemoteConfig).development) : 3002,
195
+ api: config.app.api ? parsePort((config.app.api as RemoteConfig).development) : 3014,
196
+ };
197
+ }
198
+
199
+ export function getConfigPath(): string {
200
+ if (!configDir) {
201
+ loadConfig();
202
+ }
203
+ return `${configDir}/bos.config.json`;
204
+ }
205
+
206
+ export function getHostRemoteUrl(): string | undefined {
207
+ const config = loadConfig();
208
+ return config.app.host.production || undefined;
209
+ }
210
+
211
+ export function getGatewayUrl(env: "development" | "production" = "development"): string {
212
+ const config = loadConfig();
213
+ return config.gateway[env];
214
+ }
@@ -0,0 +1,364 @@
1
+ import { oc } from "every-plugin/orpc";
2
+ import { z } from "every-plugin/zod";
3
+
4
+ const SourceModeSchema = z.enum(["local", "remote"]);
5
+
6
+ const DevOptionsSchema = z.object({
7
+ host: SourceModeSchema.default("local"),
8
+ ui: SourceModeSchema.default("local"),
9
+ api: SourceModeSchema.default("local"),
10
+ proxy: z.boolean().default(false),
11
+ port: z.number().optional(),
12
+ interactive: z.boolean().optional(),
13
+ });
14
+
15
+ const DevResultSchema = z.object({
16
+ status: z.enum(["started", "error"]),
17
+ description: z.string(),
18
+ processes: z.array(z.string()),
19
+ });
20
+
21
+ const StartOptionsSchema = z.object({
22
+ port: z.number().optional(),
23
+ interactive: z.boolean().optional(),
24
+ account: z.string().optional(),
25
+ domain: z.string().optional(),
26
+ });
27
+
28
+ const StartResultSchema = z.object({
29
+ status: z.enum(["running", "error"]),
30
+ url: z.string(),
31
+ });
32
+
33
+ const ServeOptionsSchema = z.object({
34
+ port: z.number().default(4000),
35
+ });
36
+
37
+ const ServeResultSchema = z.object({
38
+ status: z.enum(["serving", "error"]),
39
+ url: z.string(),
40
+ endpoints: z.object({
41
+ rpc: z.string(),
42
+ docs: z.string(),
43
+ }),
44
+ });
45
+
46
+ const BuildOptionsSchema = z.object({
47
+ package: z.string().default("all"),
48
+ force: z.boolean().default(false),
49
+ deploy: z.boolean().default(true),
50
+ });
51
+
52
+ const BuildResultSchema = z.object({
53
+ status: z.enum(["success", "error"]),
54
+ built: z.array(z.string()),
55
+ deployed: z.boolean().optional(),
56
+ });
57
+
58
+ const SigningMethodSchema = z.enum([
59
+ "keychain",
60
+ "ledger",
61
+ "seed-phrase",
62
+ "access-key-file",
63
+ "private-key",
64
+ ]);
65
+
66
+ const PublishOptionsSchema = z.object({
67
+ signWith: SigningMethodSchema.optional(),
68
+ network: z.enum(["mainnet", "testnet"]).default("mainnet"),
69
+ path: z.string().default("bos.config.json"),
70
+ dryRun: z.boolean().default(false),
71
+ });
72
+
73
+ const PublishResultSchema = z.object({
74
+ status: z.enum(["published", "error", "dry-run"]),
75
+ txHash: z.string(),
76
+ registryUrl: z.string(),
77
+ error: z.string().optional(),
78
+ });
79
+
80
+ const CreateOptionsSchema = z.object({
81
+ type: z.enum(["project", "ui", "api", "host", "cli", "gateway"]),
82
+ name: z.string().optional(),
83
+ template: z.string().optional(),
84
+ });
85
+
86
+ const CreateResultSchema = z.object({
87
+ status: z.enum(["created", "error"]),
88
+ path: z.string(),
89
+ });
90
+
91
+ const RemoteConfigSchema = z.object({
92
+ name: z.string(),
93
+ development: z.string(),
94
+ production: z.string(),
95
+ ssr: z.string().optional(),
96
+ exposes: z.record(z.string(), z.string()).optional(),
97
+ variables: z.record(z.string(), z.string()).optional(),
98
+ secrets: z.array(z.string()).optional(),
99
+ });
100
+
101
+ const HostConfigSchema = z.object({
102
+ title: z.string(),
103
+ description: z.string().optional(),
104
+ development: z.string(),
105
+ production: z.string(),
106
+ secrets: z.array(z.string()).optional(),
107
+ });
108
+
109
+ const BosConfigSchema = z.object({
110
+ account: z.string(),
111
+ cli: z.object({
112
+ remote: z.string().optional(),
113
+ local: z.string().optional(),
114
+ }).optional(),
115
+ create: z.record(z.string(), z.string()).optional(),
116
+ app: z.object({
117
+ host: HostConfigSchema,
118
+ }).catchall(z.union([HostConfigSchema, RemoteConfigSchema])),
119
+ });
120
+
121
+ const InfoResultSchema = z.object({
122
+ config: BosConfigSchema,
123
+ packages: z.array(z.string()),
124
+ remotes: z.array(z.string()),
125
+ });
126
+
127
+ const EndpointStatusSchema = z.object({
128
+ name: z.string(),
129
+ url: z.string(),
130
+ type: z.enum(["host", "remote", "ssr"]),
131
+ healthy: z.boolean(),
132
+ latency: z.number().optional(),
133
+ });
134
+
135
+ const StatusOptionsSchema = z.object({
136
+ env: z.enum(["development", "production"]).default("development"),
137
+ });
138
+
139
+ const StatusResultSchema = z.object({
140
+ endpoints: z.array(EndpointStatusSchema),
141
+ });
142
+
143
+ const CleanResultSchema = z.object({
144
+ status: z.enum(["cleaned", "error"]),
145
+ removed: z.array(z.string()),
146
+ });
147
+
148
+ const RegisterOptionsSchema = z.object({
149
+ name: z.string(),
150
+ network: z.enum(["mainnet", "testnet"]).default("mainnet"),
151
+ });
152
+
153
+ const RegisterResultSchema = z.object({
154
+ status: z.enum(["registered", "error"]),
155
+ account: z.string(),
156
+ novaGroup: z.string().optional(),
157
+ error: z.string().optional(),
158
+ });
159
+
160
+ const SecretsSyncOptionsSchema = z.object({
161
+ envPath: z.string(),
162
+ });
163
+
164
+ const SecretsSyncResultSchema = z.object({
165
+ status: z.enum(["synced", "error"]),
166
+ count: z.number(),
167
+ cid: z.string().optional(),
168
+ error: z.string().optional(),
169
+ });
170
+
171
+ const SecretsSetOptionsSchema = z.object({
172
+ key: z.string(),
173
+ value: z.string(),
174
+ });
175
+
176
+ const SecretsSetResultSchema = z.object({
177
+ status: z.enum(["set", "error"]),
178
+ cid: z.string().optional(),
179
+ error: z.string().optional(),
180
+ });
181
+
182
+ const SecretsListResultSchema = z.object({
183
+ status: z.enum(["listed", "error"]),
184
+ keys: z.array(z.string()),
185
+ error: z.string().optional(),
186
+ });
187
+
188
+ const SecretsDeleteOptionsSchema = z.object({
189
+ key: z.string(),
190
+ });
191
+
192
+ const SecretsDeleteResultSchema = z.object({
193
+ status: z.enum(["deleted", "error"]),
194
+ cid: z.string().optional(),
195
+ error: z.string().optional(),
196
+ });
197
+
198
+ const LoginOptionsSchema = z.object({
199
+ token: z.string().optional(),
200
+ accountId: z.string().optional(),
201
+ });
202
+
203
+ const LoginResultSchema = z.object({
204
+ status: z.enum(["logged-in", "error"]),
205
+ accountId: z.string().optional(),
206
+ error: z.string().optional(),
207
+ });
208
+
209
+ const LogoutResultSchema = z.object({
210
+ status: z.enum(["logged-out", "error"]),
211
+ error: z.string().optional(),
212
+ });
213
+
214
+ const GatewayDevOptionsSchema = z.object({});
215
+
216
+ const GatewayDevResultSchema = z.object({
217
+ status: z.enum(["started", "error"]),
218
+ url: z.string(),
219
+ error: z.string().optional(),
220
+ });
221
+
222
+ const GatewayDeployOptionsSchema = z.object({
223
+ env: z.enum(["production", "staging"]).optional(),
224
+ });
225
+
226
+ const GatewayDeployResultSchema = z.object({
227
+ status: z.enum(["deployed", "error"]),
228
+ url: z.string(),
229
+ error: z.string().optional(),
230
+ });
231
+
232
+ const GatewaySyncOptionsSchema = z.object({});
233
+
234
+ const GatewaySyncResultSchema = z.object({
235
+ status: z.enum(["synced", "error"]),
236
+ gatewayDomain: z.string().optional(),
237
+ gatewayAccount: z.string().optional(),
238
+ error: z.string().optional(),
239
+ });
240
+
241
+ export const bosContract = oc.router({
242
+ dev: oc
243
+ .route({ method: "POST", path: "/dev" })
244
+ .input(DevOptionsSchema)
245
+ .output(DevResultSchema),
246
+
247
+ start: oc
248
+ .route({ method: "POST", path: "/start" })
249
+ .input(StartOptionsSchema)
250
+ .output(StartResultSchema),
251
+
252
+ serve: oc
253
+ .route({ method: "POST", path: "/serve" })
254
+ .input(ServeOptionsSchema)
255
+ .output(ServeResultSchema),
256
+
257
+ build: oc
258
+ .route({ method: "POST", path: "/build" })
259
+ .input(BuildOptionsSchema)
260
+ .output(BuildResultSchema),
261
+
262
+ publish: oc
263
+ .route({ method: "POST", path: "/publish" })
264
+ .input(PublishOptionsSchema)
265
+ .output(PublishResultSchema),
266
+
267
+ create: oc
268
+ .route({ method: "POST", path: "/create" })
269
+ .input(CreateOptionsSchema)
270
+ .output(CreateResultSchema),
271
+
272
+ info: oc
273
+ .route({ method: "GET", path: "/info" })
274
+ .output(InfoResultSchema),
275
+
276
+ status: oc
277
+ .route({ method: "GET", path: "/status" })
278
+ .input(StatusOptionsSchema)
279
+ .output(StatusResultSchema),
280
+
281
+ clean: oc
282
+ .route({ method: "POST", path: "/clean" })
283
+ .output(CleanResultSchema),
284
+
285
+ register: oc
286
+ .route({ method: "POST", path: "/register" })
287
+ .input(RegisterOptionsSchema)
288
+ .output(RegisterResultSchema),
289
+
290
+ secretsSync: oc
291
+ .route({ method: "POST", path: "/secrets/sync" })
292
+ .input(SecretsSyncOptionsSchema)
293
+ .output(SecretsSyncResultSchema),
294
+
295
+ secretsSet: oc
296
+ .route({ method: "POST", path: "/secrets/set" })
297
+ .input(SecretsSetOptionsSchema)
298
+ .output(SecretsSetResultSchema),
299
+
300
+ secretsList: oc
301
+ .route({ method: "GET", path: "/secrets/list" })
302
+ .output(SecretsListResultSchema),
303
+
304
+ secretsDelete: oc
305
+ .route({ method: "POST", path: "/secrets/delete" })
306
+ .input(SecretsDeleteOptionsSchema)
307
+ .output(SecretsDeleteResultSchema),
308
+
309
+ login: oc
310
+ .route({ method: "POST", path: "/login" })
311
+ .input(LoginOptionsSchema)
312
+ .output(LoginResultSchema),
313
+
314
+ logout: oc
315
+ .route({ method: "POST", path: "/logout" })
316
+ .output(LogoutResultSchema),
317
+
318
+ gatewayDev: oc
319
+ .route({ method: "POST", path: "/gateway/dev" })
320
+ .input(GatewayDevOptionsSchema)
321
+ .output(GatewayDevResultSchema),
322
+
323
+ gatewayDeploy: oc
324
+ .route({ method: "POST", path: "/gateway/deploy" })
325
+ .input(GatewayDeployOptionsSchema)
326
+ .output(GatewayDeployResultSchema),
327
+
328
+ gatewaySync: oc
329
+ .route({ method: "POST", path: "/gateway/sync" })
330
+ .input(GatewaySyncOptionsSchema)
331
+ .output(GatewaySyncResultSchema),
332
+ });
333
+
334
+ export type BosContract = typeof bosContract;
335
+ export type DevOptions = z.infer<typeof DevOptionsSchema>;
336
+ export type DevResult = z.infer<typeof DevResultSchema>;
337
+ export type StartOptions = z.infer<typeof StartOptionsSchema>;
338
+ export type StartResult = z.infer<typeof StartResultSchema>;
339
+ export type ServeOptions = z.infer<typeof ServeOptionsSchema>;
340
+ export type ServeResult = z.infer<typeof ServeResultSchema>;
341
+ export type BuildOptions = z.infer<typeof BuildOptionsSchema>;
342
+ export type BuildResult = z.infer<typeof BuildResultSchema>;
343
+ export type SigningMethod = z.infer<typeof SigningMethodSchema>;
344
+ export type PublishOptions = z.infer<typeof PublishOptionsSchema>;
345
+ export type PublishResult = z.infer<typeof PublishResultSchema>;
346
+ export type CreateOptions = z.infer<typeof CreateOptionsSchema>;
347
+ export type CreateResult = z.infer<typeof CreateResultSchema>;
348
+ export type BosConfig = z.infer<typeof BosConfigSchema>;
349
+ export type InfoResult = z.infer<typeof InfoResultSchema>;
350
+ export type StatusOptions = z.infer<typeof StatusOptionsSchema>;
351
+ export type StatusResult = z.infer<typeof StatusResultSchema>;
352
+ export type CleanResult = z.infer<typeof CleanResultSchema>;
353
+ export type RegisterOptions = z.infer<typeof RegisterOptionsSchema>;
354
+ export type RegisterResult = z.infer<typeof RegisterResultSchema>;
355
+ export type SecretsSyncOptions = z.infer<typeof SecretsSyncOptionsSchema>;
356
+ export type SecretsSyncResult = z.infer<typeof SecretsSyncResultSchema>;
357
+ export type SecretsSetOptions = z.infer<typeof SecretsSetOptionsSchema>;
358
+ export type SecretsSetResult = z.infer<typeof SecretsSetResultSchema>;
359
+ export type SecretsListResult = z.infer<typeof SecretsListResultSchema>;
360
+ export type SecretsDeleteOptions = z.infer<typeof SecretsDeleteOptionsSchema>;
361
+ export type SecretsDeleteResult = z.infer<typeof SecretsDeleteResultSchema>;
362
+ export type LoginOptions = z.infer<typeof LoginOptionsSchema>;
363
+ export type LoginResult = z.infer<typeof LoginResultSchema>;
364
+ export type LogoutResult = z.infer<typeof LogoutResultSchema>;
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { default } from "./plugin";
2
+ export { bosContract } from "./contract";
3
+ export type * from "./contract";
package/src/lib/env.ts ADDED
@@ -0,0 +1,91 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { Effect } from "every-plugin/effect";
5
+ import { getConfigDir } from "../config";
6
+
7
+ export interface BosEnv {
8
+ ZE_SERVER_TOKEN?: string;
9
+ ZE_USER_EMAIL?: string;
10
+ NEAR_PRIVATE_KEY?: string;
11
+ GATEWAY_PRIVATE_KEY?: string;
12
+ NOVA_SECRETS_CID?: string;
13
+ }
14
+
15
+ function parseEnvFile(content: string): Record<string, string> {
16
+ const result: Record<string, string> = {};
17
+ const lines = content.split("\n");
18
+
19
+ for (const line of lines) {
20
+ const trimmed = line.trim();
21
+ if (!trimmed || trimmed.startsWith("#")) continue;
22
+
23
+ const eqIndex = trimmed.indexOf("=");
24
+ if (eqIndex === -1) continue;
25
+
26
+ const key = trimmed.slice(0, eqIndex).trim();
27
+ let value = trimmed.slice(eqIndex + 1).trim();
28
+
29
+ if ((value.startsWith('"') && value.endsWith('"')) ||
30
+ (value.startsWith("'") && value.endsWith("'"))) {
31
+ value = value.slice(1, -1);
32
+ }
33
+
34
+ result[key] = value;
35
+ }
36
+
37
+ return result;
38
+ }
39
+
40
+ export const loadBosEnv = Effect.gen(function* () {
41
+ const configDir = getConfigDir();
42
+ const envBosPath = path.join(configDir, ".env.bos");
43
+ const envPath = path.join(configDir, ".env");
44
+
45
+ let envVars: BosEnv = {};
46
+
47
+ const envFilePath = existsSync(envBosPath) ? envBosPath : existsSync(envPath) ? envPath : null;
48
+
49
+ if (envFilePath) {
50
+ const content = yield* Effect.tryPromise({
51
+ try: () => readFile(envFilePath, "utf-8"),
52
+ catch: () => new Error(`Failed to read ${envFilePath}`),
53
+ });
54
+
55
+ const parsed = parseEnvFile(content);
56
+ envVars = {
57
+ ZE_SERVER_TOKEN: parsed.ZE_SERVER_TOKEN,
58
+ ZE_USER_EMAIL: parsed.ZE_USER_EMAIL,
59
+ NEAR_PRIVATE_KEY: parsed.NEAR_PRIVATE_KEY,
60
+ GATEWAY_PRIVATE_KEY: parsed.GATEWAY_PRIVATE_KEY,
61
+ NOVA_SECRETS_CID: parsed.NOVA_SECRETS_CID,
62
+ };
63
+ }
64
+
65
+ envVars.ZE_SERVER_TOKEN = envVars.ZE_SERVER_TOKEN || process.env.ZE_SERVER_TOKEN;
66
+ envVars.ZE_USER_EMAIL = envVars.ZE_USER_EMAIL || process.env.ZE_USER_EMAIL;
67
+ envVars.NEAR_PRIVATE_KEY = envVars.NEAR_PRIVATE_KEY || process.env.NEAR_PRIVATE_KEY;
68
+ envVars.GATEWAY_PRIVATE_KEY = envVars.GATEWAY_PRIVATE_KEY || process.env.GATEWAY_PRIVATE_KEY;
69
+ envVars.NOVA_SECRETS_CID = envVars.NOVA_SECRETS_CID || process.env.NOVA_SECRETS_CID;
70
+
71
+ return envVars;
72
+ });
73
+
74
+ export const ZEPHYR_DOCS_URL = "https://docs.zephyr-cloud.io/features/ci-cd-server-token";
75
+
76
+ export const getBuildEnv = (bosEnv: BosEnv): Record<string, string> => {
77
+ const env: Record<string, string> = { ...process.env as Record<string, string> };
78
+
79
+ if (bosEnv.ZE_SERVER_TOKEN) {
80
+ env.ZE_SERVER_TOKEN = bosEnv.ZE_SERVER_TOKEN;
81
+ }
82
+ if (bosEnv.ZE_USER_EMAIL) {
83
+ env.ZE_USER_EMAIL = bosEnv.ZE_USER_EMAIL;
84
+ }
85
+
86
+ return env;
87
+ };
88
+
89
+ export const hasZephyrConfig = (bosEnv: BosEnv): boolean => {
90
+ return !!(bosEnv.ZE_SERVER_TOKEN && bosEnv.ZE_USER_EMAIL);
91
+ };