@objectstack/core 14.8.0 → 15.1.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,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ANONYMOUS_DENY_BODY: () => ANONYMOUS_DENY_BODY,
34
+ ANONYMOUS_DENY_CODE: () => ANONYMOUS_DENY_CODE,
35
+ ANONYMOUS_DENY_MESSAGE: () => ANONYMOUS_DENY_MESSAGE,
36
+ ANONYMOUS_DENY_STATUS: () => ANONYMOUS_DENY_STATUS,
33
37
  API_KEY_PREFIX: () => API_KEY_PREFIX,
34
38
  ApiRegistry: () => ApiRegistry,
35
39
  CORE_FALLBACK_FACTORIES: () => CORE_FALLBACK_FACTORIES,
@@ -40,6 +44,9 @@ __export(index_exports, {
40
44
  ObjectKernel: () => ObjectKernel,
41
45
  ObjectKernelBase: () => ObjectKernelBase,
42
46
  ObjectLogger: () => ObjectLogger,
47
+ POSTURE_INJECTION_RULE: () => POSTURE_INJECTION_RULE,
48
+ POSTURE_LADDER: () => POSTURE_LADDER,
49
+ POSTURE_RANK: () => POSTURE_RANK,
43
50
  PluginConfigValidator: () => PluginConfigValidator,
44
51
  PluginHealthMonitor: () => PluginHealthMonitor,
45
52
  PluginLoader: () => PluginLoader,
@@ -69,6 +76,7 @@ __export(index_exports, {
69
76
  createPluginPermissionEnforcer: () => createPluginPermissionEnforcer,
70
77
  deepMerge: () => deepMerge,
71
78
  defaultIsTransientError: () => defaultIsTransientError,
79
+ derivePosture: () => derivePosture,
72
80
  evaluateAuthGate: () => evaluateAuthGate,
73
81
  extractApiKey: () => extractApiKey,
74
82
  generateApiKey: () => generateApiKey,
@@ -83,12 +91,14 @@ __export(index_exports, {
83
91
  isNode: () => isNode,
84
92
  parseScopes: () => parseScopes,
85
93
  parseSignature: () => parseSignature,
94
+ postureVisibleRows: () => postureVisibleRows,
86
95
  readAuthoredTranslationLayer: () => readAuthoredTranslationLayer,
87
96
  resolveApiKeyPrincipal: () => resolveApiKeyPrincipal,
88
97
  resolveAuthzContext: () => resolveAuthzContext,
89
98
  resolveLocale: () => resolveLocale,
90
99
  resolveLocalizationContext: () => resolveLocalizationContext,
91
100
  safeExit: () => safeExit,
101
+ shouldDenyAnonymous: () => shouldDenyAnonymous,
92
102
  signPayload: () => signPayload,
93
103
  verifyPayload: () => verifyPayload,
94
104
  verifyPlatformSignature: () => verifyPlatformSignature,
@@ -1637,6 +1647,8 @@ var ObjectKernel = class {
1637
1647
  this.validateSystemRequirements();
1638
1648
  this.logger.debug("Triggering kernel:ready hook");
1639
1649
  await this.context.trigger("kernel:ready");
1650
+ this.logger.debug("Triggering kernel:bootstrapped hook");
1651
+ await this.context.trigger("kernel:bootstrapped");
1640
1652
  this.logger.debug("Triggering kernel:listening hook");
1641
1653
  await this.context.trigger("kernel:listening");
1642
1654
  this.logger.info("\u2705 Bootstrap complete");
@@ -1920,6 +1932,7 @@ var LiteKernel = class extends ObjectKernelBase {
1920
1932
  await this.runPluginStart(plugin);
1921
1933
  }
1922
1934
  await this.triggerHook("kernel:ready");
1935
+ await this.triggerHook("kernel:bootstrapped");
1923
1936
  await this.triggerHook("kernel:listening");
1924
1937
  this.logger.info("\u2705 Bootstrap complete", {
1925
1938
  pluginCount: this.plugins.size
@@ -4243,6 +4256,62 @@ function isGrantExpired(row, nowMs) {
4243
4256
  return !(nowMs < until);
4244
4257
  }
4245
4258
 
4259
+ // src/security/posture-ladder.ts
4260
+ var POSTURE_LADDER = [
4261
+ "PLATFORM_ADMIN",
4262
+ "TENANT_ADMIN",
4263
+ "MEMBER",
4264
+ "EXTERNAL"
4265
+ ];
4266
+ var POSTURE_RANK = {
4267
+ PLATFORM_ADMIN: 3,
4268
+ TENANT_ADMIN: 2,
4269
+ MEMBER: 1,
4270
+ EXTERNAL: 0
4271
+ };
4272
+ var POSTURE_INJECTION_RULE = {
4273
+ PLATFORM_ADMIN: "Layer 0 exemption where the object posture permits (private / platform-global / better-auth-managed) \u2014 crosses the tenant wall; org-scoped like TENANT_ADMIN on ordinary tenant business objects.",
4274
+ TENANT_ADMIN: "All rows within the active organization (organization_id == ctx.tenantId); no ownership / depth / sharing narrowing.",
4275
+ MEMBER: "Business RLS within the organization \u2014 ownership (owner / unit depth), the OWD baseline, and explicit sharing.",
4276
+ EXTERNAL: "Explicitly shared rows ONLY \u2014 OWD baselines and sharing rules never apply; a misconfiguration can only shrink visibility, never widen it."
4277
+ };
4278
+ function derivePosture(evidence) {
4279
+ if (evidence.isPlatformAdmin) return "PLATFORM_ADMIN";
4280
+ if (evidence.isTenantAdmin) return "TENANT_ADMIN";
4281
+ return "MEMBER";
4282
+ }
4283
+ function isSharedTo(row, userId) {
4284
+ return (row.sharedTo ?? []).includes(userId);
4285
+ }
4286
+ function externalVisible(rows, p) {
4287
+ return rows.filter((r) => isSharedTo(r, p.userId));
4288
+ }
4289
+ function memberVisible(rows, p) {
4290
+ const shared = new Set(externalVisible(rows, p));
4291
+ return rows.filter(
4292
+ (r) => shared.has(r) || r.organization_id === p.organizationId && (r.owner_id === p.userId || r.owdVisible === true)
4293
+ );
4294
+ }
4295
+ function tenantAdminVisible(rows, p) {
4296
+ const member = new Set(memberVisible(rows, p));
4297
+ return rows.filter((r) => member.has(r) || r.organization_id === p.organizationId);
4298
+ }
4299
+ function platformAdminVisible(rows) {
4300
+ return [...rows];
4301
+ }
4302
+ function postureVisibleRows(posture, rows, principal) {
4303
+ switch (posture) {
4304
+ case "PLATFORM_ADMIN":
4305
+ return platformAdminVisible(rows);
4306
+ case "TENANT_ADMIN":
4307
+ return tenantAdminVisible(rows, principal);
4308
+ case "MEMBER":
4309
+ return memberVisible(rows, principal);
4310
+ case "EXTERNAL":
4311
+ return externalVisible(rows, principal);
4312
+ }
4313
+ }
4314
+
4246
4315
  // src/security/resolve-authz-context.ts
4247
4316
  function safeJsonParse2(s, fallback) {
4248
4317
  try {
@@ -4389,6 +4458,10 @@ async function resolveAuthzContext(input) {
4389
4458
  if (hasPlatformAdminGrant && !ctx.positions.includes(import_spec.BUILTIN_IDENTITY_PLATFORM_ADMIN)) {
4390
4459
  ctx.positions.unshift(import_spec.BUILTIN_IDENTITY_PLATFORM_ADMIN);
4391
4460
  }
4461
+ ctx.posture = derivePosture({
4462
+ isPlatformAdmin: hasPlatformAdminGrant,
4463
+ isTenantAdmin: ctx.permissions.includes(import_spec.ORGANIZATION_ADMIN)
4464
+ });
4392
4465
  if (!ctx.permissions.includes("ai_seat")) {
4393
4466
  const aiAccess = (await getUserRow())?.ai_access;
4394
4467
  if (aiAccess === true || aiAccess === 1 || aiAccess === "1") ctx.permissions.push("ai_seat");
@@ -4474,6 +4547,26 @@ function evaluateAuthGate(sessionUser, path) {
4474
4547
  };
4475
4548
  }
4476
4549
 
4550
+ // src/security/anonymous-deny.ts
4551
+ var ANONYMOUS_DENY_STATUS = 401;
4552
+ var ANONYMOUS_DENY_CODE = "unauthenticated";
4553
+ var ANONYMOUS_DENY_MESSAGE = "Authentication is required to access this endpoint.";
4554
+ var ANONYMOUS_DENY_BODY = {
4555
+ error: ANONYMOUS_DENY_CODE,
4556
+ message: ANONYMOUS_DENY_MESSAGE
4557
+ };
4558
+ function shouldDenyAnonymous(input) {
4559
+ if (!input.requireAuth) return false;
4560
+ if (typeof input.method === "string" && input.method.toUpperCase() === "OPTIONS") {
4561
+ return false;
4562
+ }
4563
+ if (input.userId || input.isSystem) return false;
4564
+ if (typeof input.path === "string" && input.path.length > 0 && isAuthGateAllowlisted(input.path)) {
4565
+ return false;
4566
+ }
4567
+ return true;
4568
+ }
4569
+
4477
4570
  // src/utils/datetime.ts
4478
4571
  function calendarPartsInTz(d, tz) {
4479
4572
  const parts = new Intl.DateTimeFormat("en-US", {
@@ -5495,6 +5588,10 @@ var NamespaceResolver = class {
5495
5588
  };
5496
5589
  // Annotate the CommonJS export names for ESM import in node:
5497
5590
  0 && (module.exports = {
5591
+ ANONYMOUS_DENY_BODY,
5592
+ ANONYMOUS_DENY_CODE,
5593
+ ANONYMOUS_DENY_MESSAGE,
5594
+ ANONYMOUS_DENY_STATUS,
5498
5595
  API_KEY_PREFIX,
5499
5596
  ApiRegistry,
5500
5597
  CORE_FALLBACK_FACTORIES,
@@ -5505,6 +5602,9 @@ var NamespaceResolver = class {
5505
5602
  ObjectKernel,
5506
5603
  ObjectKernelBase,
5507
5604
  ObjectLogger,
5605
+ POSTURE_INJECTION_RULE,
5606
+ POSTURE_LADDER,
5607
+ POSTURE_RANK,
5508
5608
  PluginConfigValidator,
5509
5609
  PluginHealthMonitor,
5510
5610
  PluginLoader,
@@ -5534,6 +5634,7 @@ var NamespaceResolver = class {
5534
5634
  createPluginPermissionEnforcer,
5535
5635
  deepMerge,
5536
5636
  defaultIsTransientError,
5637
+ derivePosture,
5537
5638
  evaluateAuthGate,
5538
5639
  extractApiKey,
5539
5640
  generateApiKey,
@@ -5548,12 +5649,14 @@ var NamespaceResolver = class {
5548
5649
  isNode,
5549
5650
  parseScopes,
5550
5651
  parseSignature,
5652
+ postureVisibleRows,
5551
5653
  readAuthoredTranslationLayer,
5552
5654
  resolveApiKeyPrincipal,
5553
5655
  resolveAuthzContext,
5554
5656
  resolveLocale,
5555
5657
  resolveLocalizationContext,
5556
5658
  safeExit,
5659
+ shouldDenyAnonymous,
5557
5660
  signPayload,
5558
5661
  verifyPayload,
5559
5662
  verifyPlatformSignature,