@mettlecast/domain-runtime 0.2.0 → 0.2.2

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.
@@ -47,4 +47,6 @@ export interface DomainContext {
47
47
  store: DomainStoreContext;
48
48
  /** Per-domain S3 file store, automatically scoped to the current tenant. */
49
49
  files: DomainFilesContext;
50
+ /** URL path parameters from the incoming request, excluding tenantId (e.g. { tableName: 'users' }). */
51
+ pathParams: Record<string, string>;
50
52
  }
package/dist/ctx/db.d.ts CHANGED
@@ -10,6 +10,19 @@ export interface DbContext {
10
10
  * `current_setting('app.current_tenant')`.
11
11
  */
12
12
  query: any;
13
+ /**
14
+ * Raw pg client for executing SQL that Drizzle cannot express, e.g.
15
+ * information_schema queries or complex DDL. Tenant-scoped session variable
16
+ * is already set before the handler receives this.
17
+ */
18
+ client: {
19
+ query(sql: string, params?: unknown[]): Promise<{
20
+ rows: unknown[];
21
+ fields: Array<{
22
+ name: string;
23
+ }>;
24
+ }>;
25
+ };
13
26
  /**
14
27
  * Release the underlying client back to the pool. Called by the runtime
15
28
  * after the handler finishes executing. Idempotent.
@@ -141,12 +141,14 @@ export function createApiLambdaHandler(api, options) {
141
141
  const idempotencyKey = event.headers?.['idempotency-key'] ?? event.headers?.['Idempotency-Key'];
142
142
  const httpMethod = event.requestContext?.http?.method ?? '';
143
143
  // 5. Hydrate context
144
+ const { tenantId: _tenantId, ...remainingPathParams } = event.pathParameters ?? {};
144
145
  const ctx = await hydrateCtx(event, {
145
146
  actor,
146
147
  tenant,
147
148
  databaseUrl: process.env['DATABASE_URL'],
148
149
  eventBusName: process.env['EVENT_BUS_NAME'],
149
150
  traceId,
151
+ pathParams: remainingPathParams,
150
152
  });
151
153
  // G5: After hydration, check idempotency cache for POST/PUT/PATCH
152
154
  if (idempotencyKey && ['POST', 'PUT', 'PATCH'].includes(httpMethod)) {
@@ -86,7 +86,7 @@ export async function createDb(options) {
86
86
  await pool.end();
87
87
  }
88
88
  };
89
- return { query: db, release };
89
+ return { query: db, client: client, release };
90
90
  }
91
91
  /**
92
92
  * Create a mock DbContext for unit tests. The release function is a no-op.
@@ -95,8 +95,9 @@ export async function createDb(options) {
95
95
  export function createMockDb() {
96
96
  return {
97
97
  query: {},
98
- release: async () => {
99
- /* no-op */
98
+ client: {
99
+ async query() { return { rows: [], fields: [] }; },
100
100
  },
101
+ release: async () => { },
101
102
  };
102
103
  }
@@ -108,6 +108,8 @@ export interface HydrateOptions {
108
108
  files?: DomainFilesContext;
109
109
  /** S3 bucket name for per-domain files. Defaults to process.env.DOMAIN_BUCKET_NAME. */
110
110
  domainBucketName?: string;
111
+ /** URL path parameters to expose via ctx.pathParams (tenantId already excluded by caller). */
112
+ pathParams?: Record<string, string>;
111
113
  }
112
114
  /**
113
115
  * Hydrates a fully populated DomainContext from a Lambda invocation event and options bag.
@@ -171,6 +171,7 @@ export async function hydrateCtx(_event, options = {}) {
171
171
  audit,
172
172
  store,
173
173
  files,
174
+ pathParams: options.pathParams ?? {},
174
175
  };
175
176
  return ctx;
176
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mettlecast/domain-runtime",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -54,6 +54,7 @@
54
54
  "@aws-lambda-powertools/logger": "^2.0.0",
55
55
  "@aws-lambda-powertools/metrics": "^2.0.0",
56
56
  "@aws-lambda-powertools/tracer": "^2.0.0",
57
+ "aws-lambda": "^1.0.0",
57
58
  "drizzle-orm": "*",
58
59
  "pg": "^8.0.0",
59
60
  "semver": "^7.0.0",