@unifiedcommerce/core 0.0.4 → 0.1.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 (179) hide show
  1. package/dist/auth/auth-schema.d.ts +92 -0
  2. package/dist/auth/auth-schema.d.ts.map +1 -1
  3. package/dist/auth/auth-schema.js +7 -0
  4. package/dist/auth/setup.d.ts.map +1 -1
  5. package/dist/auth/setup.js +3 -1
  6. package/package.json +1 -2
  7. package/src/adapters/console-email.ts +0 -43
  8. package/src/auth/access.ts +0 -187
  9. package/src/auth/auth-schema.ts +0 -131
  10. package/src/auth/middleware.ts +0 -161
  11. package/src/auth/org.ts +0 -41
  12. package/src/auth/permissions.ts +0 -28
  13. package/src/auth/setup.ts +0 -165
  14. package/src/auth/system-actor.ts +0 -19
  15. package/src/auth/types.ts +0 -10
  16. package/src/config/defaults.ts +0 -82
  17. package/src/config/define-config.ts +0 -53
  18. package/src/config/types.ts +0 -299
  19. package/src/generated/plugin-capabilities.d.ts +0 -20
  20. package/src/generated/plugin-manifest.ts +0 -23
  21. package/src/generated/plugin-repositories.d.ts +0 -20
  22. package/src/hooks/checkout-completion.ts +0 -262
  23. package/src/hooks/checkout.ts +0 -677
  24. package/src/hooks/order-emails.ts +0 -62
  25. package/src/index.ts +0 -214
  26. package/src/interfaces/mcp/agent-prompt.ts +0 -174
  27. package/src/interfaces/mcp/context-enrichment.ts +0 -177
  28. package/src/interfaces/mcp/server.ts +0 -617
  29. package/src/interfaces/mcp/transport.ts +0 -68
  30. package/src/interfaces/rest/customer-portal.ts +0 -299
  31. package/src/interfaces/rest/index.ts +0 -74
  32. package/src/interfaces/rest/router.ts +0 -334
  33. package/src/interfaces/rest/routes/admin-jobs.ts +0 -58
  34. package/src/interfaces/rest/routes/audit.ts +0 -50
  35. package/src/interfaces/rest/routes/carts.ts +0 -89
  36. package/src/interfaces/rest/routes/catalog.ts +0 -493
  37. package/src/interfaces/rest/routes/checkout.ts +0 -283
  38. package/src/interfaces/rest/routes/inventory.ts +0 -70
  39. package/src/interfaces/rest/routes/media.ts +0 -86
  40. package/src/interfaces/rest/routes/orders.ts +0 -78
  41. package/src/interfaces/rest/routes/payments.ts +0 -60
  42. package/src/interfaces/rest/routes/pricing.ts +0 -57
  43. package/src/interfaces/rest/routes/promotions.ts +0 -92
  44. package/src/interfaces/rest/routes/search.ts +0 -71
  45. package/src/interfaces/rest/routes/webhooks.ts +0 -46
  46. package/src/interfaces/rest/schemas/admin-jobs.ts +0 -40
  47. package/src/interfaces/rest/schemas/audit.ts +0 -46
  48. package/src/interfaces/rest/schemas/carts.ts +0 -125
  49. package/src/interfaces/rest/schemas/catalog.ts +0 -450
  50. package/src/interfaces/rest/schemas/checkout.ts +0 -66
  51. package/src/interfaces/rest/schemas/customer-portal.ts +0 -195
  52. package/src/interfaces/rest/schemas/inventory.ts +0 -138
  53. package/src/interfaces/rest/schemas/media.ts +0 -75
  54. package/src/interfaces/rest/schemas/orders.ts +0 -104
  55. package/src/interfaces/rest/schemas/pricing.ts +0 -80
  56. package/src/interfaces/rest/schemas/promotions.ts +0 -110
  57. package/src/interfaces/rest/schemas/responses.ts +0 -85
  58. package/src/interfaces/rest/schemas/search.ts +0 -58
  59. package/src/interfaces/rest/schemas/shared.ts +0 -62
  60. package/src/interfaces/rest/schemas/webhooks.ts +0 -68
  61. package/src/interfaces/rest/utils.ts +0 -104
  62. package/src/interfaces/rest/webhook-router.ts +0 -50
  63. package/src/kernel/compensation/executor.ts +0 -61
  64. package/src/kernel/compensation/types.ts +0 -26
  65. package/src/kernel/database/adapter.ts +0 -13
  66. package/src/kernel/database/drizzle-db.ts +0 -56
  67. package/src/kernel/database/migrate.ts +0 -76
  68. package/src/kernel/database/plugin-types.ts +0 -34
  69. package/src/kernel/database/schema.ts +0 -49
  70. package/src/kernel/database/scoped-db.ts +0 -68
  71. package/src/kernel/database/tx-context.ts +0 -46
  72. package/src/kernel/error-mapper.ts +0 -15
  73. package/src/kernel/errors.ts +0 -89
  74. package/src/kernel/factory/repository-factory.ts +0 -242
  75. package/src/kernel/hooks/create-context.ts +0 -43
  76. package/src/kernel/hooks/executor.ts +0 -88
  77. package/src/kernel/hooks/registry.ts +0 -74
  78. package/src/kernel/hooks/types.ts +0 -52
  79. package/src/kernel/http-error.ts +0 -44
  80. package/src/kernel/jobs/adapter.ts +0 -36
  81. package/src/kernel/jobs/drizzle-adapter.ts +0 -58
  82. package/src/kernel/jobs/runner.ts +0 -153
  83. package/src/kernel/jobs/schema.ts +0 -46
  84. package/src/kernel/jobs/types.ts +0 -30
  85. package/src/kernel/local-api.ts +0 -185
  86. package/src/kernel/plugin/manifest.ts +0 -253
  87. package/src/kernel/query/executor.ts +0 -184
  88. package/src/kernel/query/registry.ts +0 -46
  89. package/src/kernel/result.ts +0 -33
  90. package/src/kernel/schema/extra-columns.ts +0 -37
  91. package/src/kernel/service-registry.ts +0 -76
  92. package/src/kernel/service-timing.ts +0 -89
  93. package/src/kernel/state-machine/machine.ts +0 -101
  94. package/src/modules/analytics/drizzle-adapter.ts +0 -426
  95. package/src/modules/analytics/hooks.ts +0 -11
  96. package/src/modules/analytics/models.ts +0 -125
  97. package/src/modules/analytics/repository/index.ts +0 -6
  98. package/src/modules/analytics/service.ts +0 -245
  99. package/src/modules/analytics/types.ts +0 -180
  100. package/src/modules/audit/hooks.ts +0 -78
  101. package/src/modules/audit/schema.ts +0 -33
  102. package/src/modules/audit/service.ts +0 -151
  103. package/src/modules/cart/access.ts +0 -27
  104. package/src/modules/cart/matcher.ts +0 -26
  105. package/src/modules/cart/repository/index.ts +0 -234
  106. package/src/modules/cart/schema.ts +0 -42
  107. package/src/modules/cart/schemas.ts +0 -38
  108. package/src/modules/cart/service.ts +0 -541
  109. package/src/modules/catalog/repository/index.ts +0 -772
  110. package/src/modules/catalog/schema.ts +0 -203
  111. package/src/modules/catalog/schemas.ts +0 -104
  112. package/src/modules/catalog/service.ts +0 -1544
  113. package/src/modules/customers/repository/index.ts +0 -327
  114. package/src/modules/customers/schema.ts +0 -64
  115. package/src/modules/customers/service.ts +0 -171
  116. package/src/modules/fulfillment/repository/index.ts +0 -426
  117. package/src/modules/fulfillment/schema.ts +0 -101
  118. package/src/modules/fulfillment/service.ts +0 -555
  119. package/src/modules/fulfillment/types.ts +0 -59
  120. package/src/modules/inventory/repository/index.ts +0 -509
  121. package/src/modules/inventory/schema.ts +0 -94
  122. package/src/modules/inventory/schemas.ts +0 -38
  123. package/src/modules/inventory/service.ts +0 -490
  124. package/src/modules/media/adapter.ts +0 -17
  125. package/src/modules/media/repository/index.ts +0 -274
  126. package/src/modules/media/schema.ts +0 -41
  127. package/src/modules/media/service.ts +0 -151
  128. package/src/modules/orders/repository/index.ts +0 -287
  129. package/src/modules/orders/schema.ts +0 -66
  130. package/src/modules/orders/service.ts +0 -619
  131. package/src/modules/orders/stale-order-cleanup.ts +0 -76
  132. package/src/modules/organization/service.ts +0 -191
  133. package/src/modules/payments/adapter.ts +0 -47
  134. package/src/modules/payments/repository/index.ts +0 -6
  135. package/src/modules/payments/service.ts +0 -107
  136. package/src/modules/pricing/repository/index.ts +0 -291
  137. package/src/modules/pricing/schema.ts +0 -71
  138. package/src/modules/pricing/schemas.ts +0 -38
  139. package/src/modules/pricing/service.ts +0 -494
  140. package/src/modules/promotions/repository/index.ts +0 -325
  141. package/src/modules/promotions/schema.ts +0 -62
  142. package/src/modules/promotions/schemas.ts +0 -38
  143. package/src/modules/promotions/service.ts +0 -598
  144. package/src/modules/search/adapter.ts +0 -57
  145. package/src/modules/search/hooks.ts +0 -12
  146. package/src/modules/search/repository/index.ts +0 -6
  147. package/src/modules/search/service.ts +0 -315
  148. package/src/modules/shipping/calculator.ts +0 -188
  149. package/src/modules/shipping/repository/index.ts +0 -6
  150. package/src/modules/shipping/service.ts +0 -51
  151. package/src/modules/tax/adapter.ts +0 -60
  152. package/src/modules/tax/repository/index.ts +0 -6
  153. package/src/modules/tax/service.ts +0 -53
  154. package/src/modules/webhooks/hook.ts +0 -34
  155. package/src/modules/webhooks/repository/index.ts +0 -278
  156. package/src/modules/webhooks/schema.ts +0 -56
  157. package/src/modules/webhooks/service.ts +0 -117
  158. package/src/modules/webhooks/signing.ts +0 -6
  159. package/src/modules/webhooks/ssrf-guard.ts +0 -71
  160. package/src/modules/webhooks/tasks.ts +0 -52
  161. package/src/modules/webhooks/worker.ts +0 -134
  162. package/src/runtime/commerce.ts +0 -145
  163. package/src/runtime/kernel.ts +0 -419
  164. package/src/runtime/logger.ts +0 -36
  165. package/src/runtime/server.ts +0 -349
  166. package/src/runtime/shutdown.ts +0 -43
  167. package/src/test-utils/create-pglite-adapter.ts +0 -129
  168. package/src/test-utils/create-plugin-test-app.ts +0 -128
  169. package/src/test-utils/create-repository-test-harness.ts +0 -16
  170. package/src/test-utils/create-test-config.ts +0 -190
  171. package/src/test-utils/create-test-kernel.ts +0 -7
  172. package/src/test-utils/create-test-plugin-context.ts +0 -75
  173. package/src/test-utils/rest-api-test-utils.ts +0 -265
  174. package/src/test-utils/test-actors.ts +0 -62
  175. package/src/test-utils/typed-hooks.ts +0 -54
  176. package/src/types/commerce-types.ts +0 -34
  177. package/src/utils/id.ts +0 -3
  178. package/src/utils/logger.ts +0 -18
  179. package/src/utils/pagination.ts +0 -22
