@enterprisestandard/react 0.0.5-beta.20260115.1 → 0.0.5-beta.20260115.2

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.
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Creates a StandardSchemaV1 for validating JWT Assertion Claims.
3
+ * @param vendor - The name of the vendor creating this schema
4
+ * @returns A StandardSchemaV1 instance for JWT Assertion Claims validation
5
+ */
6
+ export function jwtAssertionClaimsSchema(vendor) {
7
+ return {
8
+ '~standard': {
9
+ version: 1,
10
+ vendor,
11
+ validate: (value) => {
12
+ if (typeof value !== 'object' || value === null) {
13
+ return {
14
+ issues: [
15
+ {
16
+ message: 'Expected an object',
17
+ },
18
+ ],
19
+ };
20
+ }
21
+ const claims = value;
22
+ const issues = [];
23
+ const result = { ...claims };
24
+ // Validate required string fields
25
+ const requiredStringFields = ['iss', 'sub'];
26
+ for (const field of requiredStringFields) {
27
+ if (field in claims) {
28
+ if (typeof claims[field] !== 'string') {
29
+ issues.push({
30
+ message: `${field} must be a string`,
31
+ path: [field],
32
+ });
33
+ }
34
+ }
35
+ else {
36
+ issues.push({
37
+ message: `${field} is required`,
38
+ path: [field],
39
+ });
40
+ }
41
+ }
42
+ // Validate optional aud field (can be string or array of strings)
43
+ if ('aud' in claims && claims.aud !== undefined) {
44
+ const aud = claims.aud;
45
+ if (typeof aud !== 'string' && !Array.isArray(aud)) {
46
+ issues.push({
47
+ message: 'aud must be a string or array of strings',
48
+ path: ['aud'],
49
+ });
50
+ }
51
+ else if (Array.isArray(aud) && !aud.every((a) => typeof a === 'string')) {
52
+ issues.push({
53
+ message: 'aud array must contain only strings',
54
+ path: ['aud'],
55
+ });
56
+ }
57
+ }
58
+ // Validate optional string fields
59
+ const optionalStringFields = ['jti', 'scope'];
60
+ for (const field of optionalStringFields) {
61
+ if (field in claims && claims[field] !== undefined) {
62
+ if (typeof claims[field] !== 'string') {
63
+ issues.push({
64
+ message: `${field} must be a string`,
65
+ path: [field],
66
+ });
67
+ }
68
+ }
69
+ }
70
+ // Validate required number fields
71
+ const requiredNumberFields = ['exp', 'iat'];
72
+ for (const field of requiredNumberFields) {
73
+ if (field in claims) {
74
+ if (typeof claims[field] !== 'number') {
75
+ issues.push({
76
+ message: `${field} must be a number`,
77
+ path: [field],
78
+ });
79
+ }
80
+ }
81
+ else {
82
+ issues.push({
83
+ message: `${field} is required`,
84
+ path: [field],
85
+ });
86
+ }
87
+ }
88
+ if (issues.length > 0) {
89
+ return { issues };
90
+ }
91
+ return { value: result };
92
+ },
93
+ },
94
+ };
95
+ }
96
+ /**
97
+ * Creates a StandardSchemaV1 for validating Workload Token Responses.
98
+ * @param vendor - The name of the vendor creating this schema
99
+ * @returns A StandardSchemaV1 instance for Workload Token Response validation
100
+ */
101
+ export function workloadTokenResponseSchema(vendor) {
102
+ return {
103
+ '~standard': {
104
+ version: 1,
105
+ vendor,
106
+ validate: (value) => {
107
+ if (typeof value !== 'object' || value === null) {
108
+ return {
109
+ issues: [
110
+ {
111
+ message: 'Expected an object',
112
+ },
113
+ ],
114
+ };
115
+ }
116
+ const response = value;
117
+ const issues = [];
118
+ const result = {};
119
+ // Check required 'access_token' parameter
120
+ if ('access_token' in response) {
121
+ if (typeof response.access_token === 'string') {
122
+ result.access_token = response.access_token;
123
+ }
124
+ else {
125
+ issues.push({
126
+ message: 'access_token must be a string',
127
+ path: ['access_token'],
128
+ });
129
+ }
130
+ }
131
+ else {
132
+ issues.push({
133
+ message: 'access_token is required',
134
+ path: ['access_token'],
135
+ });
136
+ }
137
+ // Check required 'token_type' parameter
138
+ if ('token_type' in response) {
139
+ if (typeof response.token_type === 'string') {
140
+ result.token_type = response.token_type;
141
+ }
142
+ else {
143
+ issues.push({
144
+ message: 'token_type must be a string',
145
+ path: ['token_type'],
146
+ });
147
+ }
148
+ }
149
+ else {
150
+ issues.push({
151
+ message: 'token_type is required',
152
+ path: ['token_type'],
153
+ });
154
+ }
155
+ // Optional string fields
156
+ if ('scope' in response) {
157
+ if (typeof response.scope === 'string' || response.scope === undefined) {
158
+ result.scope = response.scope;
159
+ }
160
+ else {
161
+ issues.push({
162
+ message: 'scope must be a string',
163
+ path: ['scope'],
164
+ });
165
+ }
166
+ }
167
+ if ('refresh_token' in response) {
168
+ if (typeof response.refresh_token === 'string' || response.refresh_token === undefined) {
169
+ result.refresh_token = response.refresh_token;
170
+ }
171
+ else {
172
+ issues.push({
173
+ message: 'refresh_token must be a string',
174
+ path: ['refresh_token'],
175
+ });
176
+ }
177
+ }
178
+ if ('expires' in response) {
179
+ if (typeof response.expires === 'string' || response.expires === undefined) {
180
+ result.expires = response.expires;
181
+ }
182
+ else {
183
+ issues.push({
184
+ message: 'expires must be a string',
185
+ path: ['expires'],
186
+ });
187
+ }
188
+ }
189
+ // Optional number field
190
+ if ('expires_in' in response) {
191
+ if (typeof response.expires_in === 'number' || response.expires_in === undefined) {
192
+ result.expires_in = response.expires_in;
193
+ }
194
+ else {
195
+ issues.push({
196
+ message: 'expires_in must be a number',
197
+ path: ['expires_in'],
198
+ });
199
+ }
200
+ }
201
+ if (issues.length > 0) {
202
+ return { issues };
203
+ }
204
+ return { value: result };
205
+ },
206
+ },
207
+ };
208
+ }
@@ -0,0 +1,8 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useUser } from '..';
3
+ export function SignInLoading({ complete = false, children }) {
4
+ const { isLoading } = useUser();
5
+ if (isLoading && !complete)
6
+ return _jsx(_Fragment, { children: children });
7
+ return null;
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useUser } from '..';
3
+ export function SignedIn({ children }) {
4
+ const { user } = useUser();
5
+ if (user)
6
+ return _jsx(_Fragment, { children: children });
7
+ return null;
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useUser } from '..';
3
+ export function SignedOut({ children }) {
4
+ const { user, isLoading } = useUser();
5
+ if (user || isLoading)
6
+ return null;
7
+ return _jsx(_Fragment, { children: children });
8
+ }
@@ -0,0 +1,275 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useState } from 'react';
3
+ const CTX = createContext(undefined);
4
+ const generateStorageKey = (tenantId) => {
5
+ return `es-sso-user-${tenantId
6
+ .replace(/[^a-zA-Z0-9]/g, '-')
7
+ .replace(/-+/g, '-')
8
+ .replace(/^-|-$/g, '')}`;
9
+ };
10
+ export function SSOProvider({ tenantId, storage = 'memory', storageKey, userUrl, tokenUrl, refreshUrl, disableListener = false, children, }) {
11
+ const [user, setUserState] = useState(null);
12
+ const [isLoading, setIsLoading] = useState(!!userUrl);
13
+ const actualStorageKey = storageKey || (tenantId ? generateStorageKey(tenantId) : 'es-sso-user');
14
+ const isValidUser = useCallback((user) => {
15
+ if (!user || !tenantId)
16
+ return true;
17
+ return user.sso?.tenant?.id === tenantId;
18
+ }, [tenantId]);
19
+ const loadUserFromStorage = useCallback(() => {
20
+ if (storage === 'memory' || typeof window === 'undefined')
21
+ return null;
22
+ try {
23
+ const storageObject = storage === 'local' ? localStorage : sessionStorage;
24
+ const userData = storageObject.getItem(actualStorageKey);
25
+ if (!userData)
26
+ return null;
27
+ const parsedUser = JSON.parse(userData);
28
+ if (parsedUser.sso?.expires) {
29
+ parsedUser.sso.expires = new Date(parsedUser.sso.expires);
30
+ }
31
+ return isValidUser(parsedUser) ? parsedUser : null;
32
+ }
33
+ catch (error) {
34
+ console.error('Error loading user from storage:', error);
35
+ return null;
36
+ }
37
+ }, [storage, actualStorageKey, isValidUser]);
38
+ const saveUserToStorage = useCallback((user) => {
39
+ if (storage === 'memory' || typeof window === 'undefined')
40
+ return;
41
+ try {
42
+ const storageObject = storage === 'local' ? localStorage : sessionStorage;
43
+ if (user === null) {
44
+ storageObject.removeItem(actualStorageKey);
45
+ }
46
+ else {
47
+ storageObject.setItem(actualStorageKey, JSON.stringify(user));
48
+ }
49
+ }
50
+ catch (error) {
51
+ console.error('Error saving user to storage:', error);
52
+ }
53
+ }, [storage, actualStorageKey]);
54
+ const setUser = useCallback((newUser) => {
55
+ if (newUser && !isValidUser(newUser))
56
+ return;
57
+ setUserState(newUser);
58
+ saveUserToStorage(newUser);
59
+ }, [isValidUser, saveUserToStorage]);
60
+ const fetchUserFromUrl = useCallback(async () => {
61
+ if (!userUrl)
62
+ return;
63
+ setIsLoading(true);
64
+ try {
65
+ const response = await fetch(userUrl);
66
+ if (response.status === 401) {
67
+ setUserState(null);
68
+ saveUserToStorage(null);
69
+ setIsLoading(false);
70
+ return;
71
+ }
72
+ if (!response.ok) {
73
+ throw new Error(`Failed to fetch user: ${response.status} ${response.statusText}`);
74
+ }
75
+ const userData = (await response.json());
76
+ if (userData.sso?.expires && typeof userData.sso.expires === 'string') {
77
+ userData.sso.expires = new Date(userData.sso.expires);
78
+ }
79
+ if (isValidUser(userData)) {
80
+ setUserState(userData);
81
+ saveUserToStorage(userData);
82
+ }
83
+ }
84
+ catch (error) {
85
+ console.error('Error fetching user from URL:', error);
86
+ }
87
+ finally {
88
+ setIsLoading(false);
89
+ }
90
+ }, [userUrl, isValidUser, saveUserToStorage]);
91
+ useEffect(() => {
92
+ const storedUser = loadUserFromStorage();
93
+ if (storedUser) {
94
+ setUserState(storedUser);
95
+ }
96
+ if (userUrl) {
97
+ fetchUserFromUrl();
98
+ }
99
+ else {
100
+ setIsLoading(false);
101
+ }
102
+ }, [loadUserFromStorage, userUrl, fetchUserFromUrl]);
103
+ useEffect(() => {
104
+ if (disableListener || storage === 'memory')
105
+ return;
106
+ const handleStorageChange = (event) => {
107
+ if (event.key !== actualStorageKey)
108
+ return;
109
+ if (event.newValue === null) {
110
+ setUserState(null);
111
+ }
112
+ else {
113
+ try {
114
+ const parsedUser = JSON.parse(event.newValue);
115
+ if (parsedUser.sso?.expires) {
116
+ parsedUser.sso.expires = new Date(parsedUser.sso.expires);
117
+ }
118
+ if (isValidUser(parsedUser)) {
119
+ setUserState(parsedUser);
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.error('Error parsing user from storage event:', error);
124
+ }
125
+ }
126
+ };
127
+ const handleLogout = () => {
128
+ setUserState(null);
129
+ };
130
+ window.addEventListener('storage', handleStorageChange);
131
+ window.addEventListener('es-sso-logout', handleLogout);
132
+ return () => {
133
+ window.removeEventListener('storage', handleStorageChange);
134
+ window.removeEventListener('es-sso-logout', handleLogout);
135
+ };
136
+ }, [disableListener, storage, actualStorageKey, isValidUser]);
137
+ const contextValue = {
138
+ user,
139
+ setUser,
140
+ isLoading,
141
+ tokenUrl,
142
+ refreshUrl,
143
+ };
144
+ return _jsx(CTX.Provider, { value: contextValue, children: children });
145
+ }
146
+ export function useUser() {
147
+ const context = useContext(CTX);
148
+ if (context === undefined) {
149
+ throw new Error('useUser must be used within a SSOProvider');
150
+ }
151
+ return context;
152
+ }
153
+ export function useToken() {
154
+ const context = useContext(CTX);
155
+ if (context === undefined) {
156
+ throw new Error('useToken must be used within a SSOProvider');
157
+ }
158
+ const { tokenUrl, refreshUrl } = context;
159
+ if (!tokenUrl || !refreshUrl) {
160
+ throw new Error('useToken requires that a "tokenUrl" and "refreshUrl" be set in the SSOProvider');
161
+ }
162
+ const [token, setToken] = useState(null);
163
+ const [expires, setExpires] = useState(null);
164
+ const [isLoading, setIsLoading] = useState(!!tokenUrl);
165
+ const [error, setError] = useState(null);
166
+ const fetchJwt = useCallback(async (url) => {
167
+ setIsLoading(true);
168
+ setError(null);
169
+ try {
170
+ const response = await fetch(url);
171
+ if (response.status === 401) {
172
+ context.setUser(null);
173
+ setToken(null);
174
+ setExpires(null);
175
+ setIsLoading(false);
176
+ return;
177
+ }
178
+ if (!response.ok) {
179
+ throw new Error(`Failed to fetch JWT: ${response.status} ${response.statusText}`);
180
+ }
181
+ const data = (await response.json());
182
+ setToken(data.token);
183
+ setExpires(new Date(data.expires));
184
+ }
185
+ catch (err) {
186
+ const error = err instanceof Error ? err : new Error(String(err));
187
+ setError(error);
188
+ setToken(null);
189
+ setExpires(null);
190
+ console.error('Error fetching JWT:', error);
191
+ }
192
+ finally {
193
+ setIsLoading(false);
194
+ }
195
+ }, [context]);
196
+ const refresh = useCallback(async () => {
197
+ const url = refreshUrl || tokenUrl;
198
+ if (!url) {
199
+ console.warn('No tokenUrl or refreshUrl provided');
200
+ return;
201
+ }
202
+ await fetchJwt(url);
203
+ }, [refreshUrl, tokenUrl, fetchJwt]);
204
+ useEffect(() => {
205
+ if (!tokenUrl) {
206
+ setIsLoading(false);
207
+ return;
208
+ }
209
+ fetchJwt(tokenUrl);
210
+ }, [tokenUrl, fetchJwt]);
211
+ useEffect(() => {
212
+ if (!expires || !refreshUrl)
213
+ return;
214
+ const checkExpiration = () => {
215
+ const now = new Date();
216
+ const timeUntilExpiry = expires.getTime() - now.getTime();
217
+ // Refresh 1 minute before expiration
218
+ if (timeUntilExpiry <= 60000 && timeUntilExpiry > 0) {
219
+ refresh();
220
+ }
221
+ };
222
+ // Check immediately
223
+ checkExpiration();
224
+ // Check every 30 seconds
225
+ const interval = setInterval(checkExpiration, 30000);
226
+ return () => clearInterval(interval);
227
+ }, [expires, refreshUrl, refresh]);
228
+ return {
229
+ token,
230
+ isLoading,
231
+ error,
232
+ refresh,
233
+ };
234
+ }
235
+ export async function logout(logoutUrl) {
236
+ try {
237
+ // Make AJAX logout call
238
+ const response = await fetch(logoutUrl, {
239
+ headers: { Accept: 'application/json' },
240
+ });
241
+ if (!response.ok) {
242
+ return { success: false, error: `HTTP ${response.status}` };
243
+ }
244
+ const data = await response.json();
245
+ if (!data.success) {
246
+ return { success: false, error: data.message || 'Logout failed' };
247
+ }
248
+ // Clear managed storage keys (all es-sso-user-* keys)
249
+ if (typeof window !== 'undefined') {
250
+ // Clear localStorage
251
+ for (let i = localStorage.length - 1; i >= 0; i--) {
252
+ const key = localStorage.key(i);
253
+ if (key?.startsWith('es-sso-user')) {
254
+ localStorage.removeItem(key);
255
+ }
256
+ }
257
+ // Clear sessionStorage
258
+ for (let i = sessionStorage.length - 1; i >= 0; i--) {
259
+ const key = sessionStorage.key(i);
260
+ if (key?.startsWith('es-sso-user')) {
261
+ sessionStorage.removeItem(key);
262
+ }
263
+ }
264
+ // Dispatch custom event for same-tab state updates
265
+ window.dispatchEvent(new CustomEvent('es-sso-logout'));
266
+ }
267
+ return { success: true };
268
+ }
269
+ catch (error) {
270
+ return {
271
+ success: false,
272
+ error: error instanceof Error ? error.message : 'Network error',
273
+ };
274
+ }
275
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * User storage for persisting user profiles from SSO authentication.
3
+ *
4
+ * User stores are optional - the package works with JWT cookies alone.
5
+ * User stores are useful when you want to:
6
+ * - Cache user profiles for fast lookup
7
+ * - Store users close to your application (in-memory, Redis, etc.)
8
+ * - Avoid custom IAM/SCIM integration for simple use cases
9
+ *
10
+ * ## When to Use UserStore vs IAM
11
+ *
12
+ * **Use UserStore when:**
13
+ * - You just need fast user lookups without external systems
14
+ * - Users are managed by an external IdP and you just cache them locally
15
+ * - You want simple in-memory or Redis storage
16
+ *
17
+ * **Use IAM (SCIM) when:**
18
+ * - You need to provision users to an external identity provider
19
+ * - You need custom user attributes beyond what SSO provides
20
+ * - You need to sync users with enterprise directories
21
+ *
22
+ * ## Example Usage
23
+ *
24
+ * ```typescript
25
+ * import { sso, InMemoryUserStore } from '@enterprisestandard/react/server';
26
+ *
27
+ * const userStore = new InMemoryUserStore();
28
+ *
29
+ * const auth = sso({
30
+ * // ... other config
31
+ * user_store: userStore,
32
+ * });
33
+ *
34
+ * // Later, look up users
35
+ * const user = await userStore.get('user-sub-id');
36
+ * const userByEmail = await userStore.getByEmail('user@example.com');
37
+ * ```
38
+ */
39
+ /**
40
+ * In-memory user store implementation using Maps.
41
+ *
42
+ * Suitable for:
43
+ * - Development and testing
44
+ * - Single-server deployments
45
+ * - Applications without high availability requirements
46
+ *
47
+ * NOT suitable for:
48
+ * - Multi-server deployments (users not shared)
49
+ * - High availability scenarios (users lost on restart)
50
+ * - Production applications with distributed architecture
51
+ *
52
+ * For production, implement UserStore with Redis or a database.
53
+ *
54
+ * @template TExtended - Type-safe custom data that consumers can add to users
55
+ */
56
+ export class InMemoryUserStore {
57
+ constructor() {
58
+ /** Primary storage: sub -> user */
59
+ this.users = new Map();
60
+ /** Secondary index: email -> sub */
61
+ this.emailIndex = new Map();
62
+ /** Secondary index: userName -> sub */
63
+ this.userNameIndex = new Map();
64
+ }
65
+ async get(sub) {
66
+ return this.users.get(sub) ?? null;
67
+ }
68
+ async getByEmail(email) {
69
+ const sub = this.emailIndex.get(email.toLowerCase());
70
+ if (!sub)
71
+ return null;
72
+ return this.users.get(sub) ?? null;
73
+ }
74
+ async getByUserName(userName) {
75
+ const sub = this.userNameIndex.get(userName.toLowerCase());
76
+ if (!sub)
77
+ return null;
78
+ return this.users.get(sub) ?? null;
79
+ }
80
+ async upsert(user) {
81
+ const existing = this.users.get(user.id);
82
+ // Clean up old indexes if email or userName changed
83
+ if (existing) {
84
+ if (existing.email && existing.email.toLowerCase() !== user.email?.toLowerCase()) {
85
+ this.emailIndex.delete(existing.email.toLowerCase());
86
+ }
87
+ if (existing.userName && existing.userName.toLowerCase() !== user.userName?.toLowerCase()) {
88
+ this.userNameIndex.delete(existing.userName.toLowerCase());
89
+ }
90
+ }
91
+ // Store the user
92
+ this.users.set(user.id, user);
93
+ // Update indexes
94
+ if (user.email) {
95
+ this.emailIndex.set(user.email.toLowerCase(), user.id);
96
+ }
97
+ if (user.userName) {
98
+ this.userNameIndex.set(user.userName.toLowerCase(), user.id);
99
+ }
100
+ }
101
+ async delete(sub) {
102
+ const user = this.users.get(sub);
103
+ if (user) {
104
+ // Clean up indexes
105
+ if (user.email) {
106
+ this.emailIndex.delete(user.email.toLowerCase());
107
+ }
108
+ if (user.userName) {
109
+ this.userNameIndex.delete(user.userName.toLowerCase());
110
+ }
111
+ }
112
+ this.users.delete(sub);
113
+ }
114
+ }
package/dist/utils.js ADDED
@@ -0,0 +1,23 @@
1
+ let defaultInstance;
2
+ export function must(value, message = 'Assertion failed. Required value is null or undefined.') {
3
+ if (value === undefined || value === null) {
4
+ throw new Error(message);
5
+ }
6
+ return value;
7
+ }
8
+ export function setDefaultInstance(es) {
9
+ defaultInstance = es;
10
+ }
11
+ export function getDefaultInstance() {
12
+ return defaultInstance;
13
+ }
14
+ /**
15
+ * If an es is defined, then return it, otherwise return the defaultEnterpriseStandard
16
+ */
17
+ export function getES(es) {
18
+ if (es)
19
+ return es;
20
+ if (defaultInstance)
21
+ return defaultInstance;
22
+ throw new Error(`TODO standardize the error message when there isn't a default EntepriseStandard`);
23
+ }
package/dist/vault.js ADDED
@@ -0,0 +1,22 @@
1
+ export function vault(url) {
2
+ async function getFullSecret(path, token) {
3
+ const resp = await fetch(`${url}/${path}`, { headers: { 'X-Vault-Token': token } });
4
+ if (resp.status !== 200) {
5
+ throw new Error(`Vault returned invalid status, ${resp.status}: '${resp.statusText}' from URL: ${url}`);
6
+ }
7
+ try {
8
+ const secret = await resp.json();
9
+ return secret.data;
10
+ }
11
+ catch (cause) {
12
+ throw new Error('Error retrieving secret', { cause });
13
+ }
14
+ }
15
+ return {
16
+ url,
17
+ getFullSecret,
18
+ getSecret: async (path, token) => {
19
+ return (await getFullSecret(path, token)).data;
20
+ },
21
+ };
22
+ }
@@ -1,4 +1,4 @@
1
- import { EnterpriseStandard } from '.';
1
+ import type { EnterpriseStandard } from '.';
2
2
  import type { TokenValidationResult } from './types/workload-schema';
3
3
  import type { WorkloadIdentity } from './workload';
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"workload-server.d.ts","sourceRoot":"","sources":["../src/workload-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,GAAG,CAAC;AAEvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,KAAK,EAAY,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAc7D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAMlH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAarH;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAIlG"}
1
+ {"version":3,"file":"workload-server.d.ts","sourceRoot":"","sources":["../src/workload-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,GAAG,CAAC;AAC5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAcnD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAMlH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAarH;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAIlG"}