workos 0.11.2 → 0.12.0-beta.1

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 (169) hide show
  1. package/README.md +163 -6
  2. package/dist/bin.js +20 -1
  3. package/dist/bin.js.map +1 -1
  4. package/dist/check-coverage.ts +237 -0
  5. package/dist/commands/dev.d.ts +23 -0
  6. package/dist/commands/dev.js +139 -0
  7. package/dist/commands/dev.js.map +1 -0
  8. package/dist/commands/emulate.d.ts +6 -0
  9. package/dist/commands/emulate.js +64 -0
  10. package/dist/commands/emulate.js.map +1 -0
  11. package/dist/emulate/core/id.d.ts +33 -0
  12. package/dist/emulate/core/id.js +58 -0
  13. package/dist/emulate/core/id.js.map +1 -0
  14. package/dist/emulate/core/index.d.ts +8 -0
  15. package/dist/emulate/core/index.js +8 -0
  16. package/dist/emulate/core/index.js.map +1 -0
  17. package/dist/emulate/core/jwt.d.ts +28 -0
  18. package/dist/emulate/core/jwt.js +78 -0
  19. package/dist/emulate/core/jwt.js.map +1 -0
  20. package/dist/emulate/core/middleware/auth.d.ts +18 -0
  21. package/dist/emulate/core/middleware/auth.js +28 -0
  22. package/dist/emulate/core/middleware/auth.js.map +1 -0
  23. package/dist/emulate/core/middleware/error-handler.d.ts +22 -0
  24. package/dist/emulate/core/middleware/error-handler.js +72 -0
  25. package/dist/emulate/core/middleware/error-handler.js.map +1 -0
  26. package/dist/emulate/core/pagination.d.ts +21 -0
  27. package/dist/emulate/core/pagination.js +35 -0
  28. package/dist/emulate/core/pagination.js.map +1 -0
  29. package/dist/emulate/core/plugin.d.ts +15 -0
  30. package/dist/emulate/core/plugin.js +2 -0
  31. package/dist/emulate/core/plugin.js.map +1 -0
  32. package/dist/emulate/core/server.d.ts +17 -0
  33. package/dist/emulate/core/server.js +116 -0
  34. package/dist/emulate/core/server.js.map +1 -0
  35. package/dist/emulate/core/store.d.ts +42 -0
  36. package/dist/emulate/core/store.js +148 -0
  37. package/dist/emulate/core/store.js.map +1 -0
  38. package/dist/emulate/index.d.ts +25 -0
  39. package/dist/emulate/index.js +47 -0
  40. package/dist/emulate/index.js.map +1 -0
  41. package/dist/emulate/workos/entities.d.ts +360 -0
  42. package/dist/emulate/workos/entities.js +2 -0
  43. package/dist/emulate/workos/entities.js.map +1 -0
  44. package/dist/emulate/workos/event-bus.d.ts +12 -0
  45. package/dist/emulate/workos/event-bus.js +45 -0
  46. package/dist/emulate/workos/event-bus.js.map +1 -0
  47. package/dist/emulate/workos/helpers.d.ts +63 -0
  48. package/dist/emulate/workos/helpers.js +518 -0
  49. package/dist/emulate/workos/helpers.js.map +1 -0
  50. package/dist/emulate/workos/index.d.ts +91 -0
  51. package/dist/emulate/workos/index.js +319 -0
  52. package/dist/emulate/workos/index.js.map +1 -0
  53. package/dist/emulate/workos/routes/api-keys.d.ts +2 -0
  54. package/dist/emulate/workos/routes/api-keys.js +35 -0
  55. package/dist/emulate/workos/routes/api-keys.js.map +1 -0
  56. package/dist/emulate/workos/routes/audit-logs.d.ts +2 -0
  57. package/dist/emulate/workos/routes/audit-logs.js +107 -0
  58. package/dist/emulate/workos/routes/audit-logs.js.map +1 -0
  59. package/dist/emulate/workos/routes/auth-challenges.d.ts +2 -0
  60. package/dist/emulate/workos/routes/auth-challenges.js +51 -0
  61. package/dist/emulate/workos/routes/auth-challenges.js.map +1 -0
  62. package/dist/emulate/workos/routes/auth-factors.d.ts +2 -0
  63. package/dist/emulate/workos/routes/auth-factors.js +51 -0
  64. package/dist/emulate/workos/routes/auth-factors.js.map +1 -0
  65. package/dist/emulate/workos/routes/auth.d.ts +2 -0
  66. package/dist/emulate/workos/routes/auth.js +349 -0
  67. package/dist/emulate/workos/routes/auth.js.map +1 -0
  68. package/dist/emulate/workos/routes/authorization-checks.d.ts +10 -0
  69. package/dist/emulate/workos/routes/authorization-checks.js +135 -0
  70. package/dist/emulate/workos/routes/authorization-checks.js.map +1 -0
  71. package/dist/emulate/workos/routes/authorization-org-roles.d.ts +2 -0
  72. package/dist/emulate/workos/routes/authorization-org-roles.js +206 -0
  73. package/dist/emulate/workos/routes/authorization-org-roles.js.map +1 -0
  74. package/dist/emulate/workos/routes/authorization-permissions.d.ts +2 -0
  75. package/dist/emulate/workos/routes/authorization-permissions.js +78 -0
  76. package/dist/emulate/workos/routes/authorization-permissions.js.map +1 -0
  77. package/dist/emulate/workos/routes/authorization-resources.d.ts +2 -0
  78. package/dist/emulate/workos/routes/authorization-resources.js +128 -0
  79. package/dist/emulate/workos/routes/authorization-resources.js.map +1 -0
  80. package/dist/emulate/workos/routes/authorization-roles.d.ts +2 -0
  81. package/dist/emulate/workos/routes/authorization-roles.js +136 -0
  82. package/dist/emulate/workos/routes/authorization-roles.js.map +1 -0
  83. package/dist/emulate/workos/routes/config.d.ts +2 -0
  84. package/dist/emulate/workos/routes/config.js +56 -0
  85. package/dist/emulate/workos/routes/config.js.map +1 -0
  86. package/dist/emulate/workos/routes/connect.d.ts +2 -0
  87. package/dist/emulate/workos/routes/connect.js +69 -0
  88. package/dist/emulate/workos/routes/connect.js.map +1 -0
  89. package/dist/emulate/workos/routes/connections.d.ts +2 -0
  90. package/dist/emulate/workos/routes/connections.js +77 -0
  91. package/dist/emulate/workos/routes/connections.js.map +1 -0
  92. package/dist/emulate/workos/routes/data-integrations.d.ts +2 -0
  93. package/dist/emulate/workos/routes/data-integrations.js +55 -0
  94. package/dist/emulate/workos/routes/data-integrations.js.map +1 -0
  95. package/dist/emulate/workos/routes/directories.d.ts +2 -0
  96. package/dist/emulate/workos/routes/directories.js +106 -0
  97. package/dist/emulate/workos/routes/directories.js.map +1 -0
  98. package/dist/emulate/workos/routes/email-verification.d.ts +2 -0
  99. package/dist/emulate/workos/routes/email-verification.js +49 -0
  100. package/dist/emulate/workos/routes/email-verification.js.map +1 -0
  101. package/dist/emulate/workos/routes/events.d.ts +2 -0
  102. package/dist/emulate/workos/routes/events.js +21 -0
  103. package/dist/emulate/workos/routes/events.js.map +1 -0
  104. package/dist/emulate/workos/routes/feature-flags.d.ts +2 -0
  105. package/dist/emulate/workos/routes/feature-flags.js +131 -0
  106. package/dist/emulate/workos/routes/feature-flags.js.map +1 -0
  107. package/dist/emulate/workos/routes/invitations.d.ts +2 -0
  108. package/dist/emulate/workos/routes/invitations.js +125 -0
  109. package/dist/emulate/workos/routes/invitations.js.map +1 -0
  110. package/dist/emulate/workos/routes/legacy-mfa.d.ts +2 -0
  111. package/dist/emulate/workos/routes/legacy-mfa.js +75 -0
  112. package/dist/emulate/workos/routes/legacy-mfa.js.map +1 -0
  113. package/dist/emulate/workos/routes/magic-auth.d.ts +2 -0
  114. package/dist/emulate/workos/routes/magic-auth.js +32 -0
  115. package/dist/emulate/workos/routes/magic-auth.js.map +1 -0
  116. package/dist/emulate/workos/routes/memberships.d.ts +2 -0
  117. package/dist/emulate/workos/routes/memberships.js +118 -0
  118. package/dist/emulate/workos/routes/memberships.js.map +1 -0
  119. package/dist/emulate/workos/routes/organization-domains.d.ts +2 -0
  120. package/dist/emulate/workos/routes/organization-domains.js +58 -0
  121. package/dist/emulate/workos/routes/organization-domains.js.map +1 -0
  122. package/dist/emulate/workos/routes/organizations.d.ts +2 -0
  123. package/dist/emulate/workos/routes/organizations.js +133 -0
  124. package/dist/emulate/workos/routes/organizations.js.map +1 -0
  125. package/dist/emulate/workos/routes/password-reset.d.ts +2 -0
  126. package/dist/emulate/workos/routes/password-reset.js +61 -0
  127. package/dist/emulate/workos/routes/password-reset.js.map +1 -0
  128. package/dist/emulate/workos/routes/pipes.d.ts +2 -0
  129. package/dist/emulate/workos/routes/pipes.js +86 -0
  130. package/dist/emulate/workos/routes/pipes.js.map +1 -0
  131. package/dist/emulate/workos/routes/portal.d.ts +2 -0
  132. package/dist/emulate/workos/routes/portal.js +18 -0
  133. package/dist/emulate/workos/routes/portal.js.map +1 -0
  134. package/dist/emulate/workos/routes/radar.d.ts +2 -0
  135. package/dist/emulate/workos/routes/radar.js +45 -0
  136. package/dist/emulate/workos/routes/radar.js.map +1 -0
  137. package/dist/emulate/workos/routes/sessions.d.ts +2 -0
  138. package/dist/emulate/workos/routes/sessions.js +51 -0
  139. package/dist/emulate/workos/routes/sessions.js.map +1 -0
  140. package/dist/emulate/workos/routes/sso.d.ts +2 -0
  141. package/dist/emulate/workos/routes/sso.js +160 -0
  142. package/dist/emulate/workos/routes/sso.js.map +1 -0
  143. package/dist/emulate/workos/routes/user-features.d.ts +2 -0
  144. package/dist/emulate/workos/routes/user-features.js +50 -0
  145. package/dist/emulate/workos/routes/user-features.js.map +1 -0
  146. package/dist/emulate/workos/routes/users.d.ts +2 -0
  147. package/dist/emulate/workos/routes/users.js +133 -0
  148. package/dist/emulate/workos/routes/users.js.map +1 -0
  149. package/dist/emulate/workos/routes/webhook-endpoints.d.ts +2 -0
  150. package/dist/emulate/workos/routes/webhook-endpoints.js +70 -0
  151. package/dist/emulate/workos/routes/webhook-endpoints.js.map +1 -0
  152. package/dist/emulate/workos/routes/widgets.d.ts +2 -0
  153. package/dist/emulate/workos/routes/widgets.js +27 -0
  154. package/dist/emulate/workos/routes/widgets.js.map +1 -0
  155. package/dist/emulate/workos/store.d.ts +48 -0
  156. package/dist/emulate/workos/store.js +93 -0
  157. package/dist/emulate/workos/store.js.map +1 -0
  158. package/dist/emulate/workos/webhook-signer.d.ts +1 -0
  159. package/dist/emulate/workos/webhook-signer.js +8 -0
  160. package/dist/emulate/workos/webhook-signer.js.map +1 -0
  161. package/dist/gen-routes-lib.spec.ts +659 -0
  162. package/dist/gen-routes-lib.ts +647 -0
  163. package/dist/gen-routes.ts +96 -0
  164. package/dist/lib/dev-command.d.ts +26 -0
  165. package/dist/lib/dev-command.js +122 -0
  166. package/dist/lib/dev-command.js.map +1 -0
  167. package/dist/utils/help-json.js +23 -0
  168. package/dist/utils/help-json.js.map +1 -1
  169. package/package.json +20 -7
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Coverage checker: compares the WorkOS OpenAPI spec against the emulator's
4
+ * registered routes to find missing or extra endpoints.
5
+ *
6
+ * Usage:
7
+ * pnpm check:coverage path/to/openapi.yaml
8
+ * pnpm check:coverage ~/Developer/workos/packages/api/open-api-spec.yaml
9
+ *
10
+ * Reports:
11
+ * - Spec endpoints missing from the emulator
12
+ * - Emulator endpoints not in the spec (custom/internal)
13
+ * - Coverage percentage
14
+ */
15
+
16
+ import { readFileSync, existsSync, readdirSync } from 'node:fs';
17
+ import { resolve, extname, join } from 'node:path';
18
+ import YAML from 'yaml';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Parse OpenAPI spec endpoints
22
+ // ---------------------------------------------------------------------------
23
+
24
+ interface SpecEndpoint {
25
+ method: string;
26
+ path: string;
27
+ operationId?: string;
28
+ summary?: string;
29
+ tags: string[];
30
+ }
31
+
32
+ function parseOpenApiEndpoints(specPath: string): SpecEndpoint[] {
33
+ const raw = readFileSync(specPath, 'utf-8');
34
+ const ext = extname(specPath).toLowerCase();
35
+ const spec = ext === '.yaml' || ext === '.yml' ? YAML.parse(raw) : JSON.parse(raw);
36
+
37
+ const endpoints: SpecEndpoint[] = [];
38
+ const methods = ['get', 'post', 'put', 'patch', 'delete'] as const;
39
+
40
+ for (const [path, item] of Object.entries(spec.paths ?? {}) as [string, any][]) {
41
+ for (const method of methods) {
42
+ const op = item[method];
43
+ if (!op) continue;
44
+
45
+ // Normalize OpenAPI path params {id} → :id
46
+ const normalizedPath = path.replace(/\{([^}]+)\}/g, ':$1');
47
+
48
+ endpoints.push({
49
+ method: method.toUpperCase(),
50
+ path: normalizedPath,
51
+ operationId: op.operationId,
52
+ summary: op.summary,
53
+ tags: op.tags ?? [],
54
+ });
55
+ }
56
+ }
57
+
58
+ return endpoints;
59
+ }
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Parse emulator registered routes from source files
63
+ // ---------------------------------------------------------------------------
64
+
65
+ interface EmulatorEndpoint {
66
+ method: string;
67
+ path: string;
68
+ file: string;
69
+ line: number;
70
+ }
71
+
72
+ function parseEmulatorEndpoints(): EmulatorEndpoint[] {
73
+ const routesDir = resolve('src/emulate/workos/routes');
74
+ const serverFile = resolve('src/emulate/core/server.ts');
75
+ const endpoints: EmulatorEndpoint[] = [];
76
+
77
+ const routePattern = /app\.(get|post|put|patch|delete)\('([^']+)'/g;
78
+
79
+ const filesToScan: string[] = [];
80
+
81
+ // Collect route files
82
+ if (existsSync(routesDir)) {
83
+ for (const file of readdirSync(routesDir)) {
84
+ if (file.endsWith('.ts') && !file.endsWith('.spec.ts')) {
85
+ filesToScan.push(join(routesDir, file));
86
+ }
87
+ }
88
+ }
89
+
90
+ // Also scan server.ts for JWKS and other direct routes
91
+ if (existsSync(serverFile)) {
92
+ filesToScan.push(serverFile);
93
+ }
94
+
95
+ for (const filePath of filesToScan) {
96
+ const content = readFileSync(filePath, 'utf-8');
97
+ const lines = content.split('\n');
98
+
99
+ for (let i = 0; i < lines.length; i++) {
100
+ routePattern.lastIndex = 0;
101
+ let match;
102
+ while ((match = routePattern.exec(lines[i])) !== null) {
103
+ endpoints.push({
104
+ method: match[1].toUpperCase(),
105
+ path: match[2],
106
+ file: filePath.replace(resolve('.') + '/', ''),
107
+ line: i + 1,
108
+ });
109
+ }
110
+ }
111
+ }
112
+
113
+ return endpoints;
114
+ }
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // Normalize paths for comparison
118
+ // ---------------------------------------------------------------------------
119
+
120
+ /** Normalize path params to a canonical form for matching.
121
+ * e.g., :id, :orgId, :organization_id all become :param in the same position */
122
+ function normalizePath(path: string): string {
123
+ return path
124
+ .replace(/:[a-zA-Z_]+/g, ':param')
125
+ .replace(/\/+$/, '')
126
+ .toLowerCase();
127
+ }
128
+
129
+ function routeKey(method: string, path: string): string {
130
+ return `${method} ${normalizePath(path)}`;
131
+ }
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Main
135
+ // ---------------------------------------------------------------------------
136
+
137
+ function main(): void {
138
+ const specPath = process.argv[2];
139
+ if (!specPath) {
140
+ console.error('Usage: check-coverage <openapi-spec-path>');
141
+ console.error(' e.g.: pnpm check:coverage ~/Developer/workos/packages/api/open-api-spec.yaml');
142
+ process.exit(1);
143
+ }
144
+
145
+ const resolvedSpec = resolve(specPath);
146
+ if (!existsSync(resolvedSpec)) {
147
+ console.error(`Spec file not found: ${resolvedSpec}`);
148
+ process.exit(1);
149
+ }
150
+
151
+ const specEndpoints = parseOpenApiEndpoints(resolvedSpec);
152
+ const emulatorEndpoints = parseEmulatorEndpoints();
153
+
154
+ // Build lookup maps
155
+ const specMap = new Map<string, SpecEndpoint>();
156
+ for (const ep of specEndpoints) {
157
+ specMap.set(routeKey(ep.method, ep.path), ep);
158
+ }
159
+
160
+ const emulatorMap = new Map<string, EmulatorEndpoint>();
161
+ for (const ep of emulatorEndpoints) {
162
+ emulatorMap.set(routeKey(ep.method, ep.path), ep);
163
+ }
164
+
165
+ // Find gaps
166
+ const missing: SpecEndpoint[] = [];
167
+ const covered: SpecEndpoint[] = [];
168
+ for (const [key, ep] of specMap) {
169
+ if (emulatorMap.has(key)) {
170
+ covered.push(ep);
171
+ } else {
172
+ missing.push(ep);
173
+ }
174
+ }
175
+
176
+ const extra: EmulatorEndpoint[] = [];
177
+ for (const [key, ep] of emulatorMap) {
178
+ if (!specMap.has(key)) {
179
+ extra.push(ep);
180
+ }
181
+ }
182
+
183
+ // Group missing by tag
184
+ const missingByTag = new Map<string, SpecEndpoint[]>();
185
+ for (const ep of missing) {
186
+ const tag = ep.tags[0] ?? 'untagged';
187
+ if (!missingByTag.has(tag)) missingByTag.set(tag, []);
188
+ missingByTag.get(tag)!.push(ep);
189
+ }
190
+
191
+ // Report
192
+ const total = specEndpoints.length;
193
+ const coveredCount = covered.length;
194
+ const pct = total > 0 ? ((coveredCount / total) * 100).toFixed(1) : '0';
195
+
196
+ console.log('');
197
+ console.log('=== Emulator API Coverage Report ===');
198
+ console.log('');
199
+ console.log(` Spec endpoints: ${total}`);
200
+ console.log(` Emulator endpoints: ${emulatorEndpoints.length}`);
201
+ console.log(` Covered: ${coveredCount}/${total} (${pct}%)`);
202
+ console.log(` Missing: ${missing.length}`);
203
+ console.log(` Extra (emulator-only): ${extra.length}`);
204
+ console.log('');
205
+
206
+ if (missing.length > 0) {
207
+ console.log('--- Missing from emulator ---');
208
+ console.log('');
209
+ for (const [tag, eps] of [...missingByTag.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
210
+ console.log(` [${tag}]`);
211
+ for (const ep of eps) {
212
+ const desc = ep.summary ? ` — ${ep.summary}` : '';
213
+ console.log(` ${ep.method.padEnd(6)} ${ep.path}${desc}`);
214
+ }
215
+ console.log('');
216
+ }
217
+ }
218
+
219
+ if (extra.length > 0) {
220
+ console.log('--- Emulator-only (not in spec) ---');
221
+ console.log('');
222
+ for (const ep of extra.sort((a, b) => a.path.localeCompare(b.path))) {
223
+ console.log(` ${ep.method.padEnd(6)} ${ep.path} (${ep.file}:${ep.line})`);
224
+ }
225
+ console.log('');
226
+ }
227
+
228
+ if (missing.length === 0) {
229
+ console.log('Full coverage — all spec endpoints are implemented.');
230
+ console.log('');
231
+ }
232
+
233
+ // Exit 1 if there are missing endpoints (useful for CI later)
234
+ process.exit(missing.length > 0 ? 1 : 0);
235
+ }
236
+
237
+ main();
@@ -0,0 +1,23 @@
1
+ import { type EmulatorSeedConfig } from '../emulate/index.js';
2
+ export interface DevArgs {
3
+ port: number;
4
+ seed?: string;
5
+ '--'?: string[];
6
+ }
7
+ /**
8
+ * Build the env vars object to inject into the child process.
9
+ *
10
+ * Sets both the base URL style (`WORKOS_API_BASE_URL`) and the decomposed
11
+ * style (`WORKOS_API_HOSTNAME` + `WORKOS_API_PORT` + `WORKOS_API_HTTPS`)
12
+ * so the emulator works with authkit SDKs (which read the decomposed vars)
13
+ * and direct SDK consumers (which may use the base URL).
14
+ */
15
+ /**
16
+ * Default seed data for `workos dev` so the AuthKit login flow works
17
+ * out of the box. Provides a test user, an organization with a verified
18
+ * domain, and a membership linking the two. Skipped when the user
19
+ * provides `--seed` or a `workos-emulate.config.*` file is auto-detected.
20
+ */
21
+ export declare const DEFAULT_DEV_SEED: EmulatorSeedConfig;
22
+ export declare function buildDevEnv(emulatorUrl: string, apiKey?: string): Record<string, string>;
23
+ export declare function runDev(argv: DevArgs): Promise<void>;
@@ -0,0 +1,139 @@
1
+ import { createEmulator } from '../emulate/index.js';
2
+ import { resolveDevCommand } from '../lib/dev-command.js';
3
+ import { spawn } from 'node:child_process';
4
+ import { readFileSync, existsSync } from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+ import { parse as parseYaml } from 'yaml';
7
+ import chalk from 'chalk';
8
+ function loadSeedFile(filePath) {
9
+ const resolved = resolve(filePath);
10
+ if (!existsSync(resolved)) {
11
+ console.error(`Seed file not found: ${resolved}`);
12
+ process.exit(1);
13
+ }
14
+ const content = readFileSync(resolved, 'utf-8');
15
+ if (resolved.endsWith('.json')) {
16
+ return JSON.parse(content);
17
+ }
18
+ return parseYaml(content);
19
+ }
20
+ function autoDetectSeedFile() {
21
+ const candidates = ['workos-emulate.config.yaml', 'workos-emulate.config.yml', 'workos-emulate.config.json'];
22
+ for (const name of candidates) {
23
+ const filePath = resolve(name);
24
+ if (existsSync(filePath)) {
25
+ return loadSeedFile(filePath);
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ /**
31
+ * Build the env vars object to inject into the child process.
32
+ *
33
+ * Sets both the base URL style (`WORKOS_API_BASE_URL`) and the decomposed
34
+ * style (`WORKOS_API_HOSTNAME` + `WORKOS_API_PORT` + `WORKOS_API_HTTPS`)
35
+ * so the emulator works with authkit SDKs (which read the decomposed vars)
36
+ * and direct SDK consumers (which may use the base URL).
37
+ */
38
+ /**
39
+ * Default seed data for `workos dev` so the AuthKit login flow works
40
+ * out of the box. Provides a test user, an organization with a verified
41
+ * domain, and a membership linking the two. Skipped when the user
42
+ * provides `--seed` or a `workos-emulate.config.*` file is auto-detected.
43
+ */
44
+ export const DEFAULT_DEV_SEED = {
45
+ users: [
46
+ {
47
+ email: 'test@example.com',
48
+ first_name: 'Test',
49
+ last_name: 'User',
50
+ password: 'password',
51
+ email_verified: true,
52
+ },
53
+ ],
54
+ organizations: [
55
+ {
56
+ name: 'Test Organization',
57
+ domains: [{ domain: 'example.com', state: 'verified' }],
58
+ },
59
+ ],
60
+ };
61
+ export function buildDevEnv(emulatorUrl, apiKey = 'sk_test_default') {
62
+ const url = new URL(emulatorUrl);
63
+ return {
64
+ WORKOS_API_BASE_URL: emulatorUrl,
65
+ WORKOS_API_HOSTNAME: url.hostname,
66
+ WORKOS_API_PORT: url.port,
67
+ WORKOS_API_HTTPS: 'false',
68
+ WORKOS_API_KEY: apiKey,
69
+ WORKOS_CLIENT_ID: 'client_emulated',
70
+ };
71
+ }
72
+ export async function runDev(argv) {
73
+ const userSeed = argv.seed ? loadSeedFile(argv.seed) : autoDetectSeedFile();
74
+ const seedConfig = userSeed ?? DEFAULT_DEV_SEED;
75
+ // 1. Start emulator
76
+ const emulator = await createEmulator({
77
+ port: argv.port,
78
+ seed: seedConfig,
79
+ });
80
+ // 2. Resolve dev command
81
+ const explicit = argv['--'];
82
+ const devCmd = explicit && explicit.length > 0
83
+ ? { command: explicit[0], args: explicit.slice(1), framework: null }
84
+ : await resolveDevCommand(process.cwd());
85
+ // 3. Print status banner
86
+ console.log();
87
+ console.log(`${chalk.cyan('WorkOS Emulate')} ${chalk.dim(emulator.url)}`);
88
+ if (devCmd.framework) {
89
+ console.log(chalk.dim(`Detected ${devCmd.framework}`));
90
+ }
91
+ console.log(chalk.dim(`Running: ${devCmd.command} ${devCmd.args.join(' ')}`));
92
+ if (!userSeed) {
93
+ console.log();
94
+ console.log(` ${chalk.dim('Email:')} test@example.com`);
95
+ console.log(` ${chalk.dim('Password:')} password`);
96
+ }
97
+ console.log();
98
+ // 4. Spawn child process with env vars
99
+ let child;
100
+ try {
101
+ child = spawn(devCmd.command, devCmd.args, {
102
+ stdio: 'inherit',
103
+ env: {
104
+ ...process.env,
105
+ ...buildDevEnv(emulator.url, emulator.apiKey),
106
+ },
107
+ });
108
+ }
109
+ catch {
110
+ console.error(chalk.red(`Failed to start: ${devCmd.command} ${devCmd.args.join(' ')}`));
111
+ console.error(chalk.dim('Try specifying the command explicitly: workos dev -- <your-command>'));
112
+ await emulator.close();
113
+ process.exit(1);
114
+ }
115
+ child.on('error', async (err) => {
116
+ console.error(chalk.red(`Failed to start: ${devCmd.command}`));
117
+ if (err.code === 'ENOENT') {
118
+ console.error(chalk.dim(`Command not found: ${devCmd.command}`));
119
+ console.error(chalk.dim('Try specifying the command explicitly: workos dev -- <your-command>'));
120
+ }
121
+ else {
122
+ console.error(chalk.dim(err.message));
123
+ }
124
+ await emulator.close();
125
+ process.exit(1);
126
+ });
127
+ // 5. Signal handling — forward to child, then close emulator
128
+ const shutdown = (signal) => {
129
+ child.kill(signal);
130
+ emulator.close().then(() => process.exit(0));
131
+ };
132
+ process.on('SIGINT', () => shutdown('SIGINT'));
133
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
134
+ // 6. If child exits, close emulator and exit with same code
135
+ child.on('exit', (code) => {
136
+ emulator.close().then(() => process.exit(code ?? 0));
137
+ });
138
+ }
139
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { createEmulator, type EmulatorSeedConfig } from '../emulate/index.js';\nimport { resolveDevCommand } from '../lib/dev-command.js';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport chalk from 'chalk';\n\nexport interface DevArgs {\n port: number;\n seed?: string;\n '--'?: string[];\n}\n\nfunction loadSeedFile(filePath: string): EmulatorSeedConfig {\n const resolved = resolve(filePath);\n if (!existsSync(resolved)) {\n console.error(`Seed file not found: ${resolved}`);\n process.exit(1);\n }\n\n const content = readFileSync(resolved, 'utf-8');\n if (resolved.endsWith('.json')) {\n return JSON.parse(content) as EmulatorSeedConfig;\n }\n return parseYaml(content) as EmulatorSeedConfig;\n}\n\nfunction autoDetectSeedFile(): EmulatorSeedConfig | null {\n const candidates = ['workos-emulate.config.yaml', 'workos-emulate.config.yml', 'workos-emulate.config.json'];\n\n for (const name of candidates) {\n const filePath = resolve(name);\n if (existsSync(filePath)) {\n return loadSeedFile(filePath);\n }\n }\n return null;\n}\n\n/**\n * Build the env vars object to inject into the child process.\n *\n * Sets both the base URL style (`WORKOS_API_BASE_URL`) and the decomposed\n * style (`WORKOS_API_HOSTNAME` + `WORKOS_API_PORT` + `WORKOS_API_HTTPS`)\n * so the emulator works with authkit SDKs (which read the decomposed vars)\n * and direct SDK consumers (which may use the base URL).\n */\n/**\n * Default seed data for `workos dev` so the AuthKit login flow works\n * out of the box. Provides a test user, an organization with a verified\n * domain, and a membership linking the two. Skipped when the user\n * provides `--seed` or a `workos-emulate.config.*` file is auto-detected.\n */\nexport const DEFAULT_DEV_SEED: EmulatorSeedConfig = {\n users: [\n {\n email: 'test@example.com',\n first_name: 'Test',\n last_name: 'User',\n password: 'password',\n email_verified: true,\n },\n ],\n organizations: [\n {\n name: 'Test Organization',\n domains: [{ domain: 'example.com', state: 'verified' }],\n },\n ],\n};\n\nexport function buildDevEnv(emulatorUrl: string, apiKey = 'sk_test_default'): Record<string, string> {\n const url = new URL(emulatorUrl);\n return {\n WORKOS_API_BASE_URL: emulatorUrl,\n WORKOS_API_HOSTNAME: url.hostname,\n WORKOS_API_PORT: url.port,\n WORKOS_API_HTTPS: 'false',\n WORKOS_API_KEY: apiKey,\n WORKOS_CLIENT_ID: 'client_emulated',\n };\n}\n\nexport async function runDev(argv: DevArgs): Promise<void> {\n const userSeed = argv.seed ? loadSeedFile(argv.seed) : autoDetectSeedFile();\n const seedConfig = userSeed ?? DEFAULT_DEV_SEED;\n\n // 1. Start emulator\n const emulator = await createEmulator({\n port: argv.port,\n seed: seedConfig,\n });\n\n // 2. Resolve dev command\n const explicit = argv['--'];\n const devCmd =\n explicit && explicit.length > 0\n ? { command: explicit[0], args: explicit.slice(1), framework: null as string | null }\n : await resolveDevCommand(process.cwd());\n\n // 3. Print status banner\n console.log();\n console.log(`${chalk.cyan('WorkOS Emulate')} ${chalk.dim(emulator.url)}`);\n if (devCmd.framework) {\n console.log(chalk.dim(`Detected ${devCmd.framework}`));\n }\n console.log(chalk.dim(`Running: ${devCmd.command} ${devCmd.args.join(' ')}`));\n if (!userSeed) {\n console.log();\n console.log(` ${chalk.dim('Email:')} test@example.com`);\n console.log(` ${chalk.dim('Password:')} password`);\n }\n console.log();\n\n // 4. Spawn child process with env vars\n let child: ChildProcess;\n try {\n child = spawn(devCmd.command, devCmd.args, {\n stdio: 'inherit',\n env: {\n ...process.env,\n ...buildDevEnv(emulator.url, emulator.apiKey),\n },\n });\n } catch {\n console.error(chalk.red(`Failed to start: ${devCmd.command} ${devCmd.args.join(' ')}`));\n console.error(chalk.dim('Try specifying the command explicitly: workos dev -- <your-command>'));\n await emulator.close();\n process.exit(1);\n }\n\n child.on('error', async (err) => {\n console.error(chalk.red(`Failed to start: ${devCmd.command}`));\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n console.error(chalk.dim(`Command not found: ${devCmd.command}`));\n console.error(chalk.dim('Try specifying the command explicitly: workos dev -- <your-command>'));\n } else {\n console.error(chalk.dim(err.message));\n }\n await emulator.close();\n process.exit(1);\n });\n\n // 5. Signal handling — forward to child, then close emulator\n const shutdown = (signal: NodeJS.Signals) => {\n child.kill(signal);\n emulator.close().then(() => process.exit(0));\n };\n process.on('SIGINT', () => shutdown('SIGINT'));\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n\n // 6. If child exits, close emulator and exit with same code\n child.on('exit', (code) => {\n emulator.close().then(() => process.exit(code ?? 0));\n });\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export interface EmulateArgs {
2
+ port: number;
3
+ seed?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare function runEmulate(argv: EmulateArgs): Promise<void>;
@@ -0,0 +1,64 @@
1
+ import { createEmulator } from '../emulate/index.js';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { parse as parseYaml } from 'yaml';
5
+ import chalk from 'chalk';
6
+ function loadSeedFile(filePath) {
7
+ const resolved = resolve(filePath);
8
+ if (!existsSync(resolved)) {
9
+ console.error(`Seed file not found: ${resolved}`);
10
+ process.exit(1);
11
+ }
12
+ const content = readFileSync(resolved, 'utf-8');
13
+ if (resolved.endsWith('.json')) {
14
+ return JSON.parse(content);
15
+ }
16
+ return parseYaml(content);
17
+ }
18
+ function autoDetectSeedFile() {
19
+ const candidates = ['workos-emulate.config.yaml', 'workos-emulate.config.yml', 'workos-emulate.config.json'];
20
+ for (const name of candidates) {
21
+ const filePath = resolve(name);
22
+ if (existsSync(filePath)) {
23
+ return loadSeedFile(filePath);
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ function printBanner(emulator) {
29
+ console.log();
30
+ console.log(chalk.bold(' WorkOS Emulator'));
31
+ console.log();
32
+ console.log(` ${chalk.dim('URL:')} ${emulator.url}`);
33
+ console.log(` ${chalk.dim('API Key:')} ${emulator.apiKey}`);
34
+ console.log(` ${chalk.dim('Health:')} ${emulator.url}/health`);
35
+ console.log();
36
+ console.log(chalk.dim(' Press Ctrl+C to stop'));
37
+ console.log();
38
+ }
39
+ export async function runEmulate(argv) {
40
+ const seedConfig = argv.seed ? loadSeedFile(argv.seed) : autoDetectSeedFile();
41
+ const emulator = await createEmulator({
42
+ port: argv.port,
43
+ seed: seedConfig ?? undefined,
44
+ });
45
+ if (argv.json) {
46
+ console.log(JSON.stringify({
47
+ url: emulator.url,
48
+ port: emulator.port,
49
+ apiKey: emulator.apiKey,
50
+ health: `${emulator.url}/health`,
51
+ }));
52
+ }
53
+ else {
54
+ printBanner(emulator);
55
+ }
56
+ const shutdown = () => {
57
+ if (!argv.json)
58
+ console.log(`\n${chalk.dim('Shutting down...')}`);
59
+ emulator.close().then(() => process.exit(0));
60
+ };
61
+ process.once('SIGINT', shutdown);
62
+ process.once('SIGTERM', shutdown);
63
+ }
64
+ //# sourceMappingURL=emulate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emulate.js","sourceRoot":"","sources":["../../src/commands/emulate.ts"],"names":[],"mappings":"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","sourcesContent":["import { createEmulator, type EmulatorSeedConfig } from '../emulate/index.js';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport chalk from 'chalk';\n\nexport interface EmulateArgs {\n port: number;\n seed?: string;\n json?: boolean;\n}\n\nfunction loadSeedFile(filePath: string): EmulatorSeedConfig {\n const resolved = resolve(filePath);\n if (!existsSync(resolved)) {\n console.error(`Seed file not found: ${resolved}`);\n process.exit(1);\n }\n\n const content = readFileSync(resolved, 'utf-8');\n if (resolved.endsWith('.json')) {\n return JSON.parse(content) as EmulatorSeedConfig;\n }\n return parseYaml(content) as EmulatorSeedConfig;\n}\n\nfunction autoDetectSeedFile(): EmulatorSeedConfig | null {\n const candidates = ['workos-emulate.config.yaml', 'workos-emulate.config.yml', 'workos-emulate.config.json'];\n\n for (const name of candidates) {\n const filePath = resolve(name);\n if (existsSync(filePath)) {\n return loadSeedFile(filePath);\n }\n }\n return null;\n}\n\nfunction printBanner(emulator: { url: string; port: number; apiKey: string }): void {\n console.log();\n console.log(chalk.bold(' WorkOS Emulator'));\n console.log();\n console.log(` ${chalk.dim('URL:')} ${emulator.url}`);\n console.log(` ${chalk.dim('API Key:')} ${emulator.apiKey}`);\n console.log(` ${chalk.dim('Health:')} ${emulator.url}/health`);\n console.log();\n console.log(chalk.dim(' Press Ctrl+C to stop'));\n console.log();\n}\n\nexport async function runEmulate(argv: EmulateArgs): Promise<void> {\n const seedConfig = argv.seed ? loadSeedFile(argv.seed) : autoDetectSeedFile();\n\n const emulator = await createEmulator({\n port: argv.port,\n seed: seedConfig ?? undefined,\n });\n\n if (argv.json) {\n console.log(\n JSON.stringify({\n url: emulator.url,\n port: emulator.port,\n apiKey: emulator.apiKey,\n health: `${emulator.url}/health`,\n }),\n );\n } else {\n printBanner(emulator);\n }\n\n const shutdown = () => {\n if (!argv.json) console.log(`\\n${chalk.dim('Shutting down...')}`);\n emulator.close().then(() => process.exit(0));\n };\n process.once('SIGINT', shutdown);\n process.once('SIGTERM', shutdown);\n}\n"]}
@@ -0,0 +1,33 @@
1
+ export declare function generateId(prefix: string): string;
2
+ export declare function resetIdState(): void;
3
+ export declare const ID_PREFIXES: {
4
+ readonly user: "user";
5
+ readonly organization: "org";
6
+ readonly organization_membership: "om";
7
+ readonly organization_domain: "org_domain";
8
+ readonly connection: "conn";
9
+ readonly connection_domain: "conn_domain";
10
+ readonly directory: "directory";
11
+ readonly directory_user: "directory_user";
12
+ readonly directory_group: "directory_grp";
13
+ readonly event: "event";
14
+ readonly invitation: "inv";
15
+ readonly session: "session";
16
+ readonly email_verification: "email_verification";
17
+ readonly password_reset: "password_reset";
18
+ readonly magic_auth: "magic_auth";
19
+ readonly authentication_factor: "auth_factor";
20
+ readonly authentication_challenge: "auth_challenge";
21
+ readonly api_key: "api_key";
22
+ readonly profile: "prof";
23
+ readonly pipe_connection: "pipe_conn";
24
+ readonly audit_log_action: "audit_action";
25
+ readonly audit_log_event: "audit_event";
26
+ readonly audit_log_export: "audit_export";
27
+ readonly feature_flag: "ff";
28
+ readonly flag_target: "ff_target";
29
+ readonly connect_application: "connect_app";
30
+ readonly client_secret: "client_secret";
31
+ readonly data_integration_auth: "di_auth";
32
+ readonly radar_attempt: "radar_attempt";
33
+ };
@@ -0,0 +1,58 @@
1
+ const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
2
+ const ENCODING_LEN = ENCODING.length; // 32
3
+ const TIME_LEN = 10; // 10 chars encodes 48-bit ms timestamp
4
+ const RANDOM_LEN = 16; // 16 chars of randomness
5
+ let lastTime = 0;
6
+ export function generateId(prefix) {
7
+ let now = Date.now();
8
+ if (now <= lastTime) {
9
+ now = lastTime + 1;
10
+ }
11
+ lastTime = now;
12
+ let timeStr = '';
13
+ let t = now;
14
+ for (let i = TIME_LEN - 1; i >= 0; i--) {
15
+ timeStr = ENCODING[t % ENCODING_LEN] + timeStr;
16
+ t = Math.floor(t / ENCODING_LEN);
17
+ }
18
+ let randStr = '';
19
+ for (let i = 0; i < RANDOM_LEN; i++) {
20
+ randStr += ENCODING[Math.floor(Math.random() * ENCODING_LEN)];
21
+ }
22
+ return `${prefix}_${timeStr}${randStr}`;
23
+ }
24
+ export function resetIdState() {
25
+ lastTime = 0;
26
+ }
27
+ export const ID_PREFIXES = {
28
+ user: 'user',
29
+ organization: 'org',
30
+ organization_membership: 'om',
31
+ organization_domain: 'org_domain',
32
+ connection: 'conn',
33
+ connection_domain: 'conn_domain',
34
+ directory: 'directory',
35
+ directory_user: 'directory_user',
36
+ directory_group: 'directory_grp',
37
+ event: 'event',
38
+ invitation: 'inv',
39
+ session: 'session',
40
+ email_verification: 'email_verification',
41
+ password_reset: 'password_reset',
42
+ magic_auth: 'magic_auth',
43
+ authentication_factor: 'auth_factor',
44
+ authentication_challenge: 'auth_challenge',
45
+ api_key: 'api_key',
46
+ profile: 'prof',
47
+ pipe_connection: 'pipe_conn',
48
+ audit_log_action: 'audit_action',
49
+ audit_log_event: 'audit_event',
50
+ audit_log_export: 'audit_export',
51
+ feature_flag: 'ff',
52
+ flag_target: 'ff_target',
53
+ connect_application: 'connect_app',
54
+ client_secret: 'client_secret',
55
+ data_integration_auth: 'di_auth',
56
+ radar_attempt: 'radar_attempt',
57
+ };
58
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/emulate/core/id.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,kCAAkC,CAAC,CAAC,qBAAqB;AAC1E,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK;AAC3C,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC,uCAAuC;AAC5D,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,yBAAyB;AAEhD,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACrB,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QACpB,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,QAAQ,GAAG,GAAG,CAAC;IAEf,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC,GAAG,GAAG,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,OAAO,GAAG,QAAQ,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC;QAC/C,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,QAAQ,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,MAAM;IACZ,YAAY,EAAE,KAAK;IACnB,uBAAuB,EAAE,IAAI;IAC7B,mBAAmB,EAAE,YAAY;IACjC,UAAU,EAAE,MAAM;IAClB,iBAAiB,EAAE,aAAa;IAChC,SAAS,EAAE,WAAW;IACtB,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,eAAe;IAChC,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,KAAK;IACjB,OAAO,EAAE,SAAS;IAClB,kBAAkB,EAAE,oBAAoB;IACxC,cAAc,EAAE,gBAAgB;IAChC,UAAU,EAAE,YAAY;IACxB,qBAAqB,EAAE,aAAa;IACpC,wBAAwB,EAAE,gBAAgB;IAC1C,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,WAAW;IAC5B,gBAAgB,EAAE,cAAc;IAChC,eAAe,EAAE,aAAa;IAC9B,gBAAgB,EAAE,cAAc;IAChC,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,WAAW;IACxB,mBAAmB,EAAE,aAAa;IAClC,aAAa,EAAE,eAAe;IAC9B,qBAAqB,EAAE,SAAS;IAChC,aAAa,EAAE,eAAe;CACtB,CAAC","sourcesContent":["const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32\nconst ENCODING_LEN = ENCODING.length; // 32\nconst TIME_LEN = 10; // 10 chars encodes 48-bit ms timestamp\nconst RANDOM_LEN = 16; // 16 chars of randomness\n\nlet lastTime = 0;\n\nexport function generateId(prefix: string): string {\n let now = Date.now();\n if (now <= lastTime) {\n now = lastTime + 1;\n }\n lastTime = now;\n\n let timeStr = '';\n let t = now;\n for (let i = TIME_LEN - 1; i >= 0; i--) {\n timeStr = ENCODING[t % ENCODING_LEN] + timeStr;\n t = Math.floor(t / ENCODING_LEN);\n }\n\n let randStr = '';\n for (let i = 0; i < RANDOM_LEN; i++) {\n randStr += ENCODING[Math.floor(Math.random() * ENCODING_LEN)];\n }\n\n return `${prefix}_${timeStr}${randStr}`;\n}\n\nexport function resetIdState(): void {\n lastTime = 0;\n}\n\nexport const ID_PREFIXES = {\n user: 'user',\n organization: 'org',\n organization_membership: 'om',\n organization_domain: 'org_domain',\n connection: 'conn',\n connection_domain: 'conn_domain',\n directory: 'directory',\n directory_user: 'directory_user',\n directory_group: 'directory_grp',\n event: 'event',\n invitation: 'inv',\n session: 'session',\n email_verification: 'email_verification',\n password_reset: 'password_reset',\n magic_auth: 'magic_auth',\n authentication_factor: 'auth_factor',\n authentication_challenge: 'auth_challenge',\n api_key: 'api_key',\n profile: 'prof',\n pipe_connection: 'pipe_conn',\n audit_log_action: 'audit_action',\n audit_log_event: 'audit_event',\n audit_log_export: 'audit_export',\n feature_flag: 'ff',\n flag_target: 'ff_target',\n connect_application: 'connect_app',\n client_secret: 'client_secret',\n data_integration_auth: 'di_auth',\n radar_attempt: 'radar_attempt',\n} as const;\n"]}
@@ -0,0 +1,8 @@
1
+ export { Store, Collection, type Entity, type InsertInput, type FilterFn, type SortFn, type CollectionHooks, } from './store.js';
2
+ export { generateId, resetIdState, ID_PREFIXES } from './id.js';
3
+ export { cursorPaginate, type CursorPaginationOptions, type CursorPaginatedResult } from './pagination.js';
4
+ export { JWTManager, type JWTPayload } from './jwt.js';
5
+ export { createServer, type ServerOptions } from './server.js';
6
+ export { type ServicePlugin, type RouteContext } from './plugin.js';
7
+ export { WorkOSApiError, createApiErrorHandler, requestIdMiddleware, notFound, validationError, unauthorized, forbidden, parseJsonBody, } from './middleware/error-handler.js';
8
+ export { authMiddleware, type WorkOSAppEnv, type WorkOSAuthContext, type ApiKeyMap } from './middleware/auth.js';
@@ -0,0 +1,8 @@
1
+ export { Store, Collection, } from './store.js';
2
+ export { generateId, resetIdState, ID_PREFIXES } from './id.js';
3
+ export { cursorPaginate } from './pagination.js';
4
+ export { JWTManager } from './jwt.js';
5
+ export { createServer } from './server.js';
6
+ export { WorkOSApiError, createApiErrorHandler, requestIdMiddleware, notFound, validationError, unauthorized, forbidden, parseJsonBody, } from './middleware/error-handler.js';
7
+ export { authMiddleware } from './middleware/auth.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/emulate/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,UAAU,GAMX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,cAAc,EAA4D,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAE/D,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,SAAS,EACT,aAAa,GACd,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAA6D,MAAM,sBAAsB,CAAC","sourcesContent":["export {\n Store,\n Collection,\n type Entity,\n type InsertInput,\n type FilterFn,\n type SortFn,\n type CollectionHooks,\n} from './store.js';\nexport { generateId, resetIdState, ID_PREFIXES } from './id.js';\nexport { cursorPaginate, type CursorPaginationOptions, type CursorPaginatedResult } from './pagination.js';\nexport { JWTManager, type JWTPayload } from './jwt.js';\nexport { createServer, type ServerOptions } from './server.js';\nexport { type ServicePlugin, type RouteContext } from './plugin.js';\nexport {\n WorkOSApiError,\n createApiErrorHandler,\n requestIdMiddleware,\n notFound,\n validationError,\n unauthorized,\n forbidden,\n parseJsonBody,\n} from './middleware/error-handler.js';\nexport { authMiddleware, type WorkOSAppEnv, type WorkOSAuthContext, type ApiKeyMap } from './middleware/auth.js';\n"]}
@@ -0,0 +1,28 @@
1
+ export interface JWTPayload {
2
+ sub: string;
3
+ sid?: string;
4
+ org_id?: string;
5
+ role?: string;
6
+ permissions?: string[];
7
+ iss: string;
8
+ aud: string;
9
+ exp: number;
10
+ iat: number;
11
+ }
12
+ interface SignOptions {
13
+ expiresIn?: number;
14
+ }
15
+ export declare class JWTManager {
16
+ private privateKey;
17
+ private publicKey;
18
+ private kid;
19
+ issuer: string;
20
+ constructor(issuer?: string);
21
+ sign(payload: Omit<JWTPayload, 'iss' | 'iat' | 'exp'>, options?: SignOptions): string;
22
+ verify(token: string): JWTPayload;
23
+ getJWKS(): {
24
+ keys: Record<string, unknown>[];
25
+ };
26
+ getPublicKeyPem(): string;
27
+ }
28
+ export {};