@objectstack/core 7.9.0 → 8.0.0

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.
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ API_KEY_PREFIX: () => API_KEY_PREFIX,
33
34
  ApiRegistry: () => ApiRegistry,
34
35
  CORE_FALLBACK_FACTORIES: () => CORE_FALLBACK_FACTORIES,
35
36
  DependencyResolver: () => DependencyResolver,
@@ -63,11 +64,17 @@ __export(index_exports, {
63
64
  createMemoryQueue: () => createMemoryQueue,
64
65
  createPluginConfigValidator: () => createPluginConfigValidator,
65
66
  createPluginPermissionEnforcer: () => createPluginPermissionEnforcer,
67
+ extractApiKey: () => extractApiKey,
68
+ generateApiKey: () => generateApiKey,
66
69
  generateEd25519KeyPair: () => generateEd25519KeyPair,
67
70
  getEnv: () => getEnv,
68
71
  getMemoryUsage: () => getMemoryUsage,
72
+ hashApiKey: () => hashApiKey,
73
+ isExpired: () => isExpired,
69
74
  isNode: () => isNode,
75
+ parseScopes: () => parseScopes,
70
76
  parseSignature: () => parseSignature,
77
+ resolveApiKeyPrincipal: () => resolveApiKeyPrincipal,
71
78
  resolveLocale: () => resolveLocale,
72
79
  safeExit: () => safeExit,
73
80
  signPayload: () => signPayload,
@@ -3946,6 +3953,109 @@ var PluginSecurityScanner = class {
3946
3953
  }
3947
3954
  };
3948
3955
 
3956
+ // src/security/api-key.ts
3957
+ var import_node_crypto2 = require("crypto");
3958
+ var API_KEY_PREFIX = "osk_";
3959
+ var API_KEY_ENTROPY_BYTES = 32;
3960
+ var VISIBLE_PREFIX_LEN = 12;
3961
+ function hashApiKey(raw) {
3962
+ return (0, import_node_crypto2.createHash)("sha256").update(raw, "utf8").digest("hex");
3963
+ }
3964
+ function generateApiKey(prefix = API_KEY_PREFIX) {
3965
+ const secret = (0, import_node_crypto2.randomBytes)(API_KEY_ENTROPY_BYTES).toString("base64url");
3966
+ const raw = `${prefix}${secret}`;
3967
+ return {
3968
+ raw,
3969
+ hash: hashApiKey(raw),
3970
+ prefix: raw.slice(0, VISIBLE_PREFIX_LEN)
3971
+ };
3972
+ }
3973
+ function extractApiKey(headers) {
3974
+ const x = readHeader(headers, "x-api-key");
3975
+ if (x && x.trim()) return x.trim();
3976
+ const auth = readHeader(headers, "authorization");
3977
+ if (!auth) return void 0;
3978
+ const m = auth.match(/^ApiKey\s+(.+)$/i);
3979
+ const token = m?.[1]?.trim();
3980
+ return token || void 0;
3981
+ }
3982
+ function parseScopes(value) {
3983
+ if (Array.isArray(value)) {
3984
+ return value.filter((s) => typeof s === "string" && s.length > 0);
3985
+ }
3986
+ if (typeof value === "string" && value.trim()) {
3987
+ const parsed = safeJsonParse(value, []);
3988
+ if (Array.isArray(parsed)) {
3989
+ return parsed.filter((s) => typeof s === "string" && s.length > 0);
3990
+ }
3991
+ }
3992
+ return [];
3993
+ }
3994
+ function isExpired(value, nowMs) {
3995
+ if (value == null) return false;
3996
+ let ms;
3997
+ if (typeof value === "number") {
3998
+ ms = value < 1e12 ? value * 1e3 : value;
3999
+ } else if (value instanceof Date) {
4000
+ ms = value.getTime();
4001
+ } else if (typeof value === "string") {
4002
+ ms = Date.parse(value);
4003
+ } else {
4004
+ return false;
4005
+ }
4006
+ if (Number.isNaN(ms)) return false;
4007
+ return ms <= nowMs;
4008
+ }
4009
+ async function resolveApiKeyPrincipal(ql, headers, nowMs = Date.now()) {
4010
+ const apiKey = extractApiKey(headers);
4011
+ if (!apiKey) return void 0;
4012
+ if (!ql || typeof ql.find !== "function") return void 0;
4013
+ let rows;
4014
+ try {
4015
+ rows = await ql.find("sys_api_key", {
4016
+ where: { key: hashApiKey(apiKey), revoked: false },
4017
+ limit: 1,
4018
+ context: { isSystem: true }
4019
+ });
4020
+ } catch {
4021
+ return void 0;
4022
+ }
4023
+ if (rows && rows.value) rows = rows.value;
4024
+ const row = Array.isArray(rows) ? rows[0] : void 0;
4025
+ if (!row || row.revoked === true) return void 0;
4026
+ const expiresAt = row.expires_at ?? row.expiresAt;
4027
+ if (isExpired(expiresAt, nowMs)) return void 0;
4028
+ const userId = row.user_id ?? row.userId;
4029
+ if (!userId || typeof userId !== "string") return void 0;
4030
+ return {
4031
+ userId,
4032
+ tenantId: row.organization_id ?? row.organizationId ?? void 0,
4033
+ scopes: parseScopes(row.scopes)
4034
+ };
4035
+ }
4036
+ function readHeader(headers, name) {
4037
+ if (!headers) return void 0;
4038
+ const lower = name.toLowerCase();
4039
+ if (typeof headers.get === "function") {
4040
+ const v = headers.get(name) ?? headers.get(lower);
4041
+ return v == null ? void 0 : String(v);
4042
+ }
4043
+ for (const key of Object.keys(headers)) {
4044
+ if (key.toLowerCase() === lower) {
4045
+ const v = headers[key];
4046
+ return Array.isArray(v) ? v[0] : v == null ? void 0 : String(v);
4047
+ }
4048
+ }
4049
+ return void 0;
4050
+ }
4051
+ function safeJsonParse(s, fallback) {
4052
+ try {
4053
+ return JSON.parse(s);
4054
+ } catch {
4055
+ return fallback;
4056
+ }
4057
+ }
4058
+
3949
4059
  // src/health-monitor.ts
3950
4060
  var PluginHealthMonitor = class {
3951
4061
  constructor(logger) {
@@ -4189,7 +4299,7 @@ var PluginHealthMonitor = class {
4189
4299
  };
4190
4300
 
4191
4301
  // src/hot-reload.ts
4192
- var import_node_crypto2 = require("crypto");
4302
+ var import_node_crypto3 = require("crypto");
4193
4303
  var generateUUID = () => {
4194
4304
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
4195
4305
  return crypto.randomUUID();
@@ -4284,7 +4394,7 @@ var PluginStateManager = class {
4284
4394
  */
4285
4395
  calculateChecksum(state) {
4286
4396
  const stateStr = JSON.stringify(state);
4287
- return (0, import_node_crypto2.createHash)("sha256").update(stateStr).digest("hex");
4397
+ return (0, import_node_crypto3.createHash)("sha256").update(stateStr).digest("hex");
4288
4398
  }
4289
4399
  /**
4290
4400
  * Shutdown state manager
@@ -4861,6 +4971,7 @@ var NamespaceResolver = class {
4861
4971
  };
4862
4972
  // Annotate the CommonJS export names for ESM import in node:
4863
4973
  0 && (module.exports = {
4974
+ API_KEY_PREFIX,
4864
4975
  ApiRegistry,
4865
4976
  CORE_FALLBACK_FACTORIES,
4866
4977
  DependencyResolver,
@@ -4894,11 +5005,17 @@ var NamespaceResolver = class {
4894
5005
  createMemoryQueue,
4895
5006
  createPluginConfigValidator,
4896
5007
  createPluginPermissionEnforcer,
5008
+ extractApiKey,
5009
+ generateApiKey,
4897
5010
  generateEd25519KeyPair,
4898
5011
  getEnv,
4899
5012
  getMemoryUsage,
5013
+ hashApiKey,
5014
+ isExpired,
4900
5015
  isNode,
5016
+ parseScopes,
4901
5017
  parseSignature,
5018
+ resolveApiKeyPrincipal,
4902
5019
  resolveLocale,
4903
5020
  safeExit,
4904
5021
  signPayload,