@mono-labs/cli 0.0.194 → 0.0.195
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/cdk/index.js +51 -0
- package/dist/expo.js +51 -0
- package/dist/merge-env.js +25 -0
- package/dist/project/index.js +65 -0
- package/dist/project/merge-env.js +25 -0
- package/dist/stack.js +51 -0
- package/dist/tools.js +32 -0
- package/dist/types/cdk/index.d.ts +2 -0
- package/dist/types/expo.d.ts +2 -0
- package/dist/types/merge-env.d.ts +1 -0
- package/dist/types/project/index.d.ts +43 -0
- package/dist/types/project/merge-env.d.ts +1 -0
- package/dist/types/stack.d.ts +21 -0
- package/dist/types/tools.d.ts +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function replaceTokens(str, env) {
|
|
2
|
+
if (typeof str !== 'string')
|
|
3
|
+
return str;
|
|
4
|
+
return str.replace(/\$\{([^}]+)\}|\$([A-Z0-9_]+)/g, (m, k1, k2) => {
|
|
5
|
+
const k = k1 || k2;
|
|
6
|
+
// existing data layer takes priority (guarded in case not defined)
|
|
7
|
+
if (typeof hasData === 'function' && hasData(k)) {
|
|
8
|
+
const val = typeof getData === 'function' ? getData(k) : undefined;
|
|
9
|
+
return val == null ? '' : String(val);
|
|
10
|
+
}
|
|
11
|
+
// environment variables
|
|
12
|
+
if (env && Object.prototype.hasOwnProperty.call(env, k)) {
|
|
13
|
+
const val = env[k];
|
|
14
|
+
return val == null ? '' : String(val);
|
|
15
|
+
}
|
|
16
|
+
// fallback
|
|
17
|
+
return '';
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function filterEnvByPrefix(env, prefix) {
|
|
21
|
+
const filtered = {};
|
|
22
|
+
for (const key in env) {
|
|
23
|
+
if (key.startsWith(prefix)) {
|
|
24
|
+
filtered[key] = env[key];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return filtered;
|
|
28
|
+
}
|
|
29
|
+
export function setUpConfig(config) {
|
|
30
|
+
const { extra = {}, ...other } = config.expo || {};
|
|
31
|
+
const router = extra['router'] ?
|
|
32
|
+
{ origin: false, ...extra['router'] }
|
|
33
|
+
: {
|
|
34
|
+
origin: false,
|
|
35
|
+
};
|
|
36
|
+
const appConfig = {
|
|
37
|
+
...config,
|
|
38
|
+
expo: {
|
|
39
|
+
...other,
|
|
40
|
+
extra: {
|
|
41
|
+
...filterEnvByPrefix(process.env, 'NEXT_PUBLIC_'),
|
|
42
|
+
eas: {
|
|
43
|
+
projectId: process.env.EAS_PROJECT_ID,
|
|
44
|
+
},
|
|
45
|
+
router,
|
|
46
|
+
...extra,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
return appConfig;
|
|
51
|
+
}
|
package/dist/expo.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function replaceTokens(str, env) {
|
|
2
|
+
if (typeof str !== 'string')
|
|
3
|
+
return str;
|
|
4
|
+
return str.replace(/\$\{([^}]+)\}|\$([A-Z0-9_]+)/g, (m, k1, k2) => {
|
|
5
|
+
const k = k1 || k2;
|
|
6
|
+
// existing data layer takes priority (guarded in case not defined)
|
|
7
|
+
if (typeof hasData === 'function' && hasData(k)) {
|
|
8
|
+
const val = typeof getData === 'function' ? getData(k) : undefined;
|
|
9
|
+
return val == null ? '' : String(val);
|
|
10
|
+
}
|
|
11
|
+
// environment variables
|
|
12
|
+
if (env && Object.prototype.hasOwnProperty.call(env, k)) {
|
|
13
|
+
const val = env[k];
|
|
14
|
+
return val == null ? '' : String(val);
|
|
15
|
+
}
|
|
16
|
+
// fallback
|
|
17
|
+
return '';
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function filterEnvByPrefix(env, prefix) {
|
|
21
|
+
const filtered = {};
|
|
22
|
+
for (const key in env) {
|
|
23
|
+
if (key.startsWith(prefix)) {
|
|
24
|
+
filtered[key] = env[key];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return filtered;
|
|
28
|
+
}
|
|
29
|
+
export function setUpConfig(config) {
|
|
30
|
+
const { extra = {}, ...other } = config.expo || {};
|
|
31
|
+
const router = extra['router'] ?
|
|
32
|
+
{ origin: false, ...extra['router'] }
|
|
33
|
+
: {
|
|
34
|
+
origin: false,
|
|
35
|
+
};
|
|
36
|
+
const appConfig = {
|
|
37
|
+
...config,
|
|
38
|
+
expo: {
|
|
39
|
+
...other,
|
|
40
|
+
extra: {
|
|
41
|
+
...filterEnvByPrefix(process.env, 'NEXT_PUBLIC_'),
|
|
42
|
+
eas: {
|
|
43
|
+
projectId: process.env.EAS_PROJECT_ID,
|
|
44
|
+
},
|
|
45
|
+
router,
|
|
46
|
+
...extra,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
return appConfig;
|
|
51
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
export function loadMergedEnv() {
|
|
5
|
+
const ENV_PATH = path.resolve(process.cwd(), '.env');
|
|
6
|
+
const ENV_LOCAL_PATH = path.resolve(process.cwd(), '.env.local');
|
|
7
|
+
// Load base .env
|
|
8
|
+
const base = fs.existsSync(ENV_PATH) ? dotenv.parse(fs.readFileSync(ENV_PATH)) : {};
|
|
9
|
+
// Load overrides .env.local
|
|
10
|
+
const local = fs.existsSync(ENV_LOCAL_PATH) ?
|
|
11
|
+
dotenv.parse(fs.readFileSync(ENV_LOCAL_PATH))
|
|
12
|
+
: {};
|
|
13
|
+
// Merge: local overrides base
|
|
14
|
+
const merged = {
|
|
15
|
+
...base,
|
|
16
|
+
...local,
|
|
17
|
+
};
|
|
18
|
+
// Inject into process.env (do NOT overwrite existing real env vars)
|
|
19
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
20
|
+
if (process.env[key] === undefined) {
|
|
21
|
+
process.env[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return process.env;
|
|
25
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Finds the workspace root by walking up from `startDir`.
|
|
5
|
+
* Works for Yarn/npm workspaces via package.json "workspaces".
|
|
6
|
+
* Also recognizes common mono-repo markers as fallback.
|
|
7
|
+
*/
|
|
8
|
+
export function detectWorkspaceAndConfigPath(startDir = process.cwd(), configFileName = 'app.config.json') {
|
|
9
|
+
const cwd = path.resolve(startDir);
|
|
10
|
+
const isWorkspaceRootDir = (dir) => {
|
|
11
|
+
// 1) package.json workspaces
|
|
12
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
13
|
+
if (fs.existsSync(pkgPath)) {
|
|
14
|
+
try {
|
|
15
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
16
|
+
if (pkg?.workspaces)
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// ignore
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// 2) other common monorepo root markers (fallback)
|
|
24
|
+
const markers = [
|
|
25
|
+
'pnpm-workspace.yaml',
|
|
26
|
+
'lerna.json',
|
|
27
|
+
'turbo.json',
|
|
28
|
+
'nx.json',
|
|
29
|
+
'.git', // good enough for many repos
|
|
30
|
+
];
|
|
31
|
+
return markers.some((m) => fs.existsSync(path.join(dir, m)));
|
|
32
|
+
};
|
|
33
|
+
const findUp = (from, predicate) => {
|
|
34
|
+
let dir = path.resolve(from);
|
|
35
|
+
while (true) {
|
|
36
|
+
if (predicate(dir))
|
|
37
|
+
return dir;
|
|
38
|
+
const parent = path.dirname(dir);
|
|
39
|
+
if (parent === dir)
|
|
40
|
+
return null; // reached filesystem root
|
|
41
|
+
dir = parent;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const workspaceRoot = findUp(cwd, isWorkspaceRootDir);
|
|
45
|
+
const isWorkspaceRoot = workspaceRoot !== null && workspaceRoot === cwd;
|
|
46
|
+
// If we are inside a workspace package, config lives at root.
|
|
47
|
+
// If we're already at root, config lives in cwd (same thing).
|
|
48
|
+
const configDir = workspaceRoot ?? cwd;
|
|
49
|
+
const configPath = path.join(configDir, configFileName);
|
|
50
|
+
return { cwd, workspaceRoot, isWorkspaceRoot, configDir, configPath };
|
|
51
|
+
}
|
|
52
|
+
export function loadAppConfig(configType = 'app', startDir = process.cwd()) {
|
|
53
|
+
const fileName = `${configType}.config.json`;
|
|
54
|
+
const meta = detectWorkspaceAndConfigPath(startDir, fileName);
|
|
55
|
+
if (!fs.existsSync(meta.configPath)) {
|
|
56
|
+
const where = meta.workspaceRoot ?
|
|
57
|
+
`workspace root: ${meta.workspaceRoot}`
|
|
58
|
+
: `cwd: ${meta.cwd}`;
|
|
59
|
+
throw new Error(`Could not find ${fileName} at ${meta.configPath} (detected from ${where}).`);
|
|
60
|
+
}
|
|
61
|
+
const raw = fs.readFileSync(meta.configPath, 'utf8');
|
|
62
|
+
return { config: JSON.parse(raw), meta };
|
|
63
|
+
}
|
|
64
|
+
export const loadProjectConfig = loadAppConfig;
|
|
65
|
+
export { loadMergedEnv } from './merge-env.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
export function loadMergedEnv() {
|
|
5
|
+
const ENV_PATH = path.resolve(process.cwd(), '.env');
|
|
6
|
+
const ENV_LOCAL_PATH = path.resolve(process.cwd(), '.env.local');
|
|
7
|
+
// Load base .env
|
|
8
|
+
const base = fs.existsSync(ENV_PATH) ? dotenv.parse(fs.readFileSync(ENV_PATH)) : {};
|
|
9
|
+
// Load overrides .env.local
|
|
10
|
+
const local = fs.existsSync(ENV_LOCAL_PATH) ?
|
|
11
|
+
dotenv.parse(fs.readFileSync(ENV_LOCAL_PATH))
|
|
12
|
+
: {};
|
|
13
|
+
// Merge: local overrides base
|
|
14
|
+
const merged = {
|
|
15
|
+
...base,
|
|
16
|
+
...local,
|
|
17
|
+
};
|
|
18
|
+
// Inject into process.env (do NOT overwrite existing real env vars)
|
|
19
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
20
|
+
if (process.env[key] === undefined) {
|
|
21
|
+
process.env[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return process.env;
|
|
25
|
+
}
|
package/dist/stack.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import { loadMergedEnv } from './project/merge-env.js';
|
|
3
|
+
loadMergedEnv();
|
|
4
|
+
//cdk deploy --context owner=cody --context region=us-west-1
|
|
5
|
+
const dev = 'dev';
|
|
6
|
+
export class CustomStack extends cdk.Stack {
|
|
7
|
+
ownerName;
|
|
8
|
+
region;
|
|
9
|
+
domainName;
|
|
10
|
+
enableNATGateway = false;
|
|
11
|
+
constructor(scope, id, props = {}) {
|
|
12
|
+
// 🔑 Resolve account + region BEFORE super()
|
|
13
|
+
const resolvedEnv = {
|
|
14
|
+
account: props.env?.account ?? process.env.AWS_ACCOUNT ?? cdk.Aws.ACCOUNT_ID, // final fallback (lazy token)
|
|
15
|
+
region: props.env?.region ?? process.env.AWS_REGION ?? 'us-east-2',
|
|
16
|
+
};
|
|
17
|
+
super(scope, id, {
|
|
18
|
+
...props,
|
|
19
|
+
env: resolvedEnv,
|
|
20
|
+
});
|
|
21
|
+
// ✅ Now it’s safe to read these
|
|
22
|
+
this.ownerName = props.ownerName ?? 'dev';
|
|
23
|
+
this.domainName = props.domainName;
|
|
24
|
+
this.region = resolvedEnv.region;
|
|
25
|
+
this.enableNATGateway = props.enableNATGateway ?? false;
|
|
26
|
+
}
|
|
27
|
+
initializeStackConfig() {
|
|
28
|
+
// Context overrides (deploy-time flags)
|
|
29
|
+
const ctxOwner = this.node.tryGetContext('owner') || dev;
|
|
30
|
+
const ctxRegion = this.node.tryGetContext('region') || 'us-east-2';
|
|
31
|
+
const ctxNat = this.node.tryGetContext('enableNATGateway');
|
|
32
|
+
if (ctxOwner)
|
|
33
|
+
this.ownerName = ctxOwner;
|
|
34
|
+
if (ctxRegion)
|
|
35
|
+
this.region = ctxRegion;
|
|
36
|
+
// NAT logic
|
|
37
|
+
if (ctxNat !== undefined) {
|
|
38
|
+
this.enableNATGateway = ctxNat === 'true';
|
|
39
|
+
}
|
|
40
|
+
// Production default
|
|
41
|
+
if (this.ownerName === 'prod' || this.ownerName === 'production') {
|
|
42
|
+
this.enableNATGateway = ctxNat !== 'false';
|
|
43
|
+
}
|
|
44
|
+
console.log('[Stack Config]', {
|
|
45
|
+
owner: this.ownerName,
|
|
46
|
+
region: this.region,
|
|
47
|
+
account: this.account,
|
|
48
|
+
natGateway: this.enableNATGateway,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function filterEnvByPrefix(env, prefix) {
|
|
2
|
+
const filtered = {};
|
|
3
|
+
for (const key in env) {
|
|
4
|
+
if (key.startsWith(prefix)) {
|
|
5
|
+
filtered[key] = env[key];
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
return filtered;
|
|
9
|
+
}
|
|
10
|
+
export function setUpConfig(config) {
|
|
11
|
+
const { extra = {}, ...other } = config.expo || {};
|
|
12
|
+
const router = extra['router'] ?
|
|
13
|
+
{ origin: false, ...extra['router'] }
|
|
14
|
+
: {
|
|
15
|
+
origin: false,
|
|
16
|
+
};
|
|
17
|
+
const appConfig = {
|
|
18
|
+
...config,
|
|
19
|
+
expo: {
|
|
20
|
+
...other,
|
|
21
|
+
extra: {
|
|
22
|
+
...filterEnvByPrefix(process.env, 'NEXT_PUBLIC_'),
|
|
23
|
+
eas: {
|
|
24
|
+
projectId: process.env.EAS_PROJECT_ID,
|
|
25
|
+
},
|
|
26
|
+
router,
|
|
27
|
+
...extra,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
return appConfig;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function loadMergedEnv(): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type WorkspaceDetectResult = {
|
|
2
|
+
cwd: string;
|
|
3
|
+
workspaceRoot: string | null;
|
|
4
|
+
isWorkspaceRoot: boolean;
|
|
5
|
+
configDir: string;
|
|
6
|
+
configPath: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Finds the workspace root by walking up from `startDir`.
|
|
10
|
+
* Works for Yarn/npm workspaces via package.json "workspaces".
|
|
11
|
+
* Also recognizes common mono-repo markers as fallback.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectWorkspaceAndConfigPath(startDir?: string, configFileName?: string): WorkspaceDetectResult;
|
|
14
|
+
type DefaultAppConfig = {
|
|
15
|
+
appleAppId?: string;
|
|
16
|
+
androidAppId?: string;
|
|
17
|
+
appName?: string;
|
|
18
|
+
easProjectId?: string;
|
|
19
|
+
appScheme?: string;
|
|
20
|
+
regions?: string[];
|
|
21
|
+
};
|
|
22
|
+
type DefaultDeployConfig = {
|
|
23
|
+
baseDomain?: string;
|
|
24
|
+
webSubdomain?: string;
|
|
25
|
+
apiSubdomain?: string;
|
|
26
|
+
defaultKeyPair?: string;
|
|
27
|
+
regions?: string[];
|
|
28
|
+
};
|
|
29
|
+
type ConfigTypeMap = {
|
|
30
|
+
app: DefaultAppConfig;
|
|
31
|
+
deployment: DefaultDeployConfig;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* If TType is a known key, use the mapped type.
|
|
35
|
+
* Otherwise use TCustom (default = unknown).
|
|
36
|
+
*/
|
|
37
|
+
type ResolveConfig<TType extends string, TCustom = unknown> = TType extends keyof ConfigTypeMap ? ConfigTypeMap[TType] : TCustom;
|
|
38
|
+
export declare function loadAppConfig<TCustom = unknown, TType extends string = 'app'>(configType?: TType, startDir?: string): {
|
|
39
|
+
config: ResolveConfig<TType, TCustom>;
|
|
40
|
+
meta: WorkspaceDetectResult;
|
|
41
|
+
};
|
|
42
|
+
export declare const loadProjectConfig: typeof loadAppConfig;
|
|
43
|
+
export { loadMergedEnv } from './merge-env.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loadMergedEnv(): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
export interface ICustomStack extends cdk.Stack {
|
|
4
|
+
ownerName: string;
|
|
5
|
+
region: string;
|
|
6
|
+
enableNATGateway: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface CustomStackProps extends cdk.StackProps {
|
|
9
|
+
ownerName?: string;
|
|
10
|
+
region?: string;
|
|
11
|
+
enableNATGateway?: boolean;
|
|
12
|
+
domainName?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare abstract class CustomStack extends cdk.Stack {
|
|
15
|
+
ownerName: string;
|
|
16
|
+
region: string;
|
|
17
|
+
domainName?: string;
|
|
18
|
+
protected enableNATGateway: boolean;
|
|
19
|
+
constructor(scope: Construct, id: string, props?: CustomStackProps);
|
|
20
|
+
initializeStackConfig(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function setUpConfig(config: any): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mono-labs/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.195",
|
|
4
4
|
"description": "A CLI tool for building and deploying projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"bin/",
|
|
86
86
|
"lib/",
|
|
87
87
|
"src/",
|
|
88
|
+
"dist/",
|
|
88
89
|
"types.d.ts",
|
|
89
90
|
"README.md"
|
|
90
91
|
]
|