@@ -1380,4 +1380,96 @@ export declare const apikey: import("drizzle-orm/pg-core").PgTableWithColumns<{
1380
1380
  };
1381
1381
  dialect: "pg";
1382
1382
  }>;
1383
+ export declare const jwks: import("drizzle-orm/pg-core").PgTableWithColumns<{
1384
+ name: "jwks";
1385
+ schema: undefined;
1386
+ columns: {
1387
+ id: import("drizzle-orm/pg-core").PgColumn<{
1388
+ name: "id";
1389
+ tableName: "jwks";
1390
+ dataType: "string";
1391
+ columnType: "PgText";
1392
+ data: string;
1393
+ driverParam: string;
1394
+ notNull: true;
1395
+ hasDefault: false;
1396
+ isPrimaryKey: true;
1397
+ isAutoincrement: false;
1398
+ hasRuntimeDefault: false;
1399
+ enumValues: [string, ...string[]];
1400
+ baseColumn: never;
1401
+ identity: undefined;
1402
+ generated: undefined;
1403
+ }, {}, {}>;
1404
+ publicKey: import("drizzle-orm/pg-core").PgColumn<{
1405
+ name: "public_key";
1406
+ tableName: "jwks";
1407
+ dataType: "string";
1408
+ columnType: "PgText";
1409
+ data: string;
1410
+ driverParam: string;
1411
+ notNull: true;
1412
+ hasDefault: false;
1413
+ isPrimaryKey: false;
1414
+ isAutoincrement: false;
1415
+ hasRuntimeDefault: false;
1416
+ enumValues: [string, ...string[]];
1417
+ baseColumn: never;
1418
+ identity: undefined;
1419
+ generated: undefined;
1420
+ }, {}, {}>;
1421
+ privateKey: import("drizzle-orm/pg-core").PgColumn<{
1422
+ name: "private_key";
1423
+ tableName: "jwks";
1424
+ dataType: "string";
1425
+ columnType: "PgText";
1426
+ data: string;
1427
+ driverParam: string;
1428
+ notNull: true;
1429
+ hasDefault: false;
1430
+ isPrimaryKey: false;
1431
+ isAutoincrement: false;
1432
+ hasRuntimeDefault: false;
1433
+ enumValues: [string, ...string[]];
1434
+ baseColumn: never;
1435
+ identity: undefined;
1436
+ generated: undefined;
1437
+ }, {}, {}>;
1438
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1439
+ name: "created_at";
1440
+ tableName: "jwks";
1441
+ dataType: "date";
1442
+ columnType: "PgTimestamp";
1443
+ data: Date;
1444
+ driverParam: string;
1445
+ notNull: true;
1446
+ hasDefault: false;
1447
+ isPrimaryKey: false;
1448
+ isAutoincrement: false;
1449
+ hasRuntimeDefault: false;
1450
+ enumValues: undefined;
1451
+ baseColumn: never;
1452
+ identity: undefined;
1453
+ generated: undefined;
1454
+ }, {}, {}>;
1455
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
1456
+ name: "expires_at";
1457
+ tableName: "jwks";
1458
+ dataType: "date";
1459
+ columnType: "PgTimestamp";
1460
+ data: Date;
1461
+ driverParam: string;
1462
+ notNull: false;
1463
+ hasDefault: false;
1464
+ isPrimaryKey: false;
1465
+ isAutoincrement: false;
1466
+ hasRuntimeDefault: false;
1467
+ enumValues: undefined;
1468
+ baseColumn: never;
1469
+ identity: undefined;
1470
+ generated: undefined;
1471
+ }, {}, {}>;
1472
+ };
1473
+ dialect: "pg";
1474
+ }>;
1383
1475
  //# sourceMappingURL=auth-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-schema.d.ts","sourceRoot":"","sources":["../../src/auth/auth-schema.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaf,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAclB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBlB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOvB,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUjB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAarB,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBjB,CAAC"}
