organify-auth-sdk 0.2.3 → 0.2.5

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.
@@ -34,6 +34,7 @@ var __decorateClass = (decorators, target, key, kind) => {
34
34
  if (kind && result) __defProp(target, key, result);
35
35
  return result;
36
36
  };
37
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
37
38
  function verifyToken(token, options) {
38
39
  return jwt.verify(token, options.secret, {
39
40
  ignoreExpiration: options.ignoreExpiration
@@ -153,6 +154,6 @@ var ServiceClientError = class extends Error {
153
154
  }
154
155
  };
155
156
 
156
- export { MSGPACK_MIME, ServiceClient, ServiceClientError, __commonJS, __decorateClass, __toESM, decodeToken, extractBearerToken, extractCookieToken, hasPermission, validateServiceToken, verifyToken };
157
- //# sourceMappingURL=chunk-M5JNBLJQ.js.map
158
- //# sourceMappingURL=chunk-M5JNBLJQ.js.map
157
+ export { MSGPACK_MIME, ServiceClient, ServiceClientError, __commonJS, __decorateClass, __decorateParam, __toESM, decodeToken, extractBearerToken, extractCookieToken, hasPermission, validateServiceToken, verifyToken };
158
+ //# sourceMappingURL=chunk-OSMC4Q72.js.map
159
+ //# sourceMappingURL=chunk-OSMC4Q72.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/jwt.ts","../src/service-client.ts"],"names":[],"mappings":"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","file":"chunk-OSMC4Q72.js","sourcesContent":["// ─────────────────────────────────────────────\n// @organify/auth-sdk — JWT verification helpers\n// ─────────────────────────────────────────────\n\nimport jwt from 'jsonwebtoken';\nimport type { JwtPayload as OrganifyJwtPayload } from './types';\n\nexport interface VerifyOptions {\n secret: string;\n /** When true, expired tokens won't throw */\n ignoreExpiration?: boolean;\n}\n\n/**\n * Verify and decode a JWT token.\n * @throws Error if token is invalid or expired\n */\nexport function verifyToken(\n token: string,\n options: VerifyOptions,\n): OrganifyJwtPayload {\n return jwt.verify(token, options.secret, {\n ignoreExpiration: options.ignoreExpiration,\n }) as unknown as OrganifyJwtPayload;\n}\n\n/**\n * Decode a JWT without verifying (useful for debugging).\n */\nexport function decodeToken(token: string): OrganifyJwtPayload | null {\n return jwt.decode(token) as OrganifyJwtPayload | null;\n}\n\n/**\n * Extract Bearer token from Authorization header.\n */\nexport function extractBearerToken(\n authHeader: string | undefined,\n): string | null {\n if (!authHeader?.startsWith('Bearer ')) return null;\n return authHeader.substring(7);\n}\n\n/**\n * Extract a token from a cookie header string.\n */\nexport function extractCookieToken(\n cookieHeader: string | undefined,\n cookieName = 'auth_token',\n): string | null {\n if (!cookieHeader) return null;\n const match = cookieHeader\n .split(';')\n .map((s) => s.trim())\n .find((s) => s.startsWith(`${cookieName}=`));\n if (!match) return null;\n return decodeURIComponent(match.split('=')[1]);\n}\n\n/**\n * Check if a user has a specific permission based on their role.\n */\nexport function hasPermission(\n role: string,\n permission: string,\n rolePermissions: Record<string, string[]>,\n): boolean {\n const perms = rolePermissions[role];\n if (!perms) return false;\n return perms.includes(permission);\n}\n\n/**\n * Validate a service-to-service token.\n */\nexport function validateServiceToken(\n token: string | undefined,\n expectedToken: string,\n): boolean {\n if (!token) return false;\n return token === expectedToken;\n}\n","// ─────────────────────────────────────────────\n// ServiceClient — Inter-Service HTTP Client with MessagePack\n// ─────────────────────────────────────────────\n// All service-to-service communication uses MessagePack for\n// serialization/deserialization. This client:\n//\n// 1. Sends request bodies as MessagePack (Content-Type: application/x-msgpack)\n// 2. Requests MessagePack responses (Accept: application/x-msgpack)\n// 3. Injects X-Service-Token for authentication\n// 4. Automatically decodes MessagePack responses\n// 5. Falls back to JSON when MessagePack is not available\n//\n// Usage:\n// const client = new ServiceClient({\n// serviceToken: 'shared-secret',\n// });\n// const users = await client.get<User[]>('http://users:4001/api/internal/users/batch');\n// const workspace = await client.post('http://workspaces:4002/api/internal/workspaces/personal', { userId: '1', userName: 'John' });\n// ─────────────────────────────────────────────\n\nimport { encode, decode } from '@msgpack/msgpack';\n\nexport const MSGPACK_MIME = 'application/x-msgpack';\n\nexport interface ServiceClientConfig {\n /** Shared service-to-service token (SERVICE_TO_SERVICE_TOKEN) */\n serviceToken: string;\n /** Default timeout in ms (default: 10000) */\n timeout?: number;\n /** Additional default headers */\n headers?: Record<string, string>;\n}\n\nexport interface ServiceRequestOptions {\n /** Override timeout for this request */\n timeout?: number;\n /** Additional headers for this request */\n headers?: Record<string, string>;\n /** Override user ID to forward downstream */\n userId?: string;\n}\n\nexport interface ServiceResponse<T = any> {\n data: T;\n status: number;\n headers: Record<string, string>;\n}\n\nexport class ServiceClient {\n private config: Required<Pick<ServiceClientConfig, 'serviceToken' | 'timeout'>> & {\n headers: Record<string, string>;\n };\n\n constructor(config: ServiceClientConfig) {\n this.config = {\n serviceToken: config.serviceToken,\n timeout: config.timeout ?? 10_000,\n headers: config.headers ?? {},\n };\n }\n\n // ─── HTTP Methods ─────────────────────────\n\n async get<T = any>(url: string, opts?: ServiceRequestOptions): Promise<ServiceResponse<T>> {\n return this.request<T>('GET', url, undefined, opts);\n }\n\n async post<T = any>(url: string, body?: any, opts?: ServiceRequestOptions): Promise<ServiceResponse<T>> {\n return this.request<T>('POST', url, body, opts);\n }\n\n async put<T = any>(url: string, body?: any, opts?: ServiceRequestOptions): Promise<ServiceResponse<T>> {\n return this.request<T>('PUT', url, body, opts);\n }\n\n async patch<T = any>(url: string, body?: any, opts?: ServiceRequestOptions): Promise<ServiceResponse<T>> {\n return this.request<T>('PATCH', url, body, opts);\n }\n\n async delete<T = any>(url: string, opts?: ServiceRequestOptions): Promise<ServiceResponse<T>> {\n return this.request<T>('DELETE', url, undefined, opts);\n }\n\n // ─── Core Request ─────────────────────────\n\n private async request<T>(\n method: string,\n url: string,\n body?: any,\n opts?: ServiceRequestOptions,\n ): Promise<ServiceResponse<T>> {\n const timeout = opts?.timeout ?? this.config.timeout;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n // Always use MessagePack for internal communication\n 'Accept': MSGPACK_MIME,\n 'X-Service-Token': this.config.serviceToken,\n ...this.config.headers,\n ...opts?.headers,\n };\n\n // Forward user identity if provided\n if (opts?.userId) {\n headers['x-user-id'] = opts.userId;\n }\n\n const fetchOpts: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n };\n\n // Encode body as MessagePack if present\n if (body !== undefined && body !== null) {\n const packed = encode(body);\n fetchOpts.body = Buffer.from(packed.buffer, packed.byteOffset, packed.byteLength);\n headers['Content-Type'] = MSGPACK_MIME;\n }\n\n const response = await fetch(url, fetchOpts);\n\n // Parse response based on Content-Type\n const contentType = response.headers.get('content-type') || '';\n let data: T;\n\n if (/msgpack/i.test(contentType)) {\n const buffer = await response.arrayBuffer();\n data = decode(new Uint8Array(buffer)) as T;\n } else {\n // Fallback to JSON\n const text = await response.text();\n try {\n data = JSON.parse(text) as T;\n } catch {\n data = text as unknown as T;\n }\n }\n\n // Collect response headers\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n if (!response.ok) {\n throw new ServiceClientError(\n `Service request failed: ${method} ${url} → ${response.status}`,\n response.status,\n data,\n );\n }\n\n return { data, status: response.status, headers: responseHeaders };\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n// ─── Error Class ────────────────────────────\n\nexport class ServiceClientError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly response: any,\n ) {\n super(message);\n this.name = 'ServiceClientError';\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { MSGPACK_MIME, ServiceClient, ServiceClientError, decodeToken, extractBearerToken, extractCookieToken, hasPermission, validateServiceToken, verifyToken } from './chunk-M5JNBLJQ.js';
1
+ export { MSGPACK_MIME, ServiceClient, ServiceClientError, decodeToken, extractBearerToken, extractCookieToken, hasPermission, validateServiceToken, verifyToken } from './chunk-OSMC4Q72.js';
2
2
 
3
3
  // src/types.ts
4
4
  var Permission = /* @__PURE__ */ ((Permission2) => {
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var common = require('@nestjs/common');
4
+ var core = require('@nestjs/core');
5
+ var config = require('@nestjs/config');
4
6
  var jwt = require('jsonwebtoken');
5
7
  var msgpack = require('@msgpack/msgpack');
6
- var config = require('@nestjs/config');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
@@ -41,6 +42,7 @@ var __decorateClass = (decorators, target, key, kind) => {
41
42
  result = (decorator(result)) || result;
42
43
  return result;
43
44
  };
45
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
44
46
 
45
47
  // ../../node_modules/rxjs/dist/cjs/internal/util/isFunction.js
46
48
  var require_isFunction = __commonJS({
@@ -7627,7 +7629,9 @@ exports.AuthGuard = class AuthGuard {
7627
7629
  }
7628
7630
  };
7629
7631
  exports.AuthGuard = __decorateClass([
7630
- common.Injectable()
7632
+ common.Injectable(),
7633
+ __decorateParam(0, common.Inject(core.Reflector)),
7634
+ __decorateParam(1, common.Inject(config.ConfigService))
7631
7635
  ], exports.AuthGuard);
7632
7636
  exports.ServiceAuthGuard = class ServiceAuthGuard {
7633
7637
  constructor(config) {
@@ -7648,7 +7652,8 @@ exports.ServiceAuthGuard = class ServiceAuthGuard {
7648
7652
  }
7649
7653
  };
7650
7654
  exports.ServiceAuthGuard = __decorateClass([
7651
- common.Injectable()
7655
+ common.Injectable(),
7656
+ __decorateParam(0, common.Inject(config.ConfigService))
7652
7657
  ], exports.ServiceAuthGuard);
7653
7658
  var ROLES_KEY = "roles";
7654
7659
  var Roles = (...roles) => common.SetMetadata(ROLES_KEY, roles);
@@ -7675,7 +7680,8 @@ exports.RolesGuard = class RolesGuard {
7675
7680
  }
7676
7681
  };
7677
7682
  exports.RolesGuard = __decorateClass([
7678
- common.Injectable()
7683
+ common.Injectable(),
7684
+ __decorateParam(0, common.Inject(core.Reflector))
7679
7685
  ], exports.RolesGuard);
7680
7686
  var CurrentUser = common.createParamDecorator(
7681
7687
  (_data, ctx) => {
@@ -7685,21 +7691,26 @@ var CurrentUser = common.createParamDecorator(
7685
7691
  var CurrentUserId = common.createParamDecorator(
7686
7692
  (_data, context) => {
7687
7693
  const contextType = context.getType();
7694
+ let userId;
7688
7695
  if (contextType === "graphql") {
7689
7696
  try {
7690
7697
  const gqlContext = context.getArgByIndex(2);
7691
7698
  if (gqlContext?.req?.headers?.["x-user-id"]) {
7692
- return gqlContext.req.headers["x-user-id"];
7699
+ userId = gqlContext.req.headers["x-user-id"];
7693
7700
  }
7694
7701
  } catch {
7695
7702
  }
7696
7703
  }
7697
7704
  try {
7698
7705
  const request = context.switchToHttp().getRequest();
7699
- return request?.headers?.["x-user-id"];
7706
+ userId = request?.headers?.["x-user-id"];
7700
7707
  } catch {
7701
- return void 0;
7708
+ userId = void 0;
7709
+ }
7710
+ if (!userId) {
7711
+ throw new common.UnauthorizedException("Missing x-user-id header");
7702
7712
  }
7713
+ return userId;
7703
7714
  }
7704
7715
  );
7705
7716
  var SecurityCtx = common.createParamDecorator(
@@ -7720,6 +7731,7 @@ exports.InternalMsgPackInterceptor = class InternalMsgPackInterceptor {
7720
7731
  return next.handle().pipe(
7721
7732
  (0, import_operators.map)((data) => {
7722
7733
  if (data === void 0 || data === null) return data;
7734
+ if (res.headersSent) return data;
7723
7735
  const packed = msgpack.encode(data);
7724
7736
  const buffer = Buffer.from(
7725
7737
  packed.buffer,
@@ -7727,9 +7739,7 @@ exports.InternalMsgPackInterceptor = class InternalMsgPackInterceptor {
7727
7739
  packed.byteLength
7728
7740
  );
7729
7741
  res.setHeader("Content-Type", MSGPACK_MIME);
7730
- res.setHeader("Content-Length", buffer.length.toString());
7731
- res.end(buffer);
7732
- return void 0;
7742
+ return new common.StreamableFile(buffer);
7733
7743
  })
7734
7744
  );
7735
7745
  }