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,78 @@
1
+ import { createSign, createVerify, generateKeyPairSync } from 'node:crypto';
2
+ function base64url(input) {
3
+ const buf = typeof input === 'string' ? Buffer.from(input) : input;
4
+ return buf.toString('base64url');
5
+ }
6
+ function base64urlDecode(input) {
7
+ return Buffer.from(input, 'base64url');
8
+ }
9
+ export class JWTManager {
10
+ privateKey;
11
+ publicKey;
12
+ kid;
13
+ issuer;
14
+ constructor(issuer = 'https://api.workos.com') {
15
+ this.issuer = issuer;
16
+ const { privateKey, publicKey } = generateKeyPairSync('rsa', {
17
+ modulusLength: 2048,
18
+ });
19
+ this.privateKey = privateKey;
20
+ this.publicKey = publicKey;
21
+ this.kid = `workos_emulate_${Date.now()}`;
22
+ }
23
+ sign(payload, options) {
24
+ const now = Math.floor(Date.now() / 1000);
25
+ const expiresIn = options?.expiresIn ?? 3600;
26
+ const fullPayload = {
27
+ ...payload,
28
+ iss: this.issuer,
29
+ iat: now,
30
+ exp: now + expiresIn,
31
+ };
32
+ const header = { alg: 'RS256', typ: 'JWT', kid: this.kid };
33
+ const headerB64 = base64url(JSON.stringify(header));
34
+ const payloadB64 = base64url(JSON.stringify(fullPayload));
35
+ const signingInput = `${headerB64}.${payloadB64}`;
36
+ const signer = createSign('RSA-SHA256');
37
+ signer.update(signingInput);
38
+ const signature = signer.sign(this.privateKey, 'base64url');
39
+ return `${signingInput}.${signature}`;
40
+ }
41
+ verify(token) {
42
+ const parts = token.split('.');
43
+ if (parts.length !== 3) {
44
+ throw new Error('Invalid token format');
45
+ }
46
+ const [headerB64, payloadB64, signature] = parts;
47
+ const signingInput = `${headerB64}.${payloadB64}`;
48
+ const verifier = createVerify('RSA-SHA256');
49
+ verifier.update(signingInput);
50
+ const valid = verifier.verify(this.publicKey, signature, 'base64url');
51
+ if (!valid) {
52
+ throw new Error('Invalid token signature');
53
+ }
54
+ const payload = JSON.parse(base64urlDecode(payloadB64).toString('utf-8'));
55
+ const now = Math.floor(Date.now() / 1000);
56
+ if (payload.exp && payload.exp < now) {
57
+ throw new Error('Token has expired');
58
+ }
59
+ return payload;
60
+ }
61
+ getJWKS() {
62
+ const jwk = this.publicKey.export({ format: 'jwk' });
63
+ return {
64
+ keys: [
65
+ {
66
+ ...jwk,
67
+ kid: this.kid,
68
+ alg: 'RS256',
69
+ use: 'sig',
70
+ },
71
+ ],
72
+ };
73
+ }
74
+ getPublicKeyPem() {
75
+ return this.publicKey.export({ type: 'spki', format: 'pem' });
76
+ }
77
+ }
78
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../../src/emulate/core/jwt.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSign, createVerify, generateKeyPairSync, type KeyObject } from 'node:crypto';\n\nexport interface JWTPayload {\n sub: string;\n sid?: string;\n org_id?: string;\n role?: string;\n permissions?: string[];\n iss: string;\n aud: string;\n exp: number;\n iat: number;\n}\n\ninterface SignOptions {\n expiresIn?: number;\n}\n\nfunction base64url(input: Buffer | string): string {\n const buf = typeof input === 'string' ? Buffer.from(input) : input;\n return buf.toString('base64url');\n}\n\nfunction base64urlDecode(input: string): Buffer {\n return Buffer.from(input, 'base64url');\n}\n\nexport class JWTManager {\n private privateKey: KeyObject;\n private publicKey: KeyObject;\n private kid: string;\n issuer: string;\n\n constructor(issuer = 'https://api.workos.com') {\n this.issuer = issuer;\n const { privateKey, publicKey } = generateKeyPairSync('rsa', {\n modulusLength: 2048,\n });\n this.privateKey = privateKey;\n this.publicKey = publicKey;\n this.kid = `workos_emulate_${Date.now()}`;\n }\n\n sign(payload: Omit<JWTPayload, 'iss' | 'iat' | 'exp'>, options?: SignOptions): string {\n const now = Math.floor(Date.now() / 1000);\n const expiresIn = options?.expiresIn ?? 3600;\n\n const fullPayload: JWTPayload = {\n ...payload,\n iss: this.issuer,\n iat: now,\n exp: now + expiresIn,\n };\n\n const header = { alg: 'RS256', typ: 'JWT', kid: this.kid };\n const headerB64 = base64url(JSON.stringify(header));\n const payloadB64 = base64url(JSON.stringify(fullPayload));\n const signingInput = `${headerB64}.${payloadB64}`;\n\n const signer = createSign('RSA-SHA256');\n signer.update(signingInput);\n const signature = signer.sign(this.privateKey, 'base64url');\n\n return `${signingInput}.${signature}`;\n }\n\n verify(token: string): JWTPayload {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid token format');\n }\n\n const [headerB64, payloadB64, signature] = parts;\n const signingInput = `${headerB64}.${payloadB64}`;\n\n const verifier = createVerify('RSA-SHA256');\n verifier.update(signingInput);\n const valid = verifier.verify(this.publicKey, signature, 'base64url');\n\n if (!valid) {\n throw new Error('Invalid token signature');\n }\n\n const payload = JSON.parse(base64urlDecode(payloadB64).toString('utf-8')) as JWTPayload;\n\n const now = Math.floor(Date.now() / 1000);\n if (payload.exp && payload.exp < now) {\n throw new Error('Token has expired');\n }\n\n return payload;\n }\n\n getJWKS(): { keys: Record<string, unknown>[] } {\n const jwk = this.publicKey.export({ format: 'jwk' });\n return {\n keys: [\n {\n ...jwk,\n kid: this.kid,\n alg: 'RS256',\n use: 'sig',\n },\n ],\n };\n }\n\n getPublicKeyPem(): string {\n return this.publicKey.export({ type: 'spki', format: 'pem' }) as string;\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { Context, Next } from 'hono';
2
+ export interface WorkOSAuthContext {
3
+ environment: string;
4
+ apiKey: string;
5
+ }
6
+ export type WorkOSAppEnv = {
7
+ Variables: {
8
+ auth?: WorkOSAuthContext;
9
+ requestId?: string;
10
+ };
11
+ };
12
+ export type ApiKeyMap = Record<string, {
13
+ environment: string;
14
+ }>;
15
+ export declare function authMiddleware(apiKeys: ApiKeyMap): (c: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<{
16
+ message: string;
17
+ code: string;
18
+ }, 401, "json">) | undefined>;
@@ -0,0 +1,28 @@
1
+ export function authMiddleware(apiKeys) {
2
+ return async (c, next) => {
3
+ const authHeader = c.req.header('Authorization');
4
+ if (!authHeader) {
5
+ return c.json({
6
+ message: 'Unauthorized',
7
+ code: 'unauthorized',
8
+ }, 401);
9
+ }
10
+ const token = authHeader.replace(/^Bearer\s+/i, '').trim();
11
+ if (!token.startsWith('sk_')) {
12
+ return c.json({
13
+ message: 'Unauthorized',
14
+ code: 'unauthorized',
15
+ }, 401);
16
+ }
17
+ const keyInfo = apiKeys[token];
18
+ if (!keyInfo) {
19
+ return c.json({
20
+ message: 'Unauthorized',
21
+ code: 'unauthorized',
22
+ }, 401);
23
+ }
24
+ c.set('auth', { environment: keyInfo.environment, apiKey: token });
25
+ await next();
26
+ };
27
+ }
28
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/emulate/core/middleware/auth.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,cAAc,CAAC,OAAkB;IAC/C,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACtC,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,OAAO,EAAE,cAAc;gBACvB,IAAI,EAAE,cAAc;aACrB,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAE3D,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,OAAO,EAAE,cAAc;gBACvB,IAAI,EAAE,cAAc;aACrB,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,OAAO,EAAE,cAAc;gBACvB,IAAI,EAAE,cAAc;aACrB,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAA8B,CAAC,CAAC;QAC/F,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { Context, Next } from 'hono';\n\nexport interface WorkOSAuthContext {\n environment: string;\n apiKey: string;\n}\n\nexport type WorkOSAppEnv = {\n Variables: {\n auth?: WorkOSAuthContext;\n requestId?: string;\n };\n};\n\nexport type ApiKeyMap = Record<string, { environment: string }>;\n\nexport function authMiddleware(apiKeys: ApiKeyMap) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header('Authorization');\n if (!authHeader) {\n return c.json(\n {\n message: 'Unauthorized',\n code: 'unauthorized',\n },\n 401,\n );\n }\n\n const token = authHeader.replace(/^Bearer\\s+/i, '').trim();\n\n if (!token.startsWith('sk_')) {\n return c.json(\n {\n message: 'Unauthorized',\n code: 'unauthorized',\n },\n 401,\n );\n }\n\n const keyInfo = apiKeys[token];\n if (!keyInfo) {\n return c.json(\n {\n message: 'Unauthorized',\n code: 'unauthorized',\n },\n 401,\n );\n }\n\n c.set('auth', { environment: keyInfo.environment, apiKey: token } satisfies WorkOSAuthContext);\n await next();\n };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import type { Context, ErrorHandler, MiddlewareHandler } from 'hono';
2
+ export declare class WorkOSApiError extends Error {
3
+ status: number;
4
+ code: string;
5
+ errors?: Array<{
6
+ field: string;
7
+ code: string;
8
+ message?: string;
9
+ }> | undefined;
10
+ constructor(status: number, message: string, code: string, errors?: Array<{
11
+ field: string;
12
+ code: string;
13
+ message?: string;
14
+ }> | undefined);
15
+ }
16
+ export declare function createApiErrorHandler(): ErrorHandler;
17
+ export declare function requestIdMiddleware(): MiddlewareHandler;
18
+ export declare function notFound(resource?: string): WorkOSApiError;
19
+ export declare function validationError(message: string, errors?: WorkOSApiError['errors']): WorkOSApiError;
20
+ export declare function unauthorized(): WorkOSApiError;
21
+ export declare function forbidden(): WorkOSApiError;
22
+ export declare function parseJsonBody(c: Context): Promise<Record<string, unknown>>;
@@ -0,0 +1,72 @@
1
+ export class WorkOSApiError extends Error {
2
+ status;
3
+ code;
4
+ errors;
5
+ constructor(status, message, code, errors) {
6
+ super(message);
7
+ this.status = status;
8
+ this.code = code;
9
+ this.errors = errors;
10
+ this.name = 'WorkOSApiError';
11
+ }
12
+ }
13
+ export function createApiErrorHandler() {
14
+ return (err, c) => {
15
+ if (err instanceof WorkOSApiError) {
16
+ const body = {
17
+ message: err.message,
18
+ code: err.code,
19
+ };
20
+ if (err.errors) {
21
+ body.errors = err.errors;
22
+ }
23
+ return c.json(body, err.status);
24
+ }
25
+ const status = errorStatus(err);
26
+ return c.json({
27
+ message: 'Internal Server Error',
28
+ code: 'server_error',
29
+ }, status);
30
+ };
31
+ }
32
+ export function requestIdMiddleware() {
33
+ return async (c, next) => {
34
+ const requestId = c.req.header('X-Request-ID') ?? `req_${crypto.randomUUID()}`;
35
+ c.set('requestId', requestId);
36
+ c.header('X-Request-ID', requestId);
37
+ await next();
38
+ };
39
+ }
40
+ export function notFound(resource) {
41
+ return new WorkOSApiError(404, resource ? `${resource} not found` : 'Not Found', 'not_found');
42
+ }
43
+ export function validationError(message, errors) {
44
+ return new WorkOSApiError(422, message, 'unprocessable_entity', errors);
45
+ }
46
+ export function unauthorized() {
47
+ return new WorkOSApiError(401, 'Unauthorized', 'unauthorized');
48
+ }
49
+ export function forbidden() {
50
+ return new WorkOSApiError(403, 'Forbidden', 'forbidden');
51
+ }
52
+ export async function parseJsonBody(c) {
53
+ try {
54
+ const body = await c.req.json();
55
+ if (body && typeof body === 'object' && !Array.isArray(body)) {
56
+ return body;
57
+ }
58
+ return {};
59
+ }
60
+ catch {
61
+ throw new WorkOSApiError(400, 'Problems parsing JSON', 'invalid_request_body');
62
+ }
63
+ }
64
+ function errorStatus(err) {
65
+ if (err && typeof err === 'object' && 'status' in err) {
66
+ const s = err.status;
67
+ if (typeof s === 'number' && Number.isFinite(s))
68
+ return s;
69
+ }
70
+ return 500;
71
+ }
72
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../../src/emulate/core/middleware/error-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, ErrorHandler, MiddlewareHandler } from 'hono';\nimport type { ContentfulStatusCode } from 'hono/utils/http-status';\n\nexport class WorkOSApiError extends Error {\n constructor(\n public status: number,\n message: string,\n public code: string,\n public errors?: Array<{ field: string; code: string; message?: string }>,\n ) {\n super(message);\n this.name = 'WorkOSApiError';\n }\n}\n\nexport function createApiErrorHandler(): ErrorHandler {\n return (err, c) => {\n if (err instanceof WorkOSApiError) {\n const body: Record<string, unknown> = {\n message: err.message,\n code: err.code,\n };\n if (err.errors) {\n body.errors = err.errors;\n }\n return c.json(body, err.status as ContentfulStatusCode);\n }\n\n const status = errorStatus(err);\n return c.json(\n {\n message: 'Internal Server Error',\n code: 'server_error',\n },\n status as ContentfulStatusCode,\n );\n };\n}\n\nexport function requestIdMiddleware(): MiddlewareHandler {\n return async (c, next) => {\n const requestId = c.req.header('X-Request-ID') ?? `req_${crypto.randomUUID()}`;\n c.set('requestId', requestId);\n c.header('X-Request-ID', requestId);\n await next();\n };\n}\n\nexport function notFound(resource?: string): WorkOSApiError {\n return new WorkOSApiError(404, resource ? `${resource} not found` : 'Not Found', 'not_found');\n}\n\nexport function validationError(message: string, errors?: WorkOSApiError['errors']): WorkOSApiError {\n return new WorkOSApiError(422, message, 'unprocessable_entity', errors);\n}\n\nexport function unauthorized(): WorkOSApiError {\n return new WorkOSApiError(401, 'Unauthorized', 'unauthorized');\n}\n\nexport function forbidden(): WorkOSApiError {\n return new WorkOSApiError(403, 'Forbidden', 'forbidden');\n}\n\nexport async function parseJsonBody(c: Context): Promise<Record<string, unknown>> {\n try {\n const body = await c.req.json();\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n return body as Record<string, unknown>;\n }\n return {};\n } catch {\n throw new WorkOSApiError(400, 'Problems parsing JSON', 'invalid_request_body');\n }\n}\n\nfunction errorStatus(err: unknown): number {\n if (err && typeof err === 'object' && 'status' in err) {\n const s = (err as { status: unknown }).status;\n if (typeof s === 'number' && Number.isFinite(s)) return s;\n }\n return 500;\n}\n"]}
@@ -0,0 +1,21 @@
1
+ export interface Entity {
2
+ id: string;
3
+ created_at: string;
4
+ updated_at: string;
5
+ }
6
+ export interface CursorPaginationOptions<T> {
7
+ filter?: (item: T) => boolean;
8
+ sort?: (a: T, b: T) => number;
9
+ limit?: number;
10
+ order?: 'asc' | 'desc';
11
+ before?: string;
12
+ after?: string;
13
+ }
14
+ export interface CursorPaginatedResult<T> {
15
+ data: T[];
16
+ list_metadata: {
17
+ before: string | null;
18
+ after: string | null;
19
+ };
20
+ }
21
+ export declare function cursorPaginate<T extends Entity>(items: T[], options?: CursorPaginationOptions<T>): CursorPaginatedResult<T>;
@@ -0,0 +1,35 @@
1
+ export function cursorPaginate(items, options = {}) {
2
+ let filtered = options.filter ? items.filter(options.filter) : [...items];
3
+ const order = options.order ?? 'desc';
4
+ const defaultSort = (a, b) => order === 'desc'
5
+ ? b.created_at.localeCompare(a.created_at) || b.id.localeCompare(a.id)
6
+ : a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id);
7
+ filtered.sort(options.sort ?? defaultSort);
8
+ const limit = Math.max(1, Math.min(options.limit ?? 10, 100));
9
+ let startIndex = 0;
10
+ let endIndex = filtered.length;
11
+ if (options.after) {
12
+ const afterIndex = filtered.findIndex((item) => item.id === options.after);
13
+ if (afterIndex !== -1) {
14
+ startIndex = afterIndex + 1;
15
+ }
16
+ }
17
+ if (options.before) {
18
+ const beforeIndex = filtered.findIndex((item) => item.id === options.before);
19
+ if (beforeIndex !== -1) {
20
+ endIndex = beforeIndex;
21
+ }
22
+ }
23
+ const window = filtered.slice(startIndex, endIndex);
24
+ const page = window.slice(0, limit);
25
+ const hasMore = window.length > limit;
26
+ const hasPrev = startIndex > 0;
27
+ return {
28
+ data: page,
29
+ list_metadata: {
30
+ before: page.length > 0 && hasPrev ? page[0].id : null,
31
+ after: page.length > 0 && hasMore ? page[page.length - 1].id : null,
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/emulate/core/pagination.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,cAAc,CAC5B,KAAU,EACV,UAAsC,EAAE;IAExC,IAAI,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;IAE1E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IACtC,MAAM,WAAW,GAAG,CAAC,CAAI,EAAE,CAAI,EAAE,EAAE,CACjC,KAAK,KAAK,MAAM;QACd,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE3E,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC;IAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IAE9D,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE/B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3E,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACtB,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7E,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,QAAQ,GAAG,WAAW,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEpC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtC,MAAM,OAAO,GAAG,UAAU,GAAG,CAAC,CAAC;IAE/B,OAAO;QACL,IAAI,EAAE,IAAI;QACV,aAAa,EAAE;YACb,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;YACtD,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;SACpE;KACF,CAAC;AACJ,CAAC","sourcesContent":["export interface Entity {\n id: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface CursorPaginationOptions<T> {\n filter?: (item: T) => boolean;\n sort?: (a: T, b: T) => number;\n limit?: number;\n order?: 'asc' | 'desc';\n before?: string;\n after?: string;\n}\n\nexport interface CursorPaginatedResult<T> {\n data: T[];\n list_metadata: {\n before: string | null;\n after: string | null;\n };\n}\n\nexport function cursorPaginate<T extends Entity>(\n items: T[],\n options: CursorPaginationOptions<T> = {},\n): CursorPaginatedResult<T> {\n let filtered = options.filter ? items.filter(options.filter) : [...items];\n\n const order = options.order ?? 'desc';\n const defaultSort = (a: T, b: T) =>\n order === 'desc'\n ? b.created_at.localeCompare(a.created_at) || b.id.localeCompare(a.id)\n : a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id);\n\n filtered.sort(options.sort ?? defaultSort);\n\n const limit = Math.max(1, Math.min(options.limit ?? 10, 100));\n\n let startIndex = 0;\n let endIndex = filtered.length;\n\n if (options.after) {\n const afterIndex = filtered.findIndex((item) => item.id === options.after);\n if (afterIndex !== -1) {\n startIndex = afterIndex + 1;\n }\n }\n\n if (options.before) {\n const beforeIndex = filtered.findIndex((item) => item.id === options.before);\n if (beforeIndex !== -1) {\n endIndex = beforeIndex;\n }\n }\n\n const window = filtered.slice(startIndex, endIndex);\n const page = window.slice(0, limit);\n\n const hasMore = window.length > limit;\n const hasPrev = startIndex > 0;\n\n return {\n data: page,\n list_metadata: {\n before: page.length > 0 && hasPrev ? page[0].id : null,\n after: page.length > 0 && hasMore ? page[page.length - 1].id : null,\n },\n };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { Hono } from 'hono';
2
+ import type { Store } from './store.js';
3
+ import type { JWTManager } from './jwt.js';
4
+ import type { WorkOSAppEnv } from './middleware/auth.js';
5
+ export interface RouteContext {
6
+ app: Hono<WorkOSAppEnv>;
7
+ store: Store;
8
+ jwt: JWTManager;
9
+ baseUrl: string;
10
+ }
11
+ export interface ServicePlugin {
12
+ name: string;
13
+ register(ctx: RouteContext): void;
14
+ seed?(store: Store, baseUrl: string): void;
15
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/emulate/core/plugin.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hono } from 'hono';\nimport type { Store } from './store.js';\nimport type { JWTManager } from './jwt.js';\nimport type { WorkOSAppEnv } from './middleware/auth.js';\n\nexport interface RouteContext {\n app: Hono<WorkOSAppEnv>;\n store: Store;\n jwt: JWTManager;\n baseUrl: string;\n}\n\nexport interface ServicePlugin {\n name: string;\n register(ctx: RouteContext): void;\n seed?(store: Store, baseUrl: string): void;\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { Hono } from 'hono';
2
+ import { Store } from './store.js';
3
+ import { JWTManager } from './jwt.js';
4
+ import { type ApiKeyMap, type WorkOSAppEnv } from './middleware/auth.js';
5
+ import type { ServicePlugin } from './plugin.js';
6
+ export interface ServerOptions {
7
+ port?: number;
8
+ baseUrl?: string;
9
+ apiKeys?: ApiKeyMap;
10
+ }
11
+ export declare function createServer(plugin: ServicePlugin, options?: ServerOptions): {
12
+ app: Hono<WorkOSAppEnv, import("hono/types").BlankSchema, "/">;
13
+ store: Store;
14
+ jwt: JWTManager;
15
+ port: number;
16
+ baseUrl: string;
17
+ };
@@ -0,0 +1,116 @@
1
+ import { Hono } from 'hono';
2
+ import { cors } from 'hono/cors';
3
+ import { Store } from './store.js';
4
+ import { JWTManager } from './jwt.js';
5
+ import { createApiErrorHandler, requestIdMiddleware } from './middleware/error-handler.js';
6
+ import { authMiddleware } from './middleware/auth.js';
7
+ export function createServer(plugin, options = {}) {
8
+ const port = options.port ?? 4100;
9
+ const baseUrl = options.baseUrl ?? `http://localhost:${port}`;
10
+ const app = new Hono();
11
+ const store = new Store();
12
+ const jwt = new JWTManager(baseUrl);
13
+ const apiKeys = options.apiKeys ?? {
14
+ sk_test_default: { environment: 'test' },
15
+ };
16
+ app.onError(createApiErrorHandler());
17
+ app.use('*', cors());
18
+ app.use('*', requestIdMiddleware());
19
+ // JWKS endpoint (public, no auth)
20
+ app.get('/sso/jwks/:client_id', (c) => {
21
+ return c.json(jwt.getJWKS());
22
+ });
23
+ // Auth middleware for API routes
24
+ app.use('/api/*', authMiddleware(apiKeys));
25
+ app.use('/user_management/*', async (c, next) => {
26
+ const path = new URL(c.req.url).pathname;
27
+ // Public endpoints (no auth required)
28
+ if (path === '/user_management/authorize' ||
29
+ path === '/user_management/authenticate' ||
30
+ path === '/user_management/sessions/logout' ||
31
+ path.startsWith('/user_management/sessions/jwks/')) {
32
+ return next();
33
+ }
34
+ return authMiddleware(apiKeys)(c, next);
35
+ });
36
+ app.use('/x/authkit/*', authMiddleware(apiKeys));
37
+ app.use('/organizations', authMiddleware(apiKeys));
38
+ app.use('/organizations/*', authMiddleware(apiKeys));
39
+ app.use('/organization_memberships', authMiddleware(apiKeys));
40
+ app.use('/organization_memberships/*', authMiddleware(apiKeys));
41
+ app.use('/organization_domains', authMiddleware(apiKeys));
42
+ app.use('/organization_domains/*', authMiddleware(apiKeys));
43
+ app.use('/connections', authMiddleware(apiKeys));
44
+ app.use('/connections/*', authMiddleware(apiKeys));
45
+ app.use('/directories', authMiddleware(apiKeys));
46
+ app.use('/directories/*', authMiddleware(apiKeys));
47
+ app.use('/directory_groups', authMiddleware(apiKeys));
48
+ app.use('/directory_groups/*', authMiddleware(apiKeys));
49
+ app.use('/directory_users', authMiddleware(apiKeys));
50
+ app.use('/directory_users/*', authMiddleware(apiKeys));
51
+ app.use('/events', authMiddleware(apiKeys));
52
+ app.use('/events/*', authMiddleware(apiKeys));
53
+ app.use('/pipes/*', authMiddleware(apiKeys));
54
+ app.use('/audit_logs/*', authMiddleware(apiKeys));
55
+ app.use('/feature-flags', authMiddleware(apiKeys));
56
+ app.use('/feature-flags/*', authMiddleware(apiKeys));
57
+ app.use('/connect/*', authMiddleware(apiKeys));
58
+ app.use('/data-integrations/*', async (c, next) => {
59
+ const path = new URL(c.req.url).pathname;
60
+ if (path.endsWith('/authorize'))
61
+ return next();
62
+ return authMiddleware(apiKeys)(c, next);
63
+ });
64
+ app.use('/radar/*', authMiddleware(apiKeys));
65
+ app.use('/api_keys', authMiddleware(apiKeys));
66
+ app.use('/api_keys/*', authMiddleware(apiKeys));
67
+ app.use('/portal/*', authMiddleware(apiKeys));
68
+ app.use('/webhook_endpoints', authMiddleware(apiKeys));
69
+ app.use('/webhook_endpoints/*', authMiddleware(apiKeys));
70
+ app.use('/auth/factors', authMiddleware(apiKeys));
71
+ app.use('/auth/factors/*', authMiddleware(apiKeys));
72
+ app.use('/auth/challenges/*', authMiddleware(apiKeys));
73
+ // Rate limiting
74
+ const rateLimitCounters = new Map();
75
+ let lastPruneAt = Math.floor(Date.now() / 1000);
76
+ app.use('*', async (c, next) => {
77
+ const auth = c.get('auth');
78
+ const key = auth?.apiKey ?? '__anonymous__';
79
+ const now = Math.floor(Date.now() / 1000);
80
+ if (now - lastPruneAt > 3600) {
81
+ for (const [k, val] of rateLimitCounters) {
82
+ if (val.resetAt <= now)
83
+ rateLimitCounters.delete(k);
84
+ }
85
+ lastPruneAt = now;
86
+ }
87
+ let counter = rateLimitCounters.get(key);
88
+ if (!counter || counter.resetAt <= now) {
89
+ counter = { remaining: 1000, resetAt: now + 60 };
90
+ rateLimitCounters.set(key, counter);
91
+ }
92
+ counter.remaining = Math.max(0, counter.remaining - 1);
93
+ c.header('X-RateLimit-Limit', '1000');
94
+ c.header('X-RateLimit-Remaining', String(counter.remaining));
95
+ c.header('X-RateLimit-Reset', String(counter.resetAt));
96
+ if (counter.remaining === 0) {
97
+ c.header('Retry-After', String(counter.resetAt - now));
98
+ return c.json({
99
+ message: 'Too Many Requests',
100
+ code: 'rate_limit_exceeded',
101
+ }, 429);
102
+ }
103
+ await next();
104
+ });
105
+ // Store API key map for route access
106
+ store.setData('apiKeyMap', apiKeys);
107
+ // Register plugin routes
108
+ plugin.register({ app, store, jwt, baseUrl });
109
+ // Not found handler
110
+ app.notFound((c) => c.json({
111
+ message: 'Not Found',
112
+ code: 'not_found',
113
+ }, 404));
114
+ return { app, store, jwt, port, baseUrl };
115
+ }
116
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/emulate/core/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { Store } from './store.js';\nimport { JWTManager } from './jwt.js';\nimport { createApiErrorHandler, requestIdMiddleware } from './middleware/error-handler.js';\nimport { authMiddleware, type ApiKeyMap, type WorkOSAppEnv } from './middleware/auth.js';\nimport type { ServicePlugin } from './plugin.js';\n\nexport interface ServerOptions {\n port?: number;\n baseUrl?: string;\n apiKeys?: ApiKeyMap;\n}\n\nexport function createServer(plugin: ServicePlugin, options: ServerOptions = {}) {\n const port = options.port ?? 4100;\n const baseUrl = options.baseUrl ?? `http://localhost:${port}`;\n\n const app = new Hono<WorkOSAppEnv>();\n const store = new Store();\n const jwt = new JWTManager(baseUrl);\n\n const apiKeys: ApiKeyMap = options.apiKeys ?? {\n sk_test_default: { environment: 'test' },\n };\n\n app.onError(createApiErrorHandler());\n app.use('*', cors());\n app.use('*', requestIdMiddleware());\n\n // JWKS endpoint (public, no auth)\n app.get('/sso/jwks/:client_id', (c) => {\n return c.json(jwt.getJWKS());\n });\n\n // Auth middleware for API routes\n app.use('/api/*', authMiddleware(apiKeys));\n app.use('/user_management/*', async (c, next) => {\n const path = new URL(c.req.url).pathname;\n // Public endpoints (no auth required)\n if (\n path === '/user_management/authorize' ||\n path === '/user_management/authenticate' ||\n path === '/user_management/sessions/logout' ||\n path.startsWith('/user_management/sessions/jwks/')\n ) {\n return next();\n }\n return authMiddleware(apiKeys)(c, next);\n });\n app.use('/x/authkit/*', authMiddleware(apiKeys));\n app.use('/organizations', authMiddleware(apiKeys));\n app.use('/organizations/*', authMiddleware(apiKeys));\n app.use('/organization_memberships', authMiddleware(apiKeys));\n app.use('/organization_memberships/*', authMiddleware(apiKeys));\n app.use('/organization_domains', authMiddleware(apiKeys));\n app.use('/organization_domains/*', authMiddleware(apiKeys));\n app.use('/connections', authMiddleware(apiKeys));\n app.use('/connections/*', authMiddleware(apiKeys));\n app.use('/directories', authMiddleware(apiKeys));\n app.use('/directories/*', authMiddleware(apiKeys));\n app.use('/directory_groups', authMiddleware(apiKeys));\n app.use('/directory_groups/*', authMiddleware(apiKeys));\n app.use('/directory_users', authMiddleware(apiKeys));\n app.use('/directory_users/*', authMiddleware(apiKeys));\n app.use('/events', authMiddleware(apiKeys));\n app.use('/events/*', authMiddleware(apiKeys));\n app.use('/pipes/*', authMiddleware(apiKeys));\n app.use('/audit_logs/*', authMiddleware(apiKeys));\n app.use('/feature-flags', authMiddleware(apiKeys));\n app.use('/feature-flags/*', authMiddleware(apiKeys));\n app.use('/connect/*', authMiddleware(apiKeys));\n app.use('/data-integrations/*', async (c, next) => {\n const path = new URL(c.req.url).pathname;\n if (path.endsWith('/authorize')) return next();\n return authMiddleware(apiKeys)(c, next);\n });\n app.use('/radar/*', authMiddleware(apiKeys));\n app.use('/api_keys', authMiddleware(apiKeys));\n app.use('/api_keys/*', authMiddleware(apiKeys));\n app.use('/portal/*', authMiddleware(apiKeys));\n app.use('/webhook_endpoints', authMiddleware(apiKeys));\n app.use('/webhook_endpoints/*', authMiddleware(apiKeys));\n app.use('/auth/factors', authMiddleware(apiKeys));\n app.use('/auth/factors/*', authMiddleware(apiKeys));\n app.use('/auth/challenges/*', authMiddleware(apiKeys));\n\n // Rate limiting\n const rateLimitCounters = new Map<string, { remaining: number; resetAt: number }>();\n let lastPruneAt = Math.floor(Date.now() / 1000);\n\n app.use('*', async (c, next) => {\n const auth = c.get('auth');\n const key = auth?.apiKey ?? '__anonymous__';\n const now = Math.floor(Date.now() / 1000);\n\n if (now - lastPruneAt > 3600) {\n for (const [k, val] of rateLimitCounters) {\n if (val.resetAt <= now) rateLimitCounters.delete(k);\n }\n lastPruneAt = now;\n }\n\n let counter = rateLimitCounters.get(key);\n if (!counter || counter.resetAt <= now) {\n counter = { remaining: 1000, resetAt: now + 60 };\n rateLimitCounters.set(key, counter);\n }\n\n counter.remaining = Math.max(0, counter.remaining - 1);\n\n c.header('X-RateLimit-Limit', '1000');\n c.header('X-RateLimit-Remaining', String(counter.remaining));\n c.header('X-RateLimit-Reset', String(counter.resetAt));\n\n if (counter.remaining === 0) {\n c.header('Retry-After', String(counter.resetAt - now));\n return c.json(\n {\n message: 'Too Many Requests',\n code: 'rate_limit_exceeded',\n },\n 429,\n );\n }\n\n await next();\n });\n\n // Store API key map for route access\n store.setData('apiKeyMap', apiKeys);\n\n // Register plugin routes\n plugin.register({ app, store, jwt, baseUrl });\n\n // Not found handler\n app.notFound((c) =>\n c.json(\n {\n message: 'Not Found',\n code: 'not_found',\n },\n 404,\n ),\n );\n\n return { app, store, jwt, port, baseUrl };\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import { type Entity, type CursorPaginationOptions, type CursorPaginatedResult } from './pagination.js';
2
+ export type { Entity };
3
+ export type InsertInput<T extends Entity> = Omit<T, 'id' | 'created_at' | 'updated_at'> & {
4
+ id?: string;
5
+ };
6
+ export type FilterFn<T> = (item: T) => boolean;
7
+ export type SortFn<T> = (a: T, b: T) => number;
8
+ export interface CollectionHooks<T extends Entity> {
9
+ onInsert?: (item: T) => void;
10
+ onUpdate?: (item: T) => void;
11
+ onDelete?: (item: T) => void;
12
+ }
13
+ export declare class Collection<T extends Entity> {
14
+ private prefix;
15
+ private indexFields;
16
+ private items;
17
+ private indexes;
18
+ private hooks;
19
+ readonly fieldNames: string[];
20
+ constructor(prefix: string, indexFields?: (keyof T)[]);
21
+ private addToIndex;
22
+ private removeFromIndex;
23
+ insert(data: InsertInput<T>): T;
24
+ get(id: string): T | undefined;
25
+ findBy(field: keyof T, value: string | number): T[];
26
+ findOneBy(field: keyof T, value: string | number): T | undefined;
27
+ update(id: string, data: Partial<T>): T | undefined;
28
+ delete(id: string): boolean;
29
+ setHooks(hooks: CollectionHooks<T>): void;
30
+ all(): T[];
31
+ list(options?: CursorPaginationOptions<T>): CursorPaginatedResult<T>;
32
+ count(filter?: FilterFn<T>): number;
33
+ clear(): void;
34
+ }
35
+ export declare class Store {
36
+ private collections;
37
+ private _data;
38
+ collection<T extends Entity>(name: string, prefix: string, indexFields?: (keyof T)[]): Collection<T>;
39
+ getData<V>(key: string): V | undefined;
40
+ setData<V>(key: string, value: V): void;
41
+ reset(): void;
42
+ }