@barekey/sdk 0.1.0 → 0.1.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/README.md +9 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +15 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/evaluate.d.ts.map +1 -1
- package/dist/internal/evaluate.js +57 -7
- package/dist/internal/node-runtime.d.ts +3 -1
- package/dist/internal/node-runtime.d.ts.map +1 -1
- package/dist/internal/node-runtime.js +8 -4
- package/dist/internal/public-runtime.d.ts +14 -0
- package/dist/internal/public-runtime.d.ts.map +1 -0
- package/dist/internal/public-runtime.js +78 -0
- package/dist/internal/typegen.d.ts +16 -3
- package/dist/internal/typegen.d.ts.map +1 -1
- package/dist/internal/typegen.js +123 -12
- package/dist/public-client.d.ts +36 -0
- package/dist/public-client.d.ts.map +1 -0
- package/dist/public-client.js +150 -0
- package/dist/public-types.d.ts +26 -0
- package/dist/public-types.d.ts.map +1 -0
- package/dist/public-types.js +1 -0
- package/dist/public.d.ts +6 -0
- package/dist/public.d.ts.map +1 -0
- package/dist/public.js +3 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +3 -0
- package/dist/types.d.ts +14 -2
- package/dist/types.d.ts.map +1 -1
- package/generated.public.d.ts +8 -0
- package/{generated.d.ts → generated.server.d.ts} +8 -2
- package/index.d.ts +0 -1
- package/package.json +18 -3
- package/public.d.ts +2 -0
- package/server.d.ts +2 -0
- package/src/client.ts +17 -2
- package/src/index.ts +7 -0
- package/src/internal/evaluate.ts +83 -7
- package/src/internal/node-runtime.ts +11 -5
- package/src/internal/public-runtime.ts +123 -0
- package/src/internal/typegen.ts +203 -15
- package/src/public-client.ts +229 -0
- package/src/public-types.ts +57 -0
- package/src/public.ts +69 -0
- package/src/server.ts +60 -0
- package/src/types.ts +29 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FsNotAvailableError,
|
|
3
|
+
InvalidConfigurationProvidedError,
|
|
4
|
+
NoConfigurationProvidedError,
|
|
5
|
+
} from "../errors.js";
|
|
6
|
+
import type { PublicBarekeyClientOptions } from "../public-types.js";
|
|
7
|
+
import type { BarekeyJsonConfig, BarekeyStandardSchemaV1 } from "../types.js";
|
|
8
|
+
import { normalizeBaseUrl } from "./http.js";
|
|
9
|
+
import { isFilesystemAvailable, loadBarekeyJsonConfig } from "./node-runtime.js";
|
|
10
|
+
|
|
11
|
+
const DEFAULT_BAREKEY_API_URL = "https://api.barekey.dev";
|
|
12
|
+
|
|
13
|
+
type BarekeyResolvedScope = {
|
|
14
|
+
organization: string;
|
|
15
|
+
project: string;
|
|
16
|
+
environment: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type BarekeyPublicRuntimeContext = BarekeyResolvedScope & {
|
|
20
|
+
baseUrl: string;
|
|
21
|
+
requirements?: BarekeyStandardSchemaV1;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function readConfigString(value: unknown): string | undefined {
|
|
25
|
+
return typeof value === "string" ? value.trim() : undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeScope(input: {
|
|
29
|
+
organization?: unknown;
|
|
30
|
+
project?: unknown;
|
|
31
|
+
environment?: unknown;
|
|
32
|
+
source: string;
|
|
33
|
+
}): BarekeyResolvedScope {
|
|
34
|
+
const organization = readConfigString(input.organization) ?? "";
|
|
35
|
+
const project = readConfigString(input.project) ?? "";
|
|
36
|
+
const environment = readConfigString(input.environment) ?? "";
|
|
37
|
+
if (organization.length === 0 || project.length === 0 || environment.length === 0) {
|
|
38
|
+
throw new InvalidConfigurationProvidedError({
|
|
39
|
+
message: `${input.source} must provide organization, project, and environment.`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
organization,
|
|
45
|
+
project,
|
|
46
|
+
environment,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalizeJsonConfig(
|
|
51
|
+
input: BarekeyJsonConfig | Record<string, unknown>,
|
|
52
|
+
source: string,
|
|
53
|
+
): BarekeyResolvedScope {
|
|
54
|
+
return normalizeScope({
|
|
55
|
+
organization: input.organization ?? input.org,
|
|
56
|
+
project: input.project,
|
|
57
|
+
environment: input.environment ?? input.stage,
|
|
58
|
+
source,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function resolveScope(options: PublicBarekeyClientOptions): Promise<BarekeyResolvedScope> {
|
|
63
|
+
const explicitOrganization = "organization" in options ? options.organization : undefined;
|
|
64
|
+
const explicitProject = "project" in options ? options.project : undefined;
|
|
65
|
+
const explicitEnvironment = "environment" in options ? options.environment : undefined;
|
|
66
|
+
const explicitJson = "json" in options ? options.json : undefined;
|
|
67
|
+
|
|
68
|
+
const explicitCount =
|
|
69
|
+
Number(explicitOrganization !== undefined) +
|
|
70
|
+
Number(explicitProject !== undefined) +
|
|
71
|
+
Number(explicitEnvironment !== undefined);
|
|
72
|
+
|
|
73
|
+
if (explicitJson !== undefined && explicitCount > 0) {
|
|
74
|
+
throw new InvalidConfigurationProvidedError({
|
|
75
|
+
message: "Pass either json or organization/project/environment, not both.",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (explicitCount > 0 && explicitCount < 3) {
|
|
80
|
+
throw new InvalidConfigurationProvidedError({
|
|
81
|
+
message: "organization, project, and environment must be provided together.",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (explicitJson !== undefined) {
|
|
86
|
+
return normalizeJsonConfig(explicitJson, "The provided json configuration");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (explicitCount === 3) {
|
|
90
|
+
return normalizeScope({
|
|
91
|
+
organization: explicitOrganization,
|
|
92
|
+
project: explicitProject,
|
|
93
|
+
environment: explicitEnvironment,
|
|
94
|
+
source: "The provided Barekey configuration",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const loadedConfig = await loadBarekeyJsonConfig();
|
|
99
|
+
if (loadedConfig === null) {
|
|
100
|
+
if (!(await isFilesystemAvailable())) {
|
|
101
|
+
throw new FsNotAvailableError();
|
|
102
|
+
}
|
|
103
|
+
throw new NoConfigurationProvidedError({
|
|
104
|
+
message: "No Barekey configuration was found and no barekey.json file could be loaded.",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return normalizeJsonConfig(
|
|
109
|
+
loadedConfig.json,
|
|
110
|
+
`The barekey.json file at ${loadedConfig.path}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function resolvePublicRuntimeContext(
|
|
115
|
+
options: PublicBarekeyClientOptions,
|
|
116
|
+
): Promise<BarekeyPublicRuntimeContext> {
|
|
117
|
+
const scope = await resolveScope(options);
|
|
118
|
+
return {
|
|
119
|
+
...scope,
|
|
120
|
+
baseUrl: normalizeBaseUrl(options.baseUrl?.trim() || DEFAULT_BAREKEY_API_URL),
|
|
121
|
+
requirements: options.requirements,
|
|
122
|
+
};
|
|
123
|
+
}
|
package/src/internal/typegen.ts
CHANGED
|
@@ -3,10 +3,15 @@ import {
|
|
|
3
3
|
resolveInstalledSdkTypegenTarget,
|
|
4
4
|
writeTextFileAtomic,
|
|
5
5
|
} from "./node-runtime.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
BarekeyRolloutFunction,
|
|
8
|
+
BarekeyRolloutMilestone,
|
|
9
|
+
BarekeyTypegenResult,
|
|
10
|
+
} from "../types.js";
|
|
7
11
|
|
|
8
12
|
export type TypegenManifestVariable = {
|
|
9
13
|
name: string;
|
|
14
|
+
visibility: "private" | "public";
|
|
10
15
|
kind: "secret" | "ab_roll" | "rollout";
|
|
11
16
|
declaredType: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
12
17
|
required: boolean;
|
|
@@ -14,7 +19,7 @@ export type TypegenManifestVariable = {
|
|
|
14
19
|
typeScriptType: string;
|
|
15
20
|
valueATypeScriptType: string | null;
|
|
16
21
|
valueBTypeScriptType: string | null;
|
|
17
|
-
rolloutFunction:
|
|
22
|
+
rolloutFunction: BarekeyRolloutFunction | null;
|
|
18
23
|
rolloutMilestones: Array<BarekeyRolloutMilestone> | null;
|
|
19
24
|
};
|
|
20
25
|
|
|
@@ -29,6 +34,23 @@ export type TypegenManifest = {
|
|
|
29
34
|
};
|
|
30
35
|
|
|
31
36
|
const MANIFEST_VERSION_PATTERN = /\/\* barekey-manifest-version: ([^\n]+) \*\//;
|
|
37
|
+
const TYPEGEN_METADATA_VERSION = 1;
|
|
38
|
+
|
|
39
|
+
type TypegenMetadata = {
|
|
40
|
+
version: number;
|
|
41
|
+
last: string;
|
|
42
|
+
baseUrl: string | null;
|
|
43
|
+
orgSlug: string | null;
|
|
44
|
+
projectSlug: string | null;
|
|
45
|
+
stageSlug: string | null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type TypegenMetadataIdentity = {
|
|
49
|
+
baseUrl: string;
|
|
50
|
+
orgSlug: string;
|
|
51
|
+
projectSlug: string;
|
|
52
|
+
stageSlug: string;
|
|
53
|
+
};
|
|
32
54
|
|
|
33
55
|
function renderLinearMilestones(milestones: Array<BarekeyRolloutMilestone>): string {
|
|
34
56
|
if (milestones.length === 0) {
|
|
@@ -43,6 +65,17 @@ function renderLinearMilestones(milestones: Array<BarekeyRolloutMilestone>): str
|
|
|
43
65
|
.join(", ")}]`;
|
|
44
66
|
}
|
|
45
67
|
|
|
68
|
+
function renderRolloutMetadataType(row: TypegenManifestVariable): string {
|
|
69
|
+
const renderedMilestones = renderLinearMilestones(row.rolloutMilestones ?? []);
|
|
70
|
+
if (row.rolloutFunction === "step") {
|
|
71
|
+
return `Step<${renderedMilestones}>`;
|
|
72
|
+
}
|
|
73
|
+
if (row.rolloutFunction === "ease_in_out") {
|
|
74
|
+
return `EaseInOut<${renderedMilestones}>`;
|
|
75
|
+
}
|
|
76
|
+
return `Linear<${renderedMilestones}>`;
|
|
77
|
+
}
|
|
78
|
+
|
|
46
79
|
function renderVariableType(row: TypegenManifestVariable): string {
|
|
47
80
|
if (row.kind === "secret") {
|
|
48
81
|
return `Env<Secret, ${row.typeScriptType}>`;
|
|
@@ -52,14 +85,21 @@ function renderVariableType(row: TypegenManifestVariable): string {
|
|
|
52
85
|
return `Env<AB, ${row.typeScriptType}>`;
|
|
53
86
|
}
|
|
54
87
|
|
|
55
|
-
return `Env<AB, ${row.typeScriptType},
|
|
56
|
-
row.rolloutMilestones ?? [],
|
|
57
|
-
)}>>`;
|
|
88
|
+
return `Env<AB, ${row.typeScriptType}, ${renderRolloutMetadataType(row)}>`;
|
|
58
89
|
}
|
|
59
90
|
|
|
60
|
-
function buildGeneratedTypesContents(
|
|
91
|
+
function buildGeneratedTypesContents(
|
|
92
|
+
manifest: TypegenManifest,
|
|
93
|
+
input: {
|
|
94
|
+
typeModulePath: "./dist/types.js" | "./dist/public-types.js";
|
|
95
|
+
declaredModulePath: "./dist/types.js" | "./dist/public-types.js";
|
|
96
|
+
interfaceName: "BarekeyGeneratedTypeMap" | "BarekeyPublicGeneratedTypeMap";
|
|
97
|
+
include: (row: TypegenManifestVariable) => boolean;
|
|
98
|
+
},
|
|
99
|
+
): string {
|
|
61
100
|
const mapLines = manifest.variables
|
|
62
101
|
.slice()
|
|
102
|
+
.filter(input.include)
|
|
63
103
|
.sort((left, right) => left.name.localeCompare(right.name))
|
|
64
104
|
.map((row) => ` ${JSON.stringify(row.name)}: ${renderVariableType(row)};`)
|
|
65
105
|
.join("\n");
|
|
@@ -68,10 +108,10 @@ function buildGeneratedTypesContents(manifest: TypegenManifest): string {
|
|
|
68
108
|
/* This file is generated by barekey typegen. */
|
|
69
109
|
/* barekey-manifest-version: ${manifest.manifestVersion} */
|
|
70
110
|
|
|
71
|
-
import type { AB, Env, Linear, Secret } from "
|
|
111
|
+
import type { AB, EaseInOut, Env, Linear, Secret, Step } from "${input.typeModulePath}";
|
|
72
112
|
|
|
73
|
-
declare module "
|
|
74
|
-
interface
|
|
113
|
+
declare module "${input.declaredModulePath}" {
|
|
114
|
+
interface ${input.interfaceName} {
|
|
75
115
|
${mapLines.length > 0 ? mapLines : ""}
|
|
76
116
|
}
|
|
77
117
|
}
|
|
@@ -89,36 +129,184 @@ function readManifestVersion(contents: string | null): string | null {
|
|
|
89
129
|
return match?.[1]?.trim() ?? null;
|
|
90
130
|
}
|
|
91
131
|
|
|
132
|
+
function parseTypegenMetadata(contents: string | null): TypegenMetadata | null {
|
|
133
|
+
if (contents === null) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(contents) as unknown;
|
|
139
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const candidate = parsed as {
|
|
144
|
+
version?: unknown;
|
|
145
|
+
last?: unknown;
|
|
146
|
+
baseUrl?: unknown;
|
|
147
|
+
orgSlug?: unknown;
|
|
148
|
+
projectSlug?: unknown;
|
|
149
|
+
stageSlug?: unknown;
|
|
150
|
+
};
|
|
151
|
+
if (
|
|
152
|
+
candidate.version !== TYPEGEN_METADATA_VERSION ||
|
|
153
|
+
typeof candidate.last !== "string" ||
|
|
154
|
+
(candidate.baseUrl !== undefined &&
|
|
155
|
+
candidate.baseUrl !== null &&
|
|
156
|
+
typeof candidate.baseUrl !== "string") ||
|
|
157
|
+
(candidate.orgSlug !== undefined &&
|
|
158
|
+
candidate.orgSlug !== null &&
|
|
159
|
+
typeof candidate.orgSlug !== "string") ||
|
|
160
|
+
(candidate.projectSlug !== undefined &&
|
|
161
|
+
candidate.projectSlug !== null &&
|
|
162
|
+
typeof candidate.projectSlug !== "string") ||
|
|
163
|
+
(candidate.stageSlug !== undefined &&
|
|
164
|
+
candidate.stageSlug !== null &&
|
|
165
|
+
typeof candidate.stageSlug !== "string") ||
|
|
166
|
+
!Number.isFinite(Date.parse(candidate.last))
|
|
167
|
+
) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
version: TYPEGEN_METADATA_VERSION,
|
|
173
|
+
last: candidate.last,
|
|
174
|
+
baseUrl: candidate.baseUrl ?? null,
|
|
175
|
+
orgSlug: candidate.orgSlug ?? null,
|
|
176
|
+
projectSlug: candidate.projectSlug ?? null,
|
|
177
|
+
stageSlug: candidate.stageSlug ?? null,
|
|
178
|
+
};
|
|
179
|
+
} catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function buildTypegenMetadataContents(
|
|
185
|
+
lastGeneratedAt: Date,
|
|
186
|
+
identity: TypegenMetadataIdentity,
|
|
187
|
+
): string {
|
|
188
|
+
return `${JSON.stringify(
|
|
189
|
+
{
|
|
190
|
+
version: TYPEGEN_METADATA_VERSION,
|
|
191
|
+
last: lastGeneratedAt.toISOString(),
|
|
192
|
+
baseUrl: identity.baseUrl,
|
|
193
|
+
orgSlug: identity.orgSlug,
|
|
194
|
+
projectSlug: identity.projectSlug,
|
|
195
|
+
stageSlug: identity.stageSlug,
|
|
196
|
+
},
|
|
197
|
+
null,
|
|
198
|
+
2,
|
|
199
|
+
)}\n`;
|
|
200
|
+
}
|
|
201
|
+
|
|
92
202
|
export async function resolveInstalledSdkGeneratedTypesPath(): Promise<string | null> {
|
|
93
203
|
const target = await resolveInstalledSdkTypegenTarget();
|
|
94
|
-
return target?.
|
|
204
|
+
return target?.serverGeneratedTypesPath ?? null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function renderGeneratedTypesForManifest(manifest: TypegenManifest): {
|
|
208
|
+
serverContents: string;
|
|
209
|
+
publicContents: string;
|
|
210
|
+
} {
|
|
211
|
+
return {
|
|
212
|
+
serverContents: buildGeneratedTypesContents(manifest, {
|
|
213
|
+
typeModulePath: "./dist/types.js",
|
|
214
|
+
declaredModulePath: "./dist/types.js",
|
|
215
|
+
interfaceName: "BarekeyGeneratedTypeMap",
|
|
216
|
+
include: () => true,
|
|
217
|
+
}),
|
|
218
|
+
publicContents: buildGeneratedTypesContents(manifest, {
|
|
219
|
+
typeModulePath: "./dist/public-types.js",
|
|
220
|
+
declaredModulePath: "./dist/public-types.js",
|
|
221
|
+
interfaceName: "BarekeyPublicGeneratedTypeMap",
|
|
222
|
+
include: (row) => row.visibility === "public",
|
|
223
|
+
}),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export async function hasFreshInstalledSdkTypegen(
|
|
228
|
+
intervalMs: number,
|
|
229
|
+
identity: TypegenMetadataIdentity,
|
|
230
|
+
): Promise<boolean> {
|
|
231
|
+
const target = await resolveInstalledSdkTypegenTarget();
|
|
232
|
+
if (target === null) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const metadata = parseTypegenMetadata(await readTextFile(target.typegenMetadataPath));
|
|
237
|
+
if (metadata === null) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (
|
|
242
|
+
metadata.baseUrl !== identity.baseUrl ||
|
|
243
|
+
metadata.orgSlug !== identity.orgSlug ||
|
|
244
|
+
metadata.projectSlug !== identity.projectSlug ||
|
|
245
|
+
metadata.stageSlug !== identity.stageSlug
|
|
246
|
+
) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return Date.now() - Date.parse(metadata.last) < intervalMs;
|
|
95
251
|
}
|
|
96
252
|
|
|
97
253
|
export async function writeInstalledSdkGeneratedTypes(
|
|
98
254
|
manifest: TypegenManifest,
|
|
255
|
+
identity: TypegenMetadataIdentity,
|
|
99
256
|
): Promise<BarekeyTypegenResult> {
|
|
100
257
|
const target = await resolveInstalledSdkTypegenTarget();
|
|
101
258
|
if (target === null) {
|
|
102
259
|
return {
|
|
103
260
|
written: false,
|
|
104
261
|
path: "",
|
|
262
|
+
serverPath: "",
|
|
263
|
+
publicPath: "",
|
|
105
264
|
manifestVersion: manifest.manifestVersion,
|
|
106
265
|
};
|
|
107
266
|
}
|
|
108
267
|
|
|
109
|
-
const
|
|
110
|
-
|
|
268
|
+
const [existingServerContents, existingPublicContents] = await Promise.all([
|
|
269
|
+
readTextFile(target.serverGeneratedTypesPath),
|
|
270
|
+
readTextFile(target.publicGeneratedTypesPath),
|
|
271
|
+
]);
|
|
272
|
+
if (
|
|
273
|
+
readManifestVersion(existingServerContents) === manifest.manifestVersion &&
|
|
274
|
+
readManifestVersion(existingPublicContents) === manifest.manifestVersion
|
|
275
|
+
) {
|
|
276
|
+
await writeTextFileAtomic(
|
|
277
|
+
target.typegenMetadataPath,
|
|
278
|
+
buildTypegenMetadataContents(new Date(), identity),
|
|
279
|
+
);
|
|
111
280
|
return {
|
|
112
281
|
written: false,
|
|
113
|
-
path: target.
|
|
282
|
+
path: target.serverGeneratedTypesPath,
|
|
283
|
+
serverPath: target.serverGeneratedTypesPath,
|
|
284
|
+
publicPath: target.publicGeneratedTypesPath,
|
|
114
285
|
manifestVersion: manifest.manifestVersion,
|
|
115
286
|
};
|
|
116
287
|
}
|
|
117
288
|
|
|
118
|
-
|
|
289
|
+
const rendered = renderGeneratedTypesForManifest(manifest);
|
|
290
|
+
|
|
291
|
+
await Promise.all([
|
|
292
|
+
writeTextFileAtomic(
|
|
293
|
+
target.serverGeneratedTypesPath,
|
|
294
|
+
rendered.serverContents,
|
|
295
|
+
),
|
|
296
|
+
writeTextFileAtomic(
|
|
297
|
+
target.publicGeneratedTypesPath,
|
|
298
|
+
rendered.publicContents,
|
|
299
|
+
),
|
|
300
|
+
]);
|
|
301
|
+
await writeTextFileAtomic(
|
|
302
|
+
target.typegenMetadataPath,
|
|
303
|
+
buildTypegenMetadataContents(new Date(), identity),
|
|
304
|
+
);
|
|
119
305
|
return {
|
|
120
306
|
written: true,
|
|
121
|
-
path: target.
|
|
307
|
+
path: target.serverGeneratedTypesPath,
|
|
308
|
+
serverPath: target.serverGeneratedTypesPath,
|
|
309
|
+
publicPath: target.publicGeneratedTypesPath,
|
|
122
310
|
manifestVersion: manifest.manifestVersion,
|
|
123
311
|
};
|
|
124
312
|
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { VariableNotFoundError } from "./errors.js";
|
|
2
|
+
import { BarekeyEnvHandle } from "./handle.js";
|
|
3
|
+
import {
|
|
4
|
+
evaluateDefinition,
|
|
5
|
+
parseDeclaredValue,
|
|
6
|
+
validateDynamicOptions,
|
|
7
|
+
} from "./internal/evaluate.js";
|
|
8
|
+
import { postJson } from "./internal/http.js";
|
|
9
|
+
import { MemoryCache } from "./internal/cache.js";
|
|
10
|
+
import { validateRequirements } from "./internal/requirements.js";
|
|
11
|
+
import {
|
|
12
|
+
resolvePublicRuntimeContext,
|
|
13
|
+
type BarekeyPublicRuntimeContext,
|
|
14
|
+
} from "./internal/public-runtime.js";
|
|
15
|
+
import { resolveTtlMilliseconds } from "./internal/ttl.js";
|
|
16
|
+
import type {
|
|
17
|
+
BarekeyPublicGeneratedTypeMap,
|
|
18
|
+
BarekeyPublicKnownKey,
|
|
19
|
+
PublicBarekeyClientOptions,
|
|
20
|
+
} from "./public-types.js";
|
|
21
|
+
import type {
|
|
22
|
+
BarekeyEvaluatedValue,
|
|
23
|
+
BarekeyGetOptions,
|
|
24
|
+
BarekeyJsonConfig,
|
|
25
|
+
BarekeyVariableDefinition,
|
|
26
|
+
} from "./types.js";
|
|
27
|
+
|
|
28
|
+
type DefinitionsResponse = {
|
|
29
|
+
definitions: Array<BarekeyVariableDefinition>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function createDefaultFetch(): typeof globalThis.fetch {
|
|
33
|
+
if (typeof globalThis.fetch === "function") {
|
|
34
|
+
return globalThis.fetch.bind(globalThis);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (async () => {
|
|
38
|
+
throw new Error("fetch is not available in this runtime.");
|
|
39
|
+
}) as typeof globalThis.fetch;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class PublicBarekeyClient {
|
|
43
|
+
private readonly options: PublicBarekeyClientOptions;
|
|
44
|
+
private readonly fetchFn: typeof globalThis.fetch;
|
|
45
|
+
private readonly definitionCache = new MemoryCache<BarekeyVariableDefinition>();
|
|
46
|
+
private readonly evaluationCache = new MemoryCache<BarekeyEvaluatedValue>();
|
|
47
|
+
private runtimeContextPromise: Promise<BarekeyPublicRuntimeContext> | null = null;
|
|
48
|
+
private requirementsPromise: Promise<void> | null = null;
|
|
49
|
+
|
|
50
|
+
constructor();
|
|
51
|
+
constructor(options: {
|
|
52
|
+
organization: string;
|
|
53
|
+
project: string;
|
|
54
|
+
environment: string;
|
|
55
|
+
requirements?: PublicBarekeyClientOptions["requirements"];
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
});
|
|
58
|
+
constructor(options: {
|
|
59
|
+
json: BarekeyJsonConfig;
|
|
60
|
+
requirements?: PublicBarekeyClientOptions["requirements"];
|
|
61
|
+
baseUrl?: string;
|
|
62
|
+
});
|
|
63
|
+
constructor(options: PublicBarekeyClientOptions = {}) {
|
|
64
|
+
this.options = options;
|
|
65
|
+
this.fetchFn = createDefaultFetch();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get<TKey extends BarekeyPublicKnownKey>(
|
|
69
|
+
name: TKey,
|
|
70
|
+
options?: BarekeyGetOptions,
|
|
71
|
+
): BarekeyEnvHandle<BarekeyPublicGeneratedTypeMap[TKey]>;
|
|
72
|
+
get(name: string, options?: BarekeyGetOptions): BarekeyEnvHandle<unknown>;
|
|
73
|
+
get(name: string, options?: BarekeyGetOptions): BarekeyEnvHandle<unknown> {
|
|
74
|
+
return new BarekeyEnvHandle(
|
|
75
|
+
async () => await this.resolveEvaluatedValue(name, options),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private async getRuntimeContext(): Promise<BarekeyPublicRuntimeContext> {
|
|
80
|
+
if (this.runtimeContextPromise === null) {
|
|
81
|
+
const runtimeContextPromise = resolvePublicRuntimeContext(this.options);
|
|
82
|
+
runtimeContextPromise.catch(() => {
|
|
83
|
+
if (this.runtimeContextPromise === runtimeContextPromise) {
|
|
84
|
+
this.runtimeContextPromise = null;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
this.runtimeContextPromise = runtimeContextPromise;
|
|
88
|
+
}
|
|
89
|
+
return await this.runtimeContextPromise;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private buildDefinitionCacheKey(context: BarekeyPublicRuntimeContext, name: string): string {
|
|
93
|
+
return [context.organization, context.project, context.environment, name].join("|");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private buildEvaluationCacheKey(
|
|
97
|
+
context: BarekeyPublicRuntimeContext,
|
|
98
|
+
name: string,
|
|
99
|
+
options?: BarekeyGetOptions,
|
|
100
|
+
): string {
|
|
101
|
+
return [
|
|
102
|
+
context.organization,
|
|
103
|
+
context.project,
|
|
104
|
+
context.environment,
|
|
105
|
+
name,
|
|
106
|
+
options?.seed ?? "",
|
|
107
|
+
options?.key ?? "",
|
|
108
|
+
].join("|");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private async fetchDefinitions(names?: Array<string>): Promise<Array<BarekeyVariableDefinition>> {
|
|
112
|
+
const context = await this.getRuntimeContext();
|
|
113
|
+
const response = await postJson<DefinitionsResponse>({
|
|
114
|
+
fetchFn: this.fetchFn,
|
|
115
|
+
baseUrl: context.baseUrl,
|
|
116
|
+
path: "/v1/public/env/definitions",
|
|
117
|
+
payload: {
|
|
118
|
+
orgSlug: context.organization,
|
|
119
|
+
projectSlug: context.project,
|
|
120
|
+
stageSlug: context.environment,
|
|
121
|
+
...(names === undefined ? {} : { names }),
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
for (const definition of response.definitions) {
|
|
126
|
+
this.definitionCache.set(this.buildDefinitionCacheKey(context, definition.name), definition);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return response.definitions;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private async ensureRequirementsValidated(): Promise<void> {
|
|
133
|
+
const context = await this.getRuntimeContext();
|
|
134
|
+
const requirements = context.requirements;
|
|
135
|
+
if (requirements === undefined) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.requirementsPromise === null) {
|
|
140
|
+
const requirementsPromise = (async () => {
|
|
141
|
+
const definitions = await this.fetchDefinitions();
|
|
142
|
+
const values: Record<string, unknown> = {};
|
|
143
|
+
for (const definition of definitions) {
|
|
144
|
+
const evaluated = await evaluateDefinition(definition);
|
|
145
|
+
values[definition.name] = parseDeclaredValue(evaluated.value, evaluated.declaredType);
|
|
146
|
+
}
|
|
147
|
+
await validateRequirements(requirements, values);
|
|
148
|
+
})();
|
|
149
|
+
requirementsPromise.catch(() => {
|
|
150
|
+
if (this.requirementsPromise === requirementsPromise) {
|
|
151
|
+
this.requirementsPromise = null;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
this.requirementsPromise = requirementsPromise;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await this.requirementsPromise;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private async getStaticDefinition(name: string): Promise<BarekeyVariableDefinition> {
|
|
161
|
+
await this.ensureRequirementsValidated();
|
|
162
|
+
const context = await this.getRuntimeContext();
|
|
163
|
+
const cacheKey = this.buildDefinitionCacheKey(context, name);
|
|
164
|
+
const cached = this.definitionCache.get(cacheKey);
|
|
165
|
+
if (cached !== null) {
|
|
166
|
+
return cached;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const definitions = await this.fetchDefinitions([name]);
|
|
170
|
+
const resolved = definitions[0];
|
|
171
|
+
if (resolved === undefined) {
|
|
172
|
+
throw new VariableNotFoundError();
|
|
173
|
+
}
|
|
174
|
+
return resolved;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private async resolveStaticValue(
|
|
178
|
+
name: string,
|
|
179
|
+
options?: BarekeyGetOptions,
|
|
180
|
+
): Promise<BarekeyEvaluatedValue> {
|
|
181
|
+
const definition = await this.getStaticDefinition(name);
|
|
182
|
+
return await evaluateDefinition(definition, options);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private async resolveDynamicValue(
|
|
186
|
+
name: string,
|
|
187
|
+
options?: BarekeyGetOptions,
|
|
188
|
+
): Promise<BarekeyEvaluatedValue> {
|
|
189
|
+
await this.ensureRequirementsValidated();
|
|
190
|
+
const context = await this.getRuntimeContext();
|
|
191
|
+
const cacheKey = this.buildEvaluationCacheKey(context, name, options);
|
|
192
|
+
const dynamic = options?.dynamic;
|
|
193
|
+
const dynamicTtlMs =
|
|
194
|
+
dynamic !== undefined && dynamic !== true
|
|
195
|
+
? resolveTtlMilliseconds(dynamic.ttl, "dynamic.ttl")
|
|
196
|
+
: null;
|
|
197
|
+
|
|
198
|
+
if (dynamic !== true) {
|
|
199
|
+
const cached = this.evaluationCache.getRecord(cacheKey);
|
|
200
|
+
if (cached !== null && dynamicTtlMs !== null && Date.now() - cached.storedAtMs <= dynamicTtlMs) {
|
|
201
|
+
return cached.value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const freshDefinitions = await this.fetchDefinitions([name]);
|
|
206
|
+
const freshDefinition = freshDefinitions[0];
|
|
207
|
+
if (freshDefinition === undefined) {
|
|
208
|
+
throw new VariableNotFoundError();
|
|
209
|
+
}
|
|
210
|
+
const resolved = await evaluateDefinition(freshDefinition, options);
|
|
211
|
+
|
|
212
|
+
if (dynamicTtlMs !== null) {
|
|
213
|
+
this.evaluationCache.set(cacheKey, resolved);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return resolved;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private async resolveEvaluatedValue(
|
|
220
|
+
name: string,
|
|
221
|
+
options?: BarekeyGetOptions,
|
|
222
|
+
): Promise<BarekeyEvaluatedValue> {
|
|
223
|
+
validateDynamicOptions(options);
|
|
224
|
+
if (options?.dynamic === undefined) {
|
|
225
|
+
return await this.resolveStaticValue(name, options);
|
|
226
|
+
}
|
|
227
|
+
return await this.resolveDynamicValue(name, options);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
AB,
|
|
3
|
+
BarekeyCoerceTarget,
|
|
4
|
+
BarekeyDeclaredType,
|
|
5
|
+
BarekeyDecision,
|
|
6
|
+
BarekeyErrorCode,
|
|
7
|
+
BarekeyEvaluatedValue,
|
|
8
|
+
BarekeyGetOptions,
|
|
9
|
+
BarekeyJsonConfig,
|
|
10
|
+
BarekeyResolvedKind,
|
|
11
|
+
BarekeyRolloutFunction,
|
|
12
|
+
BarekeyRolloutMatchedRule,
|
|
13
|
+
BarekeyRolloutMilestone,
|
|
14
|
+
BarekeyStandardSchemaPathSegment,
|
|
15
|
+
BarekeyStandardSchemaResult,
|
|
16
|
+
BarekeyStandardSchemaV1,
|
|
17
|
+
BarekeyTemporalInstant,
|
|
18
|
+
BarekeyTemporalInstantLike,
|
|
19
|
+
BarekeyTtlInput,
|
|
20
|
+
BarekeyTypegenResult,
|
|
21
|
+
BarekeyVariableDefinition,
|
|
22
|
+
EaseInOut,
|
|
23
|
+
Env,
|
|
24
|
+
Linear,
|
|
25
|
+
Secret,
|
|
26
|
+
Step,
|
|
27
|
+
} from "./types.js";
|
|
28
|
+
import type { BarekeyJsonConfig, BarekeyStandardSchemaV1 } from "./types.js";
|
|
29
|
+
|
|
30
|
+
export interface BarekeyPublicGeneratedTypeMap {}
|
|
31
|
+
|
|
32
|
+
export type BarekeyPublicKnownKey = Extract<keyof BarekeyPublicGeneratedTypeMap, string>;
|
|
33
|
+
|
|
34
|
+
type BarekeyPublicBaseClientOptions = {
|
|
35
|
+
requirements?: BarekeyStandardSchemaV1;
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type PublicBarekeyClientOptions =
|
|
40
|
+
| (BarekeyPublicBaseClientOptions & {
|
|
41
|
+
organization: string;
|
|
42
|
+
project: string;
|
|
43
|
+
environment: string;
|
|
44
|
+
json?: never;
|
|
45
|
+
})
|
|
46
|
+
| (BarekeyPublicBaseClientOptions & {
|
|
47
|
+
json: BarekeyJsonConfig;
|
|
48
|
+
organization?: never;
|
|
49
|
+
project?: never;
|
|
50
|
+
environment?: never;
|
|
51
|
+
})
|
|
52
|
+
| (BarekeyPublicBaseClientOptions & {
|
|
53
|
+
organization?: never;
|
|
54
|
+
project?: never;
|
|
55
|
+
environment?: never;
|
|
56
|
+
json?: never;
|
|
57
|
+
});
|