1
+ {"version":3,"file":"auth-schema.d.ts","sourceRoot":"","sources":["../../src/auth/auth-schema.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaf,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAclB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBlB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOvB,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUjB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAarB,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBjB,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMf,CAAC"}
@@ -115,3 +115,10 @@ export const apikey = pgTable("apikey", {
115
115
  permissions: text("permissions"),
116
116
  metadata: text("metadata"),
117
117
  });
118
+ export const jwks = pgTable("jwks", {
119
+ id: text("id").primaryKey(),
120
+ publicKey: text("public_key").notNull(),
121
+ privateKey: text("private_key").notNull(),
122
+ createdAt: timestamp("created_at").notNull(),
123
+ expiresAt: timestamp("expires_at"),
124
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/auth/setup.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAgCrE,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,GAAG,EAAE;QACH,UAAU,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;YACrB,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;aAAE,CAAC;SAC/D,KAAK,OAAO,CAAC;YACZ,KAAK,EAAE,OAAO,CAAC;YACf,KAAK,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAC;YAChD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;SACrC,CAAC,CAAC;QACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;YACrB,IAAI,EAAE;gBACJ,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBACvC,MAAM,CAAC,EAAE,MAAM,CAAC;aACjB,CAAC;YACF,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,KAAK,OAAO,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC3C,qEAAqE;QACrE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,cAAc,GACrB,YAAY,CAgGd"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/auth/setup.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAgCrE,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,GAAG,EAAE;QACH,UAAU,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;YACrB,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;aAAE,CAAC;SAC/D,KAAK,OAAO,CAAC;YACZ,KAAK,EAAE,OAAO,CAAC;YACf,KAAK,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAC;YAChD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;SACrC,CAAC,CAAC;QACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;YACrB,IAAI,EAAE;gBACJ,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBACvC,MAAM,CAAC,EAAE,MAAM,CAAC;aACjB,CAAC;YACF,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,KAAK,OAAO,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC3C,qEAAqE;QACrE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,cAAc,GACrB,YAAY,CAoGd"}
@@ -1,7 +1,7 @@
1
1
  import { drizzleAdapter } from "@better-auth/drizzle-adapter";
2
2
  import { betterAuth } from "better-auth";
3
3
  import { apiKey } from "@better-auth/api-key";
4
- import { organization, twoFactor, phoneNumber } from "better-auth/plugins";
4
+ import { organization, twoFactor, phoneNumber, jwt, bearer } from "better-auth/plugins";
5
5
  import * as authSchema from "./auth-schema.js";
6
6
  function resolveAuthDbProvider(provider) {
7
7
  if (provider === "postgres" ||
@@ -22,6 +22,8 @@ export function createAuth(db, config) {
22
22
  organization({
23
23
  roles: (config.auth?.roles ?? {}),
24
24
  }),
25
+ bearer(),
26
+ jwt(),
25
27
  ];
26
28
  if (config.auth?.twoFactor?.enabled) {
27
29
  plugins.push(twoFactor({ issuer: config.storeName ?? "UnifiedCommerce" }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifiedcommerce/core",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -65,7 +65,6 @@
65
65
  },
66
66
  "files": [
67
67
  "dist",
68
- "src",
69
68
  "README.md"
70
69
  ]
71
70
  }
@@ -1,43 +0,0 @@
1
- /**
2
- * Development email adapter that logs emails to the console.
3
- *
4
- * Zero dependencies. Use this during local development to see email
5
- * content in the terminal without configuring Resend or an SMTP server.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { consoleEmailAdapter } from "@unifiedcommerce/core";
10
- *
11
- * export default defineConfig({
12
- * email: consoleEmailAdapter(),
13
- * });
14
- * ```
15
- */
16
- export function consoleEmailAdapter(): {
17
- send(input: { template: string; to: string; data?: Record<string, unknown> }): Promise<void>;
18
- } {
19
- return {
20
- async send(input) {
21
- const divider = "=".repeat(60);
22
- const lines = [
23
- "",
24
- divider,
25
- ` EMAIL: ${input.template}`,
26
- divider,
27
- ` To: ${input.to}`,
28
- ` Template: ${input.template}`,
29
- ];
30
-
31
- if (input.data && Object.keys(input.data).length > 0) {
32
- lines.push(` Data:`);
33
- for (const [key, value] of Object.entries(input.data)) {
34
- lines.push(` ${key}: ${JSON.stringify(value)}`);
35
- }
36
- }
37
-
38
- lines.push(divider, "");
39
-
40
- console.log(lines.join("\n"));
41
- },
42
- };
43
- }
@@ -1,187 +0,0 @@
1
- import type { Actor } from "./types.js";
2
-
3
- /**
4
- * A WhereClause is a plain object representing database filter conditions.
5
- * The shape mirrors what services and repositories can accept to narrow queries.
6
- *
7
- * Example: { customerId: "abc-123" } narrows results to that customer's records.
8
- * Composite: { or: [{ customerId: "x" }, { organizationId: "y" }] }
9
- */
10
- export type WhereClause = Record<string, unknown>;
11
-
12
- /**
13
- * AccessResult: the return value of an access function.
14
- *
15
- * - `true`: full access, no filter needed
16
- * - `false`: no access at all
17
- * - `WhereClause`: partial access — the caller should apply this as a query filter
18
- */
19
- export type AccessResult = boolean | WhereClause;
20
-
21
- /**
22
- * AccessContext carries everything an access function needs to make a decision.
23
- *
24
- * - `actor`: the authenticated user/api-key/null (anonymous)
25
- * - `data`: the document being accessed (for document-level checks)
26
- * - `id`: the document ID (when data isn't loaded yet)
27
- */
28
- export interface AccessContext<TData = unknown> {
29
- actor: Actor | null;
30
- data?: TData;
31
- id?: string;
32
- req?: Request;
33
- }
34
-
35
- /**
36
- * An AccessFn evaluates access for a given context.
37
- * Returns boolean (full/no access) or WhereClause (filtered access).
38
- */
39
- export type AccessFn<TData = unknown> = (
40
- ctx: AccessContext<TData>,
41
- ) => AccessResult | Promise<AccessResult>;
42
-
43
- /**
44
- * Combines multiple WhereClause objects with a logical operator.
45
- * If there's only one clause, returns it directly (no unnecessary nesting).
46
- */
47
- function combineWhere(
48
- queries: WhereClause[],
49
- operator: "and" | "or",
50
- ): WhereClause {
51
- if (queries.length === 1) return queries[0]!;
52
- return { [operator]: queries };
53
- }
54
-
55
- /**
56
- * Composes access functions with OR semantics.
57
- *
58
- * - If ANY function returns `true`, grants full access immediately (short-circuit).
59
- * - If one or more return WhereClause, combines them with OR.
60
- * - If ALL return `false`, denies access.
61
- *
62
- * Example:
63
- * ```typescript
64
- * const orderReadAccess = accessOR(isAdmin, isDocumentOwner("customerId"))
65
- * // Admins see all orders; customers see only their own
66
- * ```
67
- */
68
- export const accessOR = <TData = unknown>(
69
- ...fns: Array<AccessFn<TData>>
70
- ): AccessFn<TData> => {
71
- return async (ctx) => {
72
- const queries: WhereClause[] = [];
73
- for (const fn of fns) {
74
- const result = await fn(ctx);
75
- if (result === true) return true;
76
- if (result && typeof result === "object") queries.push(result);
77
- }
78
- if (queries.length > 0) return combineWhere(queries, "or");
79
- return false;
80
- };
81
- };
82
-
83
- /**
84
- * Composes access functions with AND semantics.
85
- *
86
- * - If ANY function returns `false`, denies access immediately (short-circuit).
87
- * - If one or more return WhereClause, combines them with AND.
88
- * - If ALL return `true`, grants full access.
89
- *
90
- * Example:
91
- * ```typescript
92
- * const restrictedAccess = accessAND(isAuthenticated, isDocumentOwner("customerId"))
93
- * // Must be logged in AND own the document
94
- * ```
95
- */
96
- export const accessAND = <TData = unknown>(
97
- ...fns: Array<AccessFn<TData>>
98
- ): AccessFn<TData> => {
99
- return async (ctx) => {
100
- const queries: WhereClause[] = [];
101
- for (const fn of fns) {
102
- const result = await fn(ctx);
103
- if (result === false) return false;
104
- if (result !== true && result && typeof result === "object") {
105
- queries.push(result);
106
- }
107
- }
108
- if (queries.length > 0) return combineWhere(queries, "and");
109
- return true;
110
- };
111
- };
112
-
113
- /**
114
- * Switches between two access functions based on a condition.
115
- *
116
- * Example:
117
- * ```typescript
118
- * const accessByRole = conditional(
119
- * ({ actor }) => actor?.role === "vendor",
120
- * isDocumentOwner("vendorId"),
121
- * isAdmin,
122
- * )
123
- * ```
124
- */
125
- export const conditional = <TData = unknown>(
126
- condition: ((ctx: AccessContext<TData>) => boolean) | boolean,
127
- accessFn: AccessFn<TData>,
128
- fallback: AccessFn<TData> = () => false,
129
- ): AccessFn<TData> => {
130
- return async (ctx) => {
131
- const applies =
132
- typeof condition === "function" ? condition(ctx) : condition;
133
- return applies ? accessFn(ctx) : fallback(ctx);
134
- };
135
- };
136
-
137
- // ─────────────────────────────────────────────────────────────────────────────
138
- // Built-in access functions
139
- // ─────────────────────────────────────────────────────────────────────────────
140
-
141
- /**
142
- * Grants access if the actor has admin or owner role (wildcard permissions).
143
- */
144
- export const isAdmin: AccessFn = ({ actor }) => {
145
- if (!actor) return false;
146
- return actor.permissions.includes("*:*");
147
- };
148
-
149
- /**
150
- * Grants access if the actor is authenticated (any role).
151
- */
152
- export const isAuthenticated: AccessFn = ({ actor }) => {
153
- return actor != null;
154
- };
155
-
156
- /**
157
- * Returns a WhereClause that filters to documents owned by the actor.
158
- * The ownerField is the column name that holds the owner's user ID.
159
- *
160
- * For document-level checks (when data is provided), returns true/false.
161
- * For list-level checks (when data is not provided), returns a WhereClause.
162
- */
163
- export const isDocumentOwner = (
164
- ownerField = "customerId",
165
- ): AccessFn => {
166
- return ({ actor, data }) => {
167
- if (!actor) return false;
168
-
169
- // Document-level check: compare directly
170
- if (data) {
171
- return (data as Record<string, unknown>)[ownerField] === actor.userId;
172
- }
173
-
174
- // List-level check: return a filter clause
175
- return { [ownerField]: actor.userId };
176
- };
177
- };
178
-
179
- /**
180
- * Grants access to everyone, including anonymous users.
181
- */
182
- export const publicAccess: AccessFn = () => true;
183
-
184
- /**
185
- * Denies access to everyone.
186
- */
187
- export const denyAll: AccessFn = () => false;
@@ -1,131 +0,0 @@
1
- import {
2
- pgTable,
3
- text,
4
- timestamp,
5
- boolean,
6
- integer,
7
- } from "drizzle-orm/pg-core";
8
-
9
- export const user = pgTable("user", {
10
- id: text("id").primaryKey(),
11
- name: text("name").notNull(),
12
- email: text("email").notNull().unique(),
13
- emailVerified: boolean("email_verified").default(false).notNull(),
14
- image: text("image"),
15
- createdAt: timestamp("created_at").defaultNow().notNull(),
16
- updatedAt: timestamp("updated_at")
17
- .defaultNow()
18
- .$onUpdate(() => /* @__PURE__ */ new Date())
19
- .notNull(),
20
- vendorId: text("vendor_id"),
21
- posOperatorPin: text("pos_operator_pin"),
22
- });
23
-
24
- export const session = pgTable("session", {
25
- id: text("id").primaryKey(),
26
- expiresAt: timestamp("expires_at").notNull(),
27
- token: text("token").notNull().unique(),
28
- createdAt: timestamp("created_at").defaultNow().notNull(),
29
- updatedAt: timestamp("updated_at")
30
- .$onUpdate(() => /* @__PURE__ */ new Date())
31
- .notNull(),
32
- ipAddress: text("ip_address"),
33
- userAgent: text("user_agent"),
34
- userId: text("user_id")
35
- .notNull()
36
- .references(() => user.id, { onDelete: "cascade" }),
37
- activeOrganizationId: text("active_organization_id"),
38
- });
39
-
40
- export const account = pgTable("account", {
41
- id: text("id").primaryKey(),
42
- accountId: text("account_id").notNull(),
43
- providerId: text("provider_id").notNull(),
44
- userId: text("user_id")
45
- .notNull()
46
- .references(() => user.id, { onDelete: "cascade" }),
47
- accessToken: text("access_token"),
48
- refreshToken: text("refresh_token"),
49
- idToken: text("id_token"),
50
- accessTokenExpiresAt: timestamp("access_token_expires_at"),
51
- refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
52
- scope: text("scope"),
53
- password: text("password"),
54
- createdAt: timestamp("created_at").defaultNow().notNull(),
55
- updatedAt: timestamp("updated_at")
56
- .$onUpdate(() => /* @__PURE__ */ new Date())
57
- .notNull(),
58
- });
59
-
60
- export const verification = pgTable("verification", {
61
- id: text("id").primaryKey(),
62
- identifier: text("identifier").notNull(),
63
- value: text("value").notNull(),
64
- expiresAt: timestamp("expires_at").notNull(),
65
- createdAt: timestamp("created_at").defaultNow().notNull(),
66
- updatedAt: timestamp("updated_at")
67
- .defaultNow()
68
- .$onUpdate(() => /* @__PURE__ */ new Date())
69
- .notNull(),
70
- });
71
-
72
- export const organization = pgTable("organization", {
73
- id: text("id").primaryKey(),
74
- name: text("name").notNull(),
75
- slug: text("slug").notNull().unique(),
76
- logo: text("logo"),
77
- createdAt: timestamp("created_at").notNull(),
78
- metadata: text("metadata"),
79
- });
80
-
81
- export const member = pgTable("member", {
82
- id: text("id").primaryKey(),
83
- organizationId: text("organization_id")
84
- .notNull()
85
- .references(() => organization.id, { onDelete: "cascade" }),
86
- userId: text("user_id")
87
- .notNull()
88
- .references(() => user.id, { onDelete: "cascade" }),
89
- role: text("role").default("member").notNull(),
90
- createdAt: timestamp("created_at").notNull(),
91
- });
92
-
93
- export const invitation = pgTable("invitation", {
94
- id: text("id").primaryKey(),
95
- organizationId: text("organization_id")
96
- .notNull()
97
- .references(() => organization.id, { onDelete: "cascade" }),
98
- email: text("email").notNull(),
99
- role: text("role"),
100
- status: text("status").default("pending").notNull(),
101
- expiresAt: timestamp("expires_at").notNull(),
102
- createdAt: timestamp("created_at").defaultNow().notNull(),
103
- inviterId: text("inviter_id")
104
- .notNull()
105
- .references(() => user.id, { onDelete: "cascade" }),
106
- });
107
-
108
- export const apikey = pgTable("apikey", {
109
- id: text("id").primaryKey(),
110
- configId: text("config_id").default("default").notNull(),
111
- name: text("name"),
112
- start: text("start"),
113
- referenceId: text("reference_id").notNull(),
114
- prefix: text("prefix"),
115
- key: text("key").notNull(),
116
- refillInterval: integer("refill_interval"),
117
- refillAmount: integer("refill_amount"),
118
- lastRefillAt: timestamp("last_refill_at"),
119
- enabled: boolean("enabled").default(true),
120
- rateLimitEnabled: boolean("rate_limit_enabled").default(false),
121
- rateLimitTimeWindow: integer("rate_limit_time_window").default(3600000),
122
- rateLimitMax: integer("rate_limit_max").default(10000),
123
- requestCount: integer("request_count").default(0),
124
- remaining: integer("remaining"),
125
- lastRequest: timestamp("last_request"),
126
- expiresAt: timestamp("expires_at"),
127
- createdAt: timestamp("created_at").notNull(),
128
- updatedAt: timestamp("updated_at").notNull(),
129
- permissions: text("permissions"),
130
- metadata: text("metadata"),
131
- });
@@ -1,161 +0,0 @@
1
- import { timingSafeEqual } from "node:crypto";
2
- import type { MiddlewareHandler } from "hono";
3
- import type { AuthSessionLike, CommerceConfig } from "../config/types.js";
4
- import type { Actor } from "./types.js";
5
- import type { AuthInstance } from "./setup.js";
6
- import { DEFAULT_ORG_ID } from "./org.js";
7
-
8
- function resolvePermissions(
9
- session: AuthSessionLike,
10
- config: CommerceConfig,
11
- ): string[] {
12
- const role = session.session.activeOrganizationRole;
13
- if (!role) {
14
- return (
15
- config.auth?.customerPermissions ?? [
16
- "catalog:read",
17
- "cart:create",
18
- "cart:read",
19
- "cart:update",
20
- "orders:create",
21
- "orders:read:own",
22
- "customers:read:self",
23
- "customers:update:self",
24
- ]
25
- );
26
- }
27
- const roleConfig = config.auth?.roles?.[role];
28
- return roleConfig ? roleConfig.permissions : [];
29
- }
30
-
31
- export function authMiddleware(
32
- auth: AuthInstance,
33
- config: CommerceConfig,
34
- ): MiddlewareHandler {
35
- return async (c, next) => {
36
- const session = (await auth.api.getSession({
37
- headers: c.req.raw.headers,
38
- })) as AuthSessionLike | null;
39
-
40
- if (session) {
41
- // Better Auth's session only stores activeOrganizationId, not the role.
42
- // Resolve role via the organization plugin's server-side API when needed.
43
- let role = session.session.activeOrganizationRole as string | undefined;
44
- if (!role && session.session.activeOrganizationId && auth.api.getActiveMemberRole) {
45
- try {
46
- const roleResult = await auth.api.getActiveMemberRole({
47
- headers: c.req.raw.headers,
48
- });
49
- role = (roleResult as Record<string, unknown>)?.role as string | undefined;
50
- } catch {
51
- // fall through — treat as customer
52
- }
53
- }
54
- const enrichedSession = {
55
- ...session,
56
- session: { ...session.session, activeOrganizationRole: role ?? null },
57
- };
58
- c.set("actor", {
59
- type: "user",
60
- userId: session.user.id,
61
- email: session.user.email ?? null,
62
- name: session.user.name ?? "User",
63
- vendorId: session.user.vendorId ?? null,
64
- organizationId: session.session.activeOrganizationId ?? null,
65
- role: role ?? "customer",
66
- permissions: resolvePermissions(enrichedSession, config),
67
- } satisfies Actor);
68
- await next();
69
- return;
70
- }
71
-
72
- // Extract API key from headers
73
- const apiKeyHeader =
74
- c.req.header("x-api-key") ??
75
- c.req.header("authorization")?.replace("Bearer ", "");
76
-
77
- if (
78
- apiKeyHeader &&
79
- config.auth?.apiKeys?.enabled &&
80
- auth.api.verifyApiKey
81
- ) {
82
- try {
83
- // Better Auth server-side calls require { body: { ... } } wrapper.
84
- // Returns { valid, error, key: Omit<ApiKey,"key"> | null }.
85
- // See: https://better-auth.com/docs/plugins/api-key/reference
86
- const result = await auth.api.verifyApiKey({
87
- body: { key: apiKeyHeader },
88
- });
89
- if (result?.valid && result.key) {
90
- const apiKey = result.key as Record<string, unknown>;
91
-
92
- // v1.5+ renamed userId → referenceId on the apikey table.
93
- const userId = (apiKey.referenceId ?? "") as string;
94
- const name = (apiKey.name ?? "API Key") as string;
95
- const orgId = (apiKey.organizationId ?? DEFAULT_ORG_ID) as string;
96
-
97
- // Better Auth stores permissions as Record<string, string[]>
98
- // (e.g. {"catalog":["read","create"]}). Flatten to the
99
- // "resource:action" string[] format the engine expects.
100
- let permissions: string[];
101
- const rawPerms = apiKey.permissions;
102
- if (Array.isArray(rawPerms)) {
103
- permissions = rawPerms;
104
- } else if (rawPerms && typeof rawPerms === "object") {
105
- permissions = [];
106
- for (const [resource, actions] of Object.entries(
107
- rawPerms as Record<string, string[]>,
108
- )) {
109
- for (const action of actions) {
110
- permissions.push(`${resource}:${action}`);
111
- }
112
- }
113
- } else {
114
- permissions = config.auth?.apiKeys?.defaultPermissions ?? [];
115
- }
116
-
117
- c.set("actor", {
118
- type: "api_key",
119
- userId,
120
- email: null,
121
- name,
122
- vendorId: null,
123
- organizationId: orgId,
124
- role: "api_key",
125
- permissions,
126
- } satisfies Actor);
127
- await next();
128
- return;
129
- }
130
- } catch {
131
- // invalid, expired, or rate-limited key — fall through
132
- }
133
- }
134
-
135
- // Config-driven dev key (OFF by default, must be explicitly enabled)
136
- if (
137
- !c.get("actor") &&
138
- apiKeyHeader &&
139
- config.auth?.enableDevKey &&
140
- config.auth.devKey &&
141
- apiKeyHeader.length === config.auth.devKey.length &&
142
- timingSafeEqual(Buffer.from(apiKeyHeader), Buffer.from(config.auth.devKey))
143
- ) {
144
- c.set("actor", {
145
- type: "api_key",
146
- userId: "dev-staff",
147
- email: "dev@local",
148
- name: "Dev Admin (dev key)",
149
- vendorId: null,
150
- organizationId: DEFAULT_ORG_ID,
151
- role: "owner",
152
- permissions: ["*:*"],
153
- } satisfies Actor);
154
- }
155
-
156
- if (!c.get("actor")) {
157
- c.set("actor", null);
158
- }
159
- await next();
160
- };
161
- }