hanzio 1.0.3 → 1.0.7
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/README.md +21 -1
- package/dist/index.d.ts +1 -0
- package/dist/secrets/index.d.ts +27 -0
- package/dist/secrets/vite.d.ts +9 -0
- package/dist/src/api-wrapper/index.js +250 -0
- package/dist/src/gzip/index.js +16 -0
- package/dist/src/index.js +1979 -0
- package/dist/src/jwt/index.js +19 -0
- package/dist/src/p-queue/index.js +439 -0
- package/dist/src/secrets/index.js +261 -0
- package/dist/src/secrets/vite.js +19 -0
- package/dist/src/sitemap/index.js +552 -0
- package/dist/src/zod/index.js +210 -0
- package/package.json +3 -2
- package/src/index.ts +2 -1
- package/src/secrets/index.ts +222 -0
- package/src/secrets/vite.ts +30 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// src/zod/index.ts
|
|
2
|
+
import { z as z3 } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/zod/jsonToZodSchemaMapper.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
function jsonToZodSchemaMapper(jsonObject, zodSchema, config) {
|
|
7
|
+
const result = {};
|
|
8
|
+
const shape = zodSchema instanceof z.ZodObject ? zodSchema.shape : {};
|
|
9
|
+
for (const key of Object.keys(shape)) {
|
|
10
|
+
const fieldConfig = config[key];
|
|
11
|
+
let value = jsonObject[key];
|
|
12
|
+
if (fieldConfig) {
|
|
13
|
+
value = fieldConfig(jsonObject);
|
|
14
|
+
}
|
|
15
|
+
if (shape[key] instanceof z.ZodObject && value && typeof value === "object") {
|
|
16
|
+
result[key] = jsonToZodSchemaMapper(value, shape[key], config[key] || {});
|
|
17
|
+
} else {
|
|
18
|
+
result[key] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return zodSchema.parse(result);
|
|
22
|
+
}
|
|
23
|
+
// src/zod/zodMinMaxFilter.ts
|
|
24
|
+
import { z as z2 } from "zod";
|
|
25
|
+
var zodMinMaxFilter = z2.object({
|
|
26
|
+
min: z2.number().optional(),
|
|
27
|
+
max: z2.number().optional()
|
|
28
|
+
});
|
|
29
|
+
function toGteLteFilter(filter) {
|
|
30
|
+
if (!filter)
|
|
31
|
+
return;
|
|
32
|
+
const hasMin = filter.min !== undefined;
|
|
33
|
+
const hasMax = filter.max !== undefined;
|
|
34
|
+
if (!hasMin && !hasMax)
|
|
35
|
+
return;
|
|
36
|
+
return {
|
|
37
|
+
...hasMin && { gte: filter.min },
|
|
38
|
+
...hasMax && { lte: filter.max }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// src/zod/zodToTypeString.ts
|
|
42
|
+
function getDefProp(def, prop) {
|
|
43
|
+
return def?.[prop];
|
|
44
|
+
}
|
|
45
|
+
function zodToTypeString(schema, indent = 0) {
|
|
46
|
+
const pad = " ".repeat(indent);
|
|
47
|
+
const innerPad = " ".repeat(indent + 1);
|
|
48
|
+
const def = schema._zod?.def ?? schema._def;
|
|
49
|
+
if (!def)
|
|
50
|
+
return "unknown";
|
|
51
|
+
const schemaType = getDefProp(def, "type") ?? getDefProp(def, "typeName");
|
|
52
|
+
switch (schemaType) {
|
|
53
|
+
case "object": {
|
|
54
|
+
const shape = getDefProp(def, "shape");
|
|
55
|
+
if (!shape || Object.keys(shape).length === 0)
|
|
56
|
+
return "{}";
|
|
57
|
+
const fields = Object.entries(shape).map(([key, value]) => {
|
|
58
|
+
const valueType = getDefProp(value._zod?.def ?? value._def, "type");
|
|
59
|
+
const isOptional = valueType === "optional";
|
|
60
|
+
const innerSchema = isOptional ? getDefProp(value._zod?.def ?? value._def, "innerType") ?? value : value;
|
|
61
|
+
const typeStr = zodToTypeString(innerSchema, indent + 1);
|
|
62
|
+
return `${innerPad}${key}${isOptional ? "?" : ""}: ${typeStr}`;
|
|
63
|
+
});
|
|
64
|
+
return `{
|
|
65
|
+
${fields.join(`
|
|
66
|
+
`)}
|
|
67
|
+
${pad}}`;
|
|
68
|
+
}
|
|
69
|
+
case "array": {
|
|
70
|
+
const itemType = getDefProp(def, "element") ?? getDefProp(def, "type");
|
|
71
|
+
return itemType ? `${zodToTypeString(itemType, indent)}[]` : "unknown[]";
|
|
72
|
+
}
|
|
73
|
+
case "string":
|
|
74
|
+
return "string";
|
|
75
|
+
case "number":
|
|
76
|
+
return "number";
|
|
77
|
+
case "boolean":
|
|
78
|
+
return "boolean";
|
|
79
|
+
case "date":
|
|
80
|
+
return "Date";
|
|
81
|
+
case "null":
|
|
82
|
+
return "null";
|
|
83
|
+
case "undefined":
|
|
84
|
+
return "undefined";
|
|
85
|
+
case "any":
|
|
86
|
+
return "any";
|
|
87
|
+
case "unknown":
|
|
88
|
+
return "unknown";
|
|
89
|
+
case "record": {
|
|
90
|
+
const valueType = getDefProp(def, "valueType");
|
|
91
|
+
return valueType ? `Record<string, ${zodToTypeString(valueType, indent)}>` : "Record<string, unknown>";
|
|
92
|
+
}
|
|
93
|
+
case "enum": {
|
|
94
|
+
const values = getDefProp(def, "values");
|
|
95
|
+
return values ? values.map((v) => `"${v}"`).join(" | ") : "string";
|
|
96
|
+
}
|
|
97
|
+
case "literal": {
|
|
98
|
+
const value = getDefProp(def, "value");
|
|
99
|
+
return typeof value === "string" ? `"${value}"` : String(value);
|
|
100
|
+
}
|
|
101
|
+
case "union": {
|
|
102
|
+
const options = getDefProp(def, "options");
|
|
103
|
+
return options ? options.map((o) => zodToTypeString(o, indent)).join(" | ") : "unknown";
|
|
104
|
+
}
|
|
105
|
+
case "optional": {
|
|
106
|
+
const inner = getDefProp(def, "innerType");
|
|
107
|
+
return inner ? `${zodToTypeString(inner, indent)} | undefined` : "unknown";
|
|
108
|
+
}
|
|
109
|
+
case "nullable": {
|
|
110
|
+
const inner = getDefProp(def, "innerType");
|
|
111
|
+
return inner ? `${zodToTypeString(inner, indent)} | null` : "unknown";
|
|
112
|
+
}
|
|
113
|
+
case "default": {
|
|
114
|
+
const inner = getDefProp(def, "innerType");
|
|
115
|
+
return inner ? zodToTypeString(inner, indent) : "unknown";
|
|
116
|
+
}
|
|
117
|
+
case "ZodObject":
|
|
118
|
+
case "ZodArray":
|
|
119
|
+
case "ZodString":
|
|
120
|
+
case "ZodNumber":
|
|
121
|
+
case "ZodBoolean":
|
|
122
|
+
case "ZodDate":
|
|
123
|
+
case "ZodNull":
|
|
124
|
+
case "ZodUndefined":
|
|
125
|
+
case "ZodAny":
|
|
126
|
+
case "ZodUnknown":
|
|
127
|
+
case "ZodRecord":
|
|
128
|
+
case "ZodEnum":
|
|
129
|
+
case "ZodLiteral":
|
|
130
|
+
case "ZodUnion":
|
|
131
|
+
case "ZodOptional":
|
|
132
|
+
case "ZodNullable":
|
|
133
|
+
case "ZodDefault":
|
|
134
|
+
return zodToTypeString(schema, indent);
|
|
135
|
+
default:
|
|
136
|
+
return "unknown";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function zodToExample(schema) {
|
|
140
|
+
const def = schema._zod?.def ?? schema._def;
|
|
141
|
+
if (!def)
|
|
142
|
+
return null;
|
|
143
|
+
const schemaType = getDefProp(def, "type") ?? getDefProp(def, "typeName");
|
|
144
|
+
switch (schemaType) {
|
|
145
|
+
case "object": {
|
|
146
|
+
const shape = getDefProp(def, "shape");
|
|
147
|
+
if (!shape)
|
|
148
|
+
return {};
|
|
149
|
+
const result = {};
|
|
150
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
151
|
+
const valueType = getDefProp(value._zod?.def ?? value._def, "type");
|
|
152
|
+
const isOptional = valueType === "optional";
|
|
153
|
+
if (!isOptional) {
|
|
154
|
+
result[key] = zodToExample(value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
case "array": {
|
|
160
|
+
const itemType = getDefProp(def, "element") ?? getDefProp(def, "type");
|
|
161
|
+
return itemType ? [zodToExample(itemType)] : [];
|
|
162
|
+
}
|
|
163
|
+
case "string":
|
|
164
|
+
return "";
|
|
165
|
+
case "number":
|
|
166
|
+
return 0;
|
|
167
|
+
case "boolean":
|
|
168
|
+
return false;
|
|
169
|
+
case "enum": {
|
|
170
|
+
const values = getDefProp(def, "values");
|
|
171
|
+
return values?.[0] ?? "";
|
|
172
|
+
}
|
|
173
|
+
case "literal":
|
|
174
|
+
return getDefProp(def, "value");
|
|
175
|
+
case "optional":
|
|
176
|
+
case "default": {
|
|
177
|
+
const inner = getDefProp(def, "innerType");
|
|
178
|
+
return inner ? zodToExample(inner) : null;
|
|
179
|
+
}
|
|
180
|
+
case "record":
|
|
181
|
+
return {};
|
|
182
|
+
default:
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/zod/index.ts
|
|
188
|
+
function createZId(typeName) {
|
|
189
|
+
return z3.string().min(1, `${typeName} ID is required`).brand();
|
|
190
|
+
}
|
|
191
|
+
function zSingleOrArray(schema) {
|
|
192
|
+
return z3.union([z3.array(schema), schema]);
|
|
193
|
+
}
|
|
194
|
+
function normalizeSingleOrArray(value) {
|
|
195
|
+
if (value == null)
|
|
196
|
+
return [];
|
|
197
|
+
if (Array.isArray(value))
|
|
198
|
+
return [...value];
|
|
199
|
+
return [value];
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
zodToTypeString,
|
|
203
|
+
zodToExample,
|
|
204
|
+
zodMinMaxFilter,
|
|
205
|
+
zSingleOrArray,
|
|
206
|
+
toGteLteFilter,
|
|
207
|
+
normalizeSingleOrArray,
|
|
208
|
+
jsonToZodSchemaMapper,
|
|
209
|
+
createZId
|
|
210
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hanzio",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "A set of utility functions for TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "bun run build:js && bun run build:types",
|
|
41
|
-
"build:js": "bun build ./src/index.ts ./src/zod/index.ts ./src/api-wrapper/index.ts ./src/jwt/index.ts ./src/gzip/index.ts ./src/sitemap/index.ts ./src/p-queue/index.ts --outdir ./dist --target node --packages external",
|
|
41
|
+
"build:js": "bun build ./src/index.ts ./src/zod/index.ts ./src/api-wrapper/index.ts ./src/jwt/index.ts ./src/gzip/index.ts ./src/sitemap/index.ts ./src/p-queue/index.ts ./src/secrets/index.ts ./src/secrets/vite.ts --outdir ./dist --target node --packages external",
|
|
42
42
|
"build:types": "tsgo -p tsconfig.build.json",
|
|
43
43
|
"prepublishOnly": "bun run build",
|
|
44
44
|
"publish:patch": "npm version patch && npm publish",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"typescript": "^5.7.0"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
+
"@infisical/sdk": "^5.0.2",
|
|
62
63
|
"jose": "^6.2.3",
|
|
63
64
|
"pako": "^2.1.0",
|
|
64
65
|
"zod": "^4.3.6"
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { InfisicalSDK } from '@infisical/sdk'
|
|
2
|
+
import { networkInterfaces } from 'node:os'
|
|
3
|
+
import { colorize, createCoolLogger } from '../cool-console-log'
|
|
4
|
+
|
|
5
|
+
const DEFAULT_INFISICAL_SITE_URL = 'https://eu.infisical.com'
|
|
6
|
+
const LOCAL_IP_VALUE = 'LOCAL_IP'
|
|
7
|
+
const VPN_INTERFACE_RE = /^(utun|tun|tailscale|wg|ipsec|ppp)/i
|
|
8
|
+
const logger = createCoolLogger()
|
|
9
|
+
|
|
10
|
+
export type SecretEnvironment = 'dev' | 'staging' | 'prod'
|
|
11
|
+
|
|
12
|
+
export type DefineSecretSetOptions<SecretKey extends string> = {
|
|
13
|
+
readonly projectId: string
|
|
14
|
+
readonly siteUrl?: string
|
|
15
|
+
readonly environment?: SecretEnvironment | (() => SecretEnvironment)
|
|
16
|
+
readonly clientIdEnvKey?: string
|
|
17
|
+
readonly clientSecretEnvKey?: string
|
|
18
|
+
readonly loader?: SecretSetLoader<SecretKey>
|
|
19
|
+
readonly getLocalIp?: () => string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SecretSetLoaderContext<SecretKey extends string> = {
|
|
23
|
+
readonly keys: readonly SecretKey[]
|
|
24
|
+
readonly projectId: string
|
|
25
|
+
readonly environment: SecretEnvironment
|
|
26
|
+
readonly siteUrl: string
|
|
27
|
+
readonly clientIdEnvKey: string
|
|
28
|
+
readonly clientSecretEnvKey: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type SecretSetLoader<SecretKey extends string> = (
|
|
32
|
+
context: SecretSetLoaderContext<SecretKey>
|
|
33
|
+
) => Promise<Partial<Record<SecretKey, string>>>
|
|
34
|
+
|
|
35
|
+
export type SecretSet<SecretKey extends string> = {
|
|
36
|
+
secret: (key: SecretKey) => string
|
|
37
|
+
secrets: () => Record<SecretKey, string>
|
|
38
|
+
reload: () => Promise<SecretSet<SecretKey>>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type InfisicalSecret = {
|
|
42
|
+
secretKey: string
|
|
43
|
+
secretValue: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export * from './vite'
|
|
47
|
+
|
|
48
|
+
export function getSecretEnvironment(): SecretEnvironment {
|
|
49
|
+
const env = process.env.SECRETS_ENV || process.env.NODE_ENV
|
|
50
|
+
if (env === 'production' || env === 'prod') return 'prod'
|
|
51
|
+
if (env === 'staging') return 'staging'
|
|
52
|
+
return 'dev'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function defineSecretSet<
|
|
56
|
+
const SecretKeys extends readonly string[]
|
|
57
|
+
>(
|
|
58
|
+
keys: SecretKeys,
|
|
59
|
+
options: DefineSecretSetOptions<SecretKeys[number]>
|
|
60
|
+
): Promise<SecretSet<SecretKeys[number]>> {
|
|
61
|
+
type SecretKey = SecretKeys[number]
|
|
62
|
+
|
|
63
|
+
const keySet = [...new Set(keys)] as SecretKey[]
|
|
64
|
+
const loader = options.loader ?? loadInfisicalSecrets
|
|
65
|
+
const getLocalIp = options.getLocalIp ?? getLocalIpAddress
|
|
66
|
+
let cachedSecrets: Record<SecretKey, string> | null = null
|
|
67
|
+
|
|
68
|
+
const resolveValue = (value: string) => {
|
|
69
|
+
if (value === LOCAL_IP_VALUE) return getLocalIp()
|
|
70
|
+
return value
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const loadSecrets = async (force = false) => {
|
|
74
|
+
const envSecrets = readEnvSecrets(keySet, force ? cachedSecrets : null)
|
|
75
|
+
const keysMissingFromEnv = keySet.filter((key) => !envSecrets[key])
|
|
76
|
+
const environment = resolveEnvironment(options.environment)
|
|
77
|
+
|
|
78
|
+
logSecretEnvironment(environment, keySet.length)
|
|
79
|
+
|
|
80
|
+
const loadedSecrets: Partial<Record<SecretKey, string>> =
|
|
81
|
+
keysMissingFromEnv.length === 0 && !force
|
|
82
|
+
? {}
|
|
83
|
+
: await loader({
|
|
84
|
+
keys: keySet,
|
|
85
|
+
projectId: options.projectId,
|
|
86
|
+
environment,
|
|
87
|
+
siteUrl: options.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
|
|
88
|
+
clientIdEnvKey: options.clientIdEnvKey ?? 'INFISICAL_CLIENT_ID',
|
|
89
|
+
clientSecretEnvKey:
|
|
90
|
+
options.clientSecretEnvKey ?? 'INFISICAL_CLIENT_SECRET'
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const missingKeys = keySet.filter(
|
|
94
|
+
(key) => !(envSecrets[key] ?? loadedSecrets[key])
|
|
95
|
+
)
|
|
96
|
+
if (missingKeys.length > 0) {
|
|
97
|
+
throw new Error(`Missing secrets: ${missingKeys.join(', ')}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const nextSecrets = Object.fromEntries(
|
|
101
|
+
keySet.map((key) => [
|
|
102
|
+
key,
|
|
103
|
+
resolveValue((envSecrets[key] ?? loadedSecrets[key]) as string)
|
|
104
|
+
])
|
|
105
|
+
) as Record<SecretKey, string>
|
|
106
|
+
|
|
107
|
+
for (const [key, value] of Object.entries(nextSecrets)) {
|
|
108
|
+
process.env[key] = value as string
|
|
109
|
+
}
|
|
110
|
+
cachedSecrets = nextSecrets
|
|
111
|
+
return nextSecrets
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const secretSet: SecretSet<SecretKey> = {
|
|
115
|
+
secret(key) {
|
|
116
|
+
const value = cachedSecrets?.[key] ?? process.env[key]
|
|
117
|
+
if (!value) {
|
|
118
|
+
throw new Error(`Secret ${key} not found`)
|
|
119
|
+
}
|
|
120
|
+
return resolveValue(value)
|
|
121
|
+
},
|
|
122
|
+
secrets() {
|
|
123
|
+
if (!cachedSecrets) {
|
|
124
|
+
throw new Error('Secrets not initialized.')
|
|
125
|
+
}
|
|
126
|
+
return cachedSecrets
|
|
127
|
+
},
|
|
128
|
+
async reload() {
|
|
129
|
+
await loadSecrets(true)
|
|
130
|
+
return secretSet
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await loadSecrets()
|
|
135
|
+
return secretSet
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function loadInfisicalSecrets<SecretKey extends string>({
|
|
139
|
+
keys,
|
|
140
|
+
projectId,
|
|
141
|
+
environment,
|
|
142
|
+
siteUrl,
|
|
143
|
+
clientIdEnvKey,
|
|
144
|
+
clientSecretEnvKey
|
|
145
|
+
}: SecretSetLoaderContext<SecretKey>): Promise<
|
|
146
|
+
Partial<Record<SecretKey, string>>
|
|
147
|
+
> {
|
|
148
|
+
const clientId = process.env[clientIdEnvKey]
|
|
149
|
+
const clientSecret = process.env[clientSecretEnvKey]
|
|
150
|
+
|
|
151
|
+
if (!clientId || !clientSecret) {
|
|
152
|
+
throw new Error('Missing Infisical credentials')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const client = new InfisicalSDK({ siteUrl })
|
|
156
|
+
|
|
157
|
+
await client.auth().universalAuth.login({
|
|
158
|
+
clientId,
|
|
159
|
+
clientSecret
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const { secrets } = (await client.secrets().listSecrets({
|
|
163
|
+
environment,
|
|
164
|
+
projectId
|
|
165
|
+
})) as { secrets: InfisicalSecret[] }
|
|
166
|
+
|
|
167
|
+
const wantedKeys = new Set<string>(keys)
|
|
168
|
+
return Object.fromEntries(
|
|
169
|
+
secrets
|
|
170
|
+
.filter((secret) => wantedKeys.has(secret.secretKey))
|
|
171
|
+
.map((secret) => [secret.secretKey, secret.secretValue])
|
|
172
|
+
) as Partial<Record<SecretKey, string>>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function resolveEnvironment(
|
|
176
|
+
environment: DefineSecretSetOptions<string>['environment']
|
|
177
|
+
): SecretEnvironment {
|
|
178
|
+
if (typeof environment === 'function') return environment()
|
|
179
|
+
return environment ?? getSecretEnvironment()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function logSecretEnvironment(
|
|
183
|
+
environment: SecretEnvironment,
|
|
184
|
+
secretCount: number
|
|
185
|
+
): void {
|
|
186
|
+
logger.info(colorize('Loading secrets', 'cyan', 'bold'), {
|
|
187
|
+
environment: colorize(environment, 'brightCyan', 'bold'),
|
|
188
|
+
count: secretCount
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function readEnvSecrets<SecretKey extends string>(
|
|
193
|
+
keys: readonly SecretKey[],
|
|
194
|
+
previousSecrets: Record<SecretKey, string> | null = null
|
|
195
|
+
): Partial<Record<SecretKey, string>> {
|
|
196
|
+
return Object.fromEntries(
|
|
197
|
+
keys
|
|
198
|
+
.filter((key) => {
|
|
199
|
+
const value = process.env[key]
|
|
200
|
+
return value && value !== previousSecrets?.[key]
|
|
201
|
+
})
|
|
202
|
+
.map((key) => [key, process.env[key] as string])
|
|
203
|
+
) as Partial<Record<SecretKey, string>>
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function getLocalIpAddress(): string {
|
|
207
|
+
const interfaces = networkInterfaces()
|
|
208
|
+
|
|
209
|
+
for (const name of Object.keys(interfaces)) {
|
|
210
|
+
if (VPN_INTERFACE_RE.test(name)) continue
|
|
211
|
+
const nets = interfaces[name]
|
|
212
|
+
if (!nets) continue
|
|
213
|
+
|
|
214
|
+
for (const net of nets) {
|
|
215
|
+
if (net.family === 'IPv4' && !net.internal) {
|
|
216
|
+
return net.address
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return '127.0.0.1'
|
|
222
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SecretSet } from '.'
|
|
2
|
+
|
|
3
|
+
export type ViteSecretSetPlugin = {
|
|
4
|
+
name: string
|
|
5
|
+
config: () => {
|
|
6
|
+
define: Record<string, string>
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getViteDefine<SecretKey extends string>(
|
|
11
|
+
secretSet: SecretSet<SecretKey>
|
|
12
|
+
): Record<string, string> {
|
|
13
|
+
return Object.fromEntries(
|
|
14
|
+
Object.entries(secretSet.secrets()).map(([key, value]) => [
|
|
15
|
+
`import.meta.env.${key}`,
|
|
16
|
+
JSON.stringify(value)
|
|
17
|
+
])
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function viteSecretSetPlugin<SecretKey extends string>(
|
|
22
|
+
secretSet: SecretSet<SecretKey>
|
|
23
|
+
): ViteSecretSetPlugin {
|
|
24
|
+
return {
|
|
25
|
+
name: 'hanzio-secret-set',
|
|
26
|
+
config: () => ({
|
|
27
|
+
define: getViteDefine(secretSet)
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|