@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
@@ -1,16 +0,0 @@
1
- import type { CommerceConfig } from "../config/types.js";
2
- import { createTestConfig } from "./create-test-config.js";
3
- import { createKernel } from "../runtime/kernel.js";
4
-
5
- export interface RepositoryTestHarness {
6
- config: CommerceConfig;
7
- kernel: ReturnType<typeof createKernel>;
8
- }
9
-
10
- export async function createRepositoryTestHarness(
11
- overrides: Partial<CommerceConfig> = {},
12
- ): Promise<RepositoryTestHarness> {
13
- const config = await createTestConfig(overrides);
14
- const kernel = createKernel(config);
15
- return { config, kernel };
16
- }
@@ -1,190 +0,0 @@
1
- import { defineConfig } from "../config/define-config.js";
2
- import type { CommerceConfig } from "../config/types.js";
3
- import { Ok } from "../kernel/result.js";
4
- import type { StorageAdapter } from "../modules/media/adapter.js";
5
-
6
- function createInMemoryStorageAdapter(): StorageAdapter {
7
- const files = new Map<string, { data: ArrayBuffer; contentType: string }>();
8
- const baseUrl = "http://localhost:3000/test-assets";
9
-
10
- return {
11
- providerId: "test-memory-storage",
12
- async upload(key, data, contentType) {
13
- const body =
14
- data instanceof ArrayBuffer
15
- ? data
16
- : await new Response(data).arrayBuffer();
17
- files.set(key, { data: body, contentType });
18
- return Ok({
19
- key,
20
- url: `${baseUrl}/${key}`,
21
- contentType,
22
- size: body.byteLength,
23
- });
24
- },
25
- async getUrl(key) {
26
- return Ok(`${baseUrl}/${key}`);
27
- },
28
- async getSignedUrl(key, expiresIn) {
29
- return Ok(`${baseUrl}/${key}?expiresIn=${expiresIn}`);
30
- },
31
- async delete(key) {
32
- files.delete(key);
33
- return Ok(undefined);
34
- },
35
- async list(prefix) {
36
- return Ok(
37
- Array.from(files.entries())
38
- .filter(([key]) => key.startsWith(prefix))
39
- .map(([key, file]) => ({
40
- key,
41
- url: `${baseUrl}/${key}`,
42
- contentType: file.contentType,
43
- size: file.data.byteLength,
44
- })),
45
- );
46
- },
47
- };
48
- }
49
-
50
- export async function createTestConfig(
51
- overrides: Partial<CommerceConfig> = {},
52
- ): Promise<CommerceConfig> {
53
- // Auto-provision PGlite when no databaseAdapter is provided
54
- if (!overrides.databaseAdapter) {
55
- const { createPGliteTestAdapter } = await import("./create-pglite-adapter.js");
56
- const { adapter } = await createPGliteTestAdapter();
57
- overrides = { ...overrides, databaseAdapter: adapter };
58
- }
59
-
60
- return defineConfig({
61
- version: "0.0.1-test",
62
- storeName: "Test Store",
63
- database: {
64
- provider: "postgresql",
65
- },
66
- auth: {
67
- requireEmailVerification: false,
68
- apiKeys: { enabled: true, defaultPermissions: ["catalog:read"] },
69
- enableDevKey: true,
70
- devKey: "dev-staff-key",
71
- posPin: { enabled: true },
72
- roles: {
73
- owner: { permissions: ["*:*"] },
74
- admin: { permissions: ["*:*"] },
75
- staff: {
76
- permissions: [
77
- "catalog:create",
78
- "catalog:update",
79
- "catalog:delete",
80
- "catalog:read",
81
- "inventory:adjust",
82
- "orders:create",
83
- "orders:read",
84
- "orders:update",
85
- "cart:create",
86
- "cart:update",
87
- "customers:update:self",
88
- ],
89
- },
90
- ai_agent: {
91
- permissions: [
92
- "catalog:read",
93
- "catalog:create",
94
- "inventory:read",
95
- "inventory:adjust",
96
- "orders:read",
97
- "cart:create",
98
- "cart:update",
99
- "mcp:access",
100
- ],
101
- },
102
- },
103
- customerPermissions: [
104
- "catalog:read",
105
- "cart:create",
106
- "cart:read",
107
- "cart:update",
108
- "orders:create",
109
- "orders:read:own",
110
- "customers:read:self",
111
- "customers:update:self",
112
- ],
113
- },
114
- entities: {
115
- product: {
116
- fields: [
117
- { name: "weight", type: "number" },
118
- { name: "brand", type: "text" },
119
- ],
120
- variants: { enabled: true, optionTypes: ["size", "color"] },
121
- fulfillment: "physical",
122
- },
123
- digitalDownload: {
124
- fields: [{ name: "fileAssetId", type: "text" }],
125
- variants: { enabled: false },
126
- fulfillment: "digital-download",
127
- },
128
- course: {
129
- fields: [{ name: "modules", type: "json" }],
130
- variants: { enabled: false },
131
- fulfillment: "digital-access",
132
- },
133
- },
134
- cart: {
135
- ttlMinutes: 5,
136
- hooks: {},
137
- },
138
- checkout: {
139
- hooks: {
140
- beforeCreate: [],
141
- afterCreate: [],
142
- },
143
- },
144
- orders: {
145
- hooks: {
146
- beforeCreate: [],
147
- afterCreate: [],
148
- beforeStatusChange: [],
149
- afterStatusChange: [],
150
- },
151
- },
152
- inventory: {
153
- hooks: {
154
- afterAdjust: [],
155
- },
156
- },
157
- email: {
158
- async send() {
159
- // no-op for tests
160
- },
161
- },
162
- storage: createInMemoryStorageAdapter(),
163
- ...overrides,
164
- });
165
- }
166
-
167
- /**
168
- * Creates a test config backed by PGlite (in-memory PostgreSQL).
169
- *
170
- * This provides production parity for tests by using real SQL execution
171
- * and PostgreSQL behavior while remaining fast and self-contained.
172
- *
173
- * @param overrides - Optional config overrides
174
- * @returns A promise resolving to an object containing:
175
- * - config: The CommerceConfig to pass to createKernel
176
- * - cleanup: Async function to reset data between tests
177
- */
178
- export async function createPGliteTestConfig(
179
- overrides: Partial<CommerceConfig> = {},
180
- ): Promise<{ config: CommerceConfig; cleanup: () => Promise<void> }> {
181
- const { createPGliteTestAdapter } = await import("./create-pglite-adapter.js");
182
- const { adapter, cleanup } = await createPGliteTestAdapter();
183
-
184
- const config = await createTestConfig({
185
- databaseAdapter: adapter,
186
- ...overrides,
187
- });
188
-
189
- return { config, cleanup };
190
- }
@@ -1,7 +0,0 @@
1
- import type { CommerceConfig } from "../config/types.js";
2
- import { createKernel } from "../runtime/kernel.js";
3
- import { createTestConfig } from "./create-test-config.js";
4
-
5
- export async function createTestKernel(overrides: Partial<CommerceConfig> = {}) {
6
- return createKernel(await createTestConfig(overrides));
7
- }
@@ -1,75 +0,0 @@
1
- import { HookRegistry } from "../kernel/hooks/registry.js";
2
- import { createLogger } from "../utils/logger.js";
3
- import { createTestConfig } from "./create-test-config.js";
4
- import type { CommerceConfig, MCPTool } from "../config/types.js";
5
-
6
- interface PluginContextShape {
7
- hooks: HookRegistry;
8
- config: CommerceConfig;
9
- services: Record<string, unknown>;
10
- routes: { add(method: string, path: string, handler: (...args: unknown[]) => unknown): void };
11
- mcp: { registerTool(tool: MCPTool): void };
12
- analytics: { registerModel(model: unknown): void };
13
- database: {
14
- registerSchema(schema: Record<string, unknown>): void;
15
- query: unknown;
16
- transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T>;
17
- };
18
- logger: { info(message: string, data?: unknown): void; warn(message: string, data?: unknown): void; error(message: string, data?: unknown): void };
19
- }
20
-
21
- export interface TestPluginContext extends PluginContextShape {
22
- registeredRoutes: Array<{ method: string; path: string; handler: (...args: unknown[]) => unknown }>;
23
- registeredMCPTools: MCPTool[];
24
- registeredAnalyticsModels: unknown[];
25
- registeredSchemas: Array<Record<string, unknown>>;
26
- }
27
-
28
- export async function createTestPluginContext(options?: {
29
- config?: Partial<CommerceConfig>;
30
- services?: Record<string, unknown>;
31
- }): Promise<TestPluginContext> {
32
- const hooks = new HookRegistry();
33
- const config = await createTestConfig(options?.config ?? {});
34
- const services = options?.services ?? {};
35
-
36
- const registeredRoutes: TestPluginContext["registeredRoutes"] = [];
37
- const registeredMCPTools: MCPTool[] = [];
38
- const registeredAnalyticsModels: unknown[] = [];
39
- const registeredSchemas: Array<Record<string, unknown>> = [];
40
-
41
- return {
42
- hooks,
43
- config,
44
- services,
45
- routes: {
46
- add(method, path, handler) {
47
- registeredRoutes.push({ method: method.toUpperCase(), path, handler });
48
- },
49
- },
50
- mcp: {
51
- registerTool(tool) {
52
- registeredMCPTools.push(tool);
53
- },
54
- },
55
- analytics: {
56
- registerModel(model) {
57
- registeredAnalyticsModels.push(model);
58
- },
59
- },
60
- database: {
61
- registerSchema(schema) {
62
- registeredSchemas.push(schema);
63
- },
64
- query: {},
65
- async transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T> {
66
- return fn({});
67
- },
68
- },
69
- logger: createLogger("test-plugin-context"),
70
- registeredRoutes,
71
- registeredMCPTools,
72
- registeredAnalyticsModels,
73
- registeredSchemas,
74
- };
75
- }
@@ -1,265 +0,0 @@
1
- /**
2
- * Integration test utilities for REST API endpoints.
3
- *
4
- * Provides helper functions to test Hono routes with a real kernel,
5
- * PGlite database, and authentication middleware.
6
- */
7
-
8
- import { Hono } from "hono";
9
- import { createKernel } from "../runtime/kernel.js";
10
- import { createAuth } from "../auth/setup.js";
11
- import { authMiddleware } from "../auth/middleware.js";
12
- import { createRestRoutes } from "../interfaces/rest/index.js";
13
- import { createPGliteTestConfig } from "./create-test-config.js";
14
- import { CommerceValidationError } from "../kernel/errors.js";
15
- import { Ok, Err } from "../kernel/result.js";
16
- import type { CommerceConfig } from "../config/types.js";
17
- import type { Actor } from "../auth/types.js";
18
- import type { AuthInstance } from "../auth/setup.js";
19
-
20
- type ServerEnv = {
21
- Variables: {
22
- auth: AuthInstance;
23
- actor: Actor | null;
24
- };
25
- };
26
-
27
- const mockPaymentAdapter = {
28
- providerId: "test-payments",
29
- async createPaymentIntent(params: { amount: number; currency: string }) {
30
- return Ok({
31
- id: "pi_test_" + Date.now(),
32
- status: "requires_capture",
33
- amount: params.amount,
34
- currency: params.currency,
35
- clientSecret: "secret_test",
36
- });
37
- },
38
- async capturePayment() {
39
- return Ok({ id: "pi_test_" + Date.now(), status: "succeeded", amountCaptured: 1000 });
40
- },
41
- async refundPayment() {
42
- return Ok({ id: "re_test_" + Date.now(), status: "succeeded", amountRefunded: 1000 });
43
- },
44
- async cancelPaymentIntent() {
45
- return Ok(undefined);
46
- },
47
- async verifyWebhook(request: Request) {
48
- // Extract signature from headers
49
- const signature = request.headers.get("stripe-signature") || request.headers.get("webhook-signature");
50
-
51
- // Extract payload from request body
52
- let payload: Record<string, unknown> | undefined;
53
- try {
54
- payload = await request.clone().json();
55
- } catch {
56
- return Err(new CommerceValidationError("Webhook payload is invalid or missing"));
57
- }
58
-
59
- // Simulate signature verification for production-hardened testing
60
- // Reject invalid signatures like "invalid_signature"
61
- if (signature === "invalid_signature") {
62
- return Err(new CommerceValidationError("Invalid webhook signature"));
63
- }
64
-
65
- // Reject requests with no required fields
66
- if (!payload || !payload.type) {
67
- return Err(new CommerceValidationError("Webhook payload is missing required fields"));
68
- }
69
-
70
- return Ok({ id: "evt_test_" + Date.now(), type: String(payload.type), data: (payload.data ?? {}) as unknown });
71
- },
72
- };
73
-
74
- /**
75
- * Creates a test server with PGlite-backed kernel for REST API testing.
76
- */
77
- export async function createTestServer(
78
- overrides: Partial<CommerceConfig> = {},
79
- ): Promise<{
80
- server: Hono<ServerEnv>;
81
- kernel: ReturnType<typeof createKernel>;
82
- auth: AuthInstance;
83
- cleanup: () => Promise<void>;
84
- }> {
85
- const { config, cleanup } = await createPGliteTestConfig({
86
- payments: [mockPaymentAdapter],
87
- ...overrides,
88
- });
89
-
90
- const kernel = createKernel(config);
91
- const auth = createAuth(kernel.database, config);
92
- const app = new Hono<ServerEnv>();
93
-
94
- // Set auth in context (like createServer does)
95
- app.use("*", async (c, next) => {
96
- c.set("auth", auth);
97
- await next();
98
- });
99
-
100
- // Test middleware: allow direct actor injection via x-test-actor header for testing
101
- app.use("*", async (c, next) => {
102
- const testActorHeader = c.req.header("x-test-actor");
103
- if (testActorHeader) {
104
- try {
105
- const actor = JSON.parse(testActorHeader) as Actor;
106
- c.set("actor", actor);
107
- await next();
108
- return;
109
- } catch {
110
- // Invalid JSON, continue to auth middleware
111
- }
112
- }
113
- await next();
114
- });
115
-
116
- // Add auth middleware
117
- app.use("*", authMiddleware(auth, config));
118
-
119
- // Error handling middleware - catch thrown errors and convert to JSON
120
- app.use("*", async (c, next) => {
121
- try {
122
- await next();
123
- } catch (error) {
124
- // Import error handling utilities
125
- const { mapErrorToResponse, mapErrorToStatus } = await import("../interfaces/rest/utils.js");
126
- return c.json(
127
- mapErrorToResponse(error),
128
- mapErrorToStatus(error),
129
- );
130
- }
131
- });
132
-
133
- // Add REST routes
134
- app.route("/api", createRestRoutes(kernel));
135
-
136
- return { server: app, kernel, auth, cleanup };
137
- }
138
-
139
- /**
140
- * Helper to parse JSON response from Hono Response
141
- */
142
- export async function parseJsonResponse<T = unknown>(response: Response): Promise<T> {
143
- return response.json() as Promise<T>;
144
- }
145
-
146
- /**
147
- * Common test actor with staff permissions
148
- */
149
- export const testActor: Actor = {
150
- type: "user",
151
- userId: "00000000-0000-0000-0000-000000000001",
152
- email: "test@example.com",
153
- name: "Test Staff",
154
- vendorId: null,
155
- organizationId: "org_default",
156
- role: "staff",
157
- permissions: [
158
- "catalog:create",
159
- "catalog:update",
160
- "catalog:read",
161
- "inventory:adjust",
162
- "inventory:read",
163
- "orders:create",
164
- "orders:read",
165
- "orders:update",
166
- "cart:create",
167
- "cart:update",
168
- "cart:read",
169
- "customers:update:self",
170
- "webhooks:manage",
171
- "pricing:manage",
172
- "promotions:manage",
173
- "promotions:read",
174
- "audit:read",
175
- "media:write",
176
- ],
177
- };
178
-
179
- /**
180
- * Test actor with read-only permissions
181
- */
182
- export const readonlyActor: Actor = {
183
- type: "user",
184
- userId: "00000000-0000-0000-0000-000000000002",
185
- email: "readonly@example.com",
186
- name: "Read Only User",
187
- vendorId: null,
188
- organizationId: "org_default",
189
- role: "customer",
190
- permissions: ["catalog:read", "cart:read", "orders:read:own"],
191
- };
192
-
193
- /**
194
- * Test actor with no permissions
195
- */
196
- export const noPermActor: Actor = {
197
- type: "user",
198
- userId: "00000000-0000-0000-0000-000000000003",
199
- email: "noperm@example.com",
200
- name: "No Perm",
201
- vendorId: null,
202
- organizationId: "org_default",
203
- role: "customer",
204
- permissions: [],
205
- };
206
-
207
- /**
208
- * Helper to create a mock request with actor context
209
- */
210
- export function createMockRequest(server: Hono<ServerEnv>, options: {
211
- method: string;
212
- url: string;
213
- body?: unknown;
214
- headers?: Record<string, string>;
215
- actor?: Actor;
216
- }) {
217
- const url = new URL(options.url, "http://localhost");
218
-
219
- const headers: Record<string, string> = {
220
- "content-type": "application/json",
221
- ...options.headers,
222
- };
223
-
224
- // Add actor as header for test middleware
225
- if (options.actor) {
226
- headers["x-test-actor"] = JSON.stringify(options.actor);
227
- }
228
-
229
- // Build the request
230
- const requestInit: RequestInit = {
231
- method: options.method,
232
- headers,
233
- };
234
- if (options.body) {
235
- requestInit.body = JSON.stringify(options.body);
236
- }
237
- const request = new Request(url, requestInit);
238
-
239
- return request;
240
- }
241
-
242
- /**
243
- * Helper to make authenticated requests to the test server
244
- */
245
- export async function makeRequest(
246
- server: Hono<ServerEnv>,
247
- options: {
248
- method: string;
249
- url: string;
250
- body?: unknown;
251
- headers?: Record<string, string>;
252
- actor?: Actor;
253
- },
254
- ) {
255
- // Create request with actor header (defaults to testActor)
256
- const request = createMockRequest(server, {
257
- ...options,
258
- actor: options.actor ?? testActor,
259
- });
260
-
261
- // Route the request through Hono
262
- const response = await server.fetch(request);
263
-
264
- return response;
265
- }
@@ -1,62 +0,0 @@
1
- import type { Actor } from "../auth/types.js";
2
-
3
- /** Admin with wildcard permissions. Use for setup operations in beforeAll. */
4
- export const testAdminActor: Actor = {
5
- type: "user",
6
- userId: "test-admin-1",
7
- email: "admin@test.local",
8
- name: "Test Admin",
9
- vendorId: null,
10
- organizationId: "org_default",
11
- role: "admin",
12
- permissions: ["*:*"],
13
- };
14
-
15
- /** Staff with common operational permissions. */
16
- export const testStaffActor: Actor = {
17
- type: "user",
18
- userId: "test-staff-1",
19
- email: "staff@test.local",
20
- name: "Test Staff",
21
- vendorId: null,
22
- organizationId: "org_default",
23
- role: "staff",
24
- permissions: [
25
- "catalog:read", "catalog:create", "catalog:update",
26
- "inventory:adjust", "orders:read", "orders:create", "orders:update",
27
- ],
28
- };
29
-
30
- /** Customer with minimal read/write-own permissions. */
31
- export const testCustomerActor: Actor = {
32
- type: "user",
33
- userId: "test-customer-1",
34
- email: "customer@test.local",
35
- name: "Test Customer",
36
- vendorId: null,
37
- organizationId: "org_default",
38
- role: "customer",
39
- permissions: ["catalog:read", "cart:create", "cart:read", "orders:read:own"],
40
- };
41
-
42
- /** Actor with zero permissions. Use for negative auth/perm tests. */
43
- export const testNoPermActor: Actor = {
44
- type: "user",
45
- userId: "test-noperm-1",
46
- email: "noperm@test.local",
47
- name: "No Permissions",
48
- vendorId: null,
49
- organizationId: "org_default",
50
- role: "customer",
51
- permissions: [],
52
- };
53
-
54
- /**
55
- * Builds request headers with optional test actor injection.
56
- * The x-test-actor header is parsed by createPluginTestApp's middleware.
57
- */
58
- export function jsonHeaders(actor?: Actor): Record<string, string> {
59
- const headers: Record<string, string> = { "Content-Type": "application/json" };
60
- if (actor) headers["x-test-actor"] = JSON.stringify(actor);
61
- return headers;
62
- }
@@ -1,54 +0,0 @@
1
- import type { PluginHookRegistration } from "../kernel/plugin/manifest.js";
2
- import type { HookContext, HookOperation } from "../kernel/hooks/types.js";
3
-
4
- /**
5
- * Creates a typed before-hook registration for plugins.
6
- *
7
- * Narrows the handler signature from the loose `(...args: unknown[]) => unknown`
8
- * on PluginHookRegistration to the actual `{ data, operation, context }` shape,
9
- * providing autocomplete on context.jobs.enqueue(), context.logger.info(), etc.
10
- *
11
- * @example
12
- * ```typescript
13
- * hooks: () => [
14
- * beforeHook<{ customerId: string }>("orders.beforeCreate", async ({ data, context }) => {
15
- * context.logger.info("order_creating", { customerId: data.customerId });
16
- * return data;
17
- * }),
18
- * ],
19
- * ```
20
- */
21
- export function beforeHook<TData>(
22
- key: string,
23
- handler: (args: {
24
- data: TData;
25
- operation: HookOperation;
26
- context: HookContext;
27
- }) => Promise<TData> | TData,
28
- ): PluginHookRegistration {
29
- return { key, handler: handler as PluginHookRegistration["handler"] };
30
- }
31
-
32
- /**
33
- * Creates a typed after-hook registration for plugins.
34
- *
35
- * @example
36
- * ```typescript
37
- * hooks: () => [
38
- * afterHook<{ id: string; grandTotal: number }>("orders.afterCreate", async ({ result, context }) => {
39
- * await context.jobs.enqueue("loyalty:award-points", { orderId: result.id });
40
- * }),
41
- * ],
42
- * ```
43
- */
44
- export function afterHook<TData>(
45
- key: string,
46
- handler: (args: {
47
- data: TData | null;
48
- result: TData;
49
- operation: HookOperation;
50
- context: HookContext;
51
- }) => Promise<void> | void,
52
- ): PluginHookRegistration {
53
- return { key, handler: handler as PluginHookRegistration["handler"] };
54
- }