@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.
Files changed (48) hide show
  1. package/README.md +9 -3
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +15 -3
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/internal/evaluate.d.ts.map +1 -1
  8. package/dist/internal/evaluate.js +57 -7
  9. package/dist/internal/node-runtime.d.ts +3 -1
  10. package/dist/internal/node-runtime.d.ts.map +1 -1
  11. package/dist/internal/node-runtime.js +8 -4
  12. package/dist/internal/public-runtime.d.ts +14 -0
  13. package/dist/internal/public-runtime.d.ts.map +1 -0
  14. package/dist/internal/public-runtime.js +78 -0
  15. package/dist/internal/typegen.d.ts +16 -3
  16. package/dist/internal/typegen.d.ts.map +1 -1
  17. package/dist/internal/typegen.js +123 -12
  18. package/dist/public-client.d.ts +36 -0
  19. package/dist/public-client.d.ts.map +1 -0
  20. package/dist/public-client.js +150 -0
  21. package/dist/public-types.d.ts +26 -0
  22. package/dist/public-types.d.ts.map +1 -0
  23. package/dist/public-types.js +1 -0
  24. package/dist/public.d.ts +6 -0
  25. package/dist/public.d.ts.map +1 -0
  26. package/dist/public.js +3 -0
  27. package/dist/server.d.ts +5 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +3 -0
  30. package/dist/types.d.ts +14 -2
  31. package/dist/types.d.ts.map +1 -1
  32. package/generated.public.d.ts +8 -0
  33. package/{generated.d.ts → generated.server.d.ts} +8 -2
  34. package/index.d.ts +0 -1
  35. package/package.json +18 -3
  36. package/public.d.ts +2 -0
  37. package/server.d.ts +2 -0
  38. package/src/client.ts +17 -2
  39. package/src/index.ts +7 -0
  40. package/src/internal/evaluate.ts +83 -7
  41. package/src/internal/node-runtime.ts +11 -5
  42. package/src/internal/public-runtime.ts +123 -0
  43. package/src/internal/typegen.ts +203 -15
  44. package/src/public-client.ts +229 -0
  45. package/src/public-types.ts +57 -0
  46. package/src/public.ts +69 -0
  47. package/src/server.ts +60 -0
  48. 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
+ }
@@ -3,10 +3,15 @@ import {
3
3
  resolveInstalledSdkTypegenTarget,
4
4
  writeTextFileAtomic,
5
5
  } from "./node-runtime.js";
6
- import type { BarekeyRolloutMilestone, BarekeyTypegenResult } from "../types.js";
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: "linear" | null;
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}, Linear<${renderLinearMilestones(
56
- row.rolloutMilestones ?? [],
57
- )}>>`;
88
+ return `Env<AB, ${row.typeScriptType}, ${renderRolloutMetadataType(row)}>`;
58
89
  }
59
90
 
60
- function buildGeneratedTypesContents(manifest: TypegenManifest): string {
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 "./dist/types.js";
111
+ import type { AB, EaseInOut, Env, Linear, Secret, Step } from "${input.typeModulePath}";
72
112
 
73
- declare module "./dist/types.js" {
74
- interface BarekeyGeneratedTypeMap {
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?.generatedTypesPath ?? null;
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 existingContents = await readTextFile(target.generatedTypesPath);
110
- if (readManifestVersion(existingContents) === manifest.manifestVersion) {
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.generatedTypesPath,
282
+ path: target.serverGeneratedTypesPath,
283
+ serverPath: target.serverGeneratedTypesPath,
284
+ publicPath: target.publicGeneratedTypesPath,
114
285
  manifestVersion: manifest.manifestVersion,
115
286
  };
116
287
  }
117
288
 
118
- await writeTextFileAtomic(target.generatedTypesPath, buildGeneratedTypesContents(manifest));
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.generatedTypesPath,
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
+ });