@autonoma-ai/sdk 0.1.0 → 0.1.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.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @autonoma-ai/sdk
2
+
3
+ Core protocol layer for the Autonoma Environment Factory. Handles HMAC verification, JWT-signed teardown tokens, template resolution, FK graph ordering, and the `discover`/`up`/`down` request lifecycle.
4
+
5
+ This package is the shared dependency of all ORM and server adapters — you don't need to install it directly unless you're building a custom adapter.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @autonoma-ai/sdk
11
+ ```
12
+
13
+ ## What's exported
14
+
15
+ ### `handleRequest(config, request)`
16
+
17
+ Main entry point. Routes `discover`, `up`, and `down` actions, verifies HMAC, and delegates to the ORM adapter.
18
+
19
+ ```typescript
20
+ import { handleRequest } from '@autonoma-ai/sdk'
21
+
22
+ const response = await handleRequest(config, { body, headers })
23
+ // { status: 200, body: { ... } }
24
+ ```
25
+
26
+ ### `checkScenario(adapter, scenario)`
27
+
28
+ Dry-run a scenario against a real database — full create-then-teardown cycle. Use this in integration tests to validate scenario data before deploying.
29
+
30
+ ```typescript
31
+ import { checkScenario } from '@autonoma-ai/sdk'
32
+
33
+ const result = await checkScenario(adapter, {
34
+ create: {
35
+ Organization: [{
36
+ name: 'Test [{{testRunId}}]',
37
+ slug: 'test-{{testRunId}}',
38
+ users: [{ email: 'admin-{{testRunId}}@test.com', name: 'Admin' }],
39
+ }],
40
+ },
41
+ })
42
+
43
+ // result.valid → true/false
44
+ // result.phase → 'ok' | 'up' | 'down'
45
+ // result.errors → [{ message, fix }]
46
+ // result.timing → { upMs, downMs }
47
+ ```
48
+
49
+ ### `checkAllScenarios(adapter, scenarios)`
50
+
51
+ Runs `checkScenario` for each scenario definition and returns all results.
52
+
53
+ ### Graph utilities (`@autonoma-ai/sdk/graph`)
54
+
55
+ Exported from the `/graph` subpath for use in ORM adapters:
56
+
57
+ ```typescript
58
+ import { topoSort, findDeferrableEdge } from '@autonoma-ai/sdk/graph'
59
+ ```
60
+
61
+ - `topoSort(edges)` — Kahn's algorithm + Tarjan's SCC for FK-ordered entity creation
62
+ - `findDeferrableEdge(scc, edges)` — finds a nullable FK in a cycle to break it
63
+
64
+ ### Other exports
65
+
66
+ | Export | Use |
67
+ |--------|-----|
68
+ | `signBody` / `verifySignature` | HMAC-SHA256 signing for request auth |
69
+ | `signRefs` / `verifyRefs` | JWT-like token for signing teardown refs |
70
+ | `resolveTemplate` | Resolve `{{testRunId}}`, `{{index}}`, `{{cycle(...)}}`, etc. |
71
+ | `resolveTree` | Nested scenario tree → flat entity list with auto-wired FKs |
72
+ | `fingerprint` | Deterministic hash of scenario definitions |
73
+
74
+ ## CLI
75
+
76
+ The package ships an `autonoma` CLI:
77
+
78
+ ```bash
79
+ # Validate a scenario against a schema
80
+ npx autonoma validate <schema.json> <scenario.json>
81
+
82
+ # Convert Prisma DMMF to autonoma-schema.json
83
+ npx autonoma schema convert <dmmf.json> --scope-field <field>
84
+ ```
85
+
86
+ ## Documentation
87
+
88
+ Full docs: [docs/](../../docs/) — start with [overview](../../docs/overview.txt) or read [everything in one file](../../docs/llms-full.txt).
@@ -6,6 +6,12 @@ interface OrmAdapter {
6
6
  createEntities(spec: Record<string, ResolvedEntitySpec>, context: CreateContext): Promise<Record<string, Record<string, unknown>[]>>;
7
7
  /** Delete all data scoped to a value. Refs are provided for targeted cleanup of un-scoped models. */
8
8
  teardown(scopeValue: string, refs?: Record<string, Record<string, unknown>[]>): Promise<void>;
9
+ /**
10
+ * Update a single record by ID. Used to backfill nullable FKs in circular
11
+ * dependency cycles (e.g. Application.mainBranchId after Branch is created).
12
+ * Optional — only required when circular FK relationships exist in the schema.
13
+ */
14
+ updateEntity?(model: string, id: string, fields: Record<string, unknown>): Promise<void>;
9
15
  }
10
16
  interface SchemaInfo {
11
17
  models: ModelInfo[];
package/dist/graph.d.ts CHANGED
@@ -1 +1 @@
1
- export { F as FKEdge, T as TopoSortResult, g as findDeferrableEdge, t as topoSort } from './graph-DpqVvKaD.js';
1
+ export { F as FKEdge, T as TopoSortResult, g as findDeferrableEdge, t as topoSort } from './graph-DmvFK17b.js';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { H as HandlerConfig, a as HandlerRequest, b as HandlerResponse, S as SchemaInfo, O as OrmAdapter, c as ScenarioDefinition } from './graph-DpqVvKaD.js';
2
- export { A as AuthResult, C as CreateContext, D as DiscoverResponse, d as DownResponse, F as FKEdge, e as FieldInfo, M as ModelInfo, R as ResolvedEntitySpec, f as SchemaRelation, U as UpResponse, g as findDeferrableEdge, t as topoSort } from './graph-DpqVvKaD.js';
1
+ import { H as HandlerConfig, a as HandlerRequest, b as HandlerResponse, S as SchemaInfo, O as OrmAdapter, c as ScenarioDefinition } from './graph-DmvFK17b.js';
2
+ export { A as AuthResult, C as CreateContext, D as DiscoverResponse, d as DownResponse, F as FKEdge, e as FieldInfo, M as ModelInfo, R as ResolvedEntitySpec, f as SchemaRelation, U as UpResponse, g as findDeferrableEdge, t as topoSort } from './graph-DmvFK17b.js';
3
3
 
4
4
  declare function handleRequest(config: HandlerConfig, req: HandlerRequest): Promise<HandlerResponse>;
5
5
 
@@ -43,9 +43,24 @@ interface CreateOp {
43
43
  tempId: string;
44
44
  batch: boolean;
45
45
  }
46
+ /**
47
+ * A deferred FK update — emitted when a _ref points to a node that hasn't
48
+ * been created yet (circular dependency). Resolved after all creates.
49
+ */
50
+ interface DeferredUpdate {
51
+ /** Temp ID of the record that needs to be updated */
52
+ targetTempId: string;
53
+ /** Model name of the record to update */
54
+ model: string;
55
+ /** Field on the record that holds the deferred FK */
56
+ field: string;
57
+ /** Alias that will resolve to the FK value once created */
58
+ refAlias: string;
59
+ }
46
60
  /** Result of resolving a tree scenario */
47
61
  interface ResolvedTree {
48
62
  ops: CreateOp[];
63
+ deferredUpdates: DeferredUpdate[];
49
64
  aliases: Map<string, string>;
50
65
  }
51
66
  /** A resolved reference to another node's id */
@@ -59,6 +74,10 @@ interface RefNode {
59
74
  * Handles both directions:
60
75
  * - FK on child (Application.organizationId → Organization): set child FK to parent ID
61
76
  * - FK on parent (Member.userId → User): create child first, set parent FK to child ID
77
+ *
78
+ * Circular FK cycles (e.g. Application.mainBranchId ↔ Branch.applicationId) are handled
79
+ * transparently: the nullable FK is omitted on the first create and emitted as a
80
+ * DeferredUpdate to be applied via UPDATE after all records exist.
62
81
  */
63
82
  declare function resolveTree(create: Record<string, Record<string, unknown>[]>, schema: SchemaInfo, testRunId: string): ResolvedTree;
64
83
 
package/dist/index.js CHANGED
@@ -125,6 +125,7 @@ function resolveTree(create, schema, testRunId) {
125
125
  }
126
126
  const aliases = /* @__PURE__ */ new Map();
127
127
  const ops = [];
128
+ const deferredUpdates = [];
128
129
  let tempCounter = 0;
129
130
  function makeTempId(model) {
130
131
  return `__temp_${model}_${tempCounter++}`;
@@ -151,7 +152,8 @@ function resolveTree(create, schema, testRunId) {
151
152
  const refAlias = value._ref;
152
153
  const refTempId = aliases.get(refAlias);
153
154
  if (!refTempId) {
154
- throw new Error(`_ref "${refAlias}" not found. Ensure the referenced node has _alias and is created before this one.`);
155
+ deferredUpdates.push({ targetTempId: tempId, model: modelName, field: key, refAlias });
156
+ continue;
155
157
  }
156
158
  fields[key] = refTempId;
157
159
  continue;
@@ -200,7 +202,7 @@ function resolveTree(create, schema, testRunId) {
200
202
  walkNode(modelName, nodes[i], null, null, false, i);
201
203
  }
202
204
  }
203
- return { ops, aliases };
205
+ return { ops, deferredUpdates, aliases };
204
206
  }
205
207
 
206
208
  // src/errors.ts
@@ -355,6 +357,22 @@ async function handleUp(config, body) {
355
357
  }
356
358
  i++;
357
359
  }
360
+ for (const deferred of tree.deferredUpdates) {
361
+ const realTargetId = idMap.get(deferred.targetTempId);
362
+ const refTempId = tree.aliases.get(deferred.refAlias);
363
+ const realRefId = refTempId ? idMap.get(refTempId) : void 0;
364
+ if (!realTargetId || !realRefId) {
365
+ throw new Error(
366
+ `_ref "${deferred.refAlias}" could not be resolved. Ensure the referenced node has _alias defined in the scenario.`
367
+ );
368
+ }
369
+ if (!config.adapter.updateEntity) {
370
+ throw new Error(
371
+ `Circular FK detected (${deferred.model}.${deferred.field}), but the ORM adapter does not implement updateEntity. Upgrade @autonoma-ai/sdk-prisma or @autonoma-ai/sdk-drizzle to a version that supports circular FK resolution.`
372
+ );
373
+ }
374
+ await config.adapter.updateEntity(deferred.model, realTargetId, { [deferred.field]: realRefId });
375
+ }
358
376
  const scopeValue = detectScopeValue(refs, schema.scopeField) ?? testRunId;
359
377
  const firstUser = findFirstUser(refs);
360
378
  let auth = { token: "" };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hmac.ts","../src/refs.ts","../src/template.ts","../src/tree.ts","../src/errors.ts","../src/handler.ts","../src/fingerprint.ts","../src/check.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto'\n\nexport function signBody(body: string, secret: string): string {\n return createHmac('sha256', secret).update(body).digest('hex')\n}\n\nexport function verifySignature(\n body: string,\n signature: string,\n secret: string,\n): boolean {\n const expected = signBody(body, secret)\n if (expected.length !== signature.length) return false\n return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))\n}\n","import { createHmac } from 'node:crypto'\n\ninterface RefsPayload {\n refs: Record<string, Record<string, unknown>[]>\n testRunId: string\n environment: string\n}\n\n/**\n * Sign refs into a JWT-like token (header.payload.signature).\n * Uses HMAC-SHA256 — not a full JWT library to avoid dependencies.\n */\nexport function signRefs(payload: RefsPayload, secret: string): string {\n const header = base64url({ alg: 'HS256', typ: 'REFS' })\n const body = base64url(payload)\n const signature = hmac(`${header}.${body}`, secret)\n return `${header}.${body}.${signature}`\n}\n\n/**\n * Verify and decode a refs token. Returns the payload or throws.\n */\nexport function verifyRefs(\n token: string,\n secret: string,\n): RefsPayload {\n const parts = token.split('.')\n if (parts.length !== 3) throw new Error('malformed token')\n\n const [header, body, signature] = parts\n const expected = hmac(`${header}.${body}`, secret)\n\n if (expected !== signature) throw new Error('signature mismatch')\n\n return JSON.parse(Buffer.from(body!, 'base64url').toString())\n}\n\nfunction base64url(obj: unknown): string {\n return Buffer.from(JSON.stringify(obj)).toString('base64url')\n}\n\nfunction hmac(data: string, secret: string): string {\n return createHmac('sha256', secret).update(data).digest('base64url')\n}\n","const TEMPLATE_RE = /\\{\\{(.+?)\\}\\}/g\n\nexport interface TemplateContext {\n testRunId: string\n index: number\n}\n\n/**\n * Resolve all {{...}} expressions in a value. Handles strings, objects, and arrays recursively.\n */\nexport function resolveTemplate(value: unknown, ctx: TemplateContext): unknown {\n if (typeof value === 'string') return resolveString(value, ctx)\n if (Array.isArray(value)) return value.map((v) => resolveTemplate(v, ctx))\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = resolveTemplate(v, ctx)\n }\n return result\n }\n return value\n}\n\nfunction resolveString(str: string, ctx: TemplateContext): unknown {\n // If the entire string is a single expression, return the raw value (preserving type)\n const fullMatch = str.match(/^\\{\\{(.+?)\\}\\}$/)\n if (fullMatch) {\n return evaluateExpression(fullMatch[1]!, ctx)\n }\n\n // Otherwise, interpolate expressions into the string\n return str.replace(TEMPLATE_RE, (_, expr: string) => {\n const val = evaluateExpression(expr, ctx)\n return String(val)\n })\n}\n\nfunction evaluateExpression(expr: string, ctx: TemplateContext): unknown {\n expr = expr.trim()\n\n // Simple variables\n if (expr === 'testRunId') return ctx.testRunId\n if (expr === 'index') return ctx.index\n if (expr === 'index1') return ctx.index + 1\n\n // cycle([...])\n const cycleMatch = expr.match(/^cycle\\(\\[(.+)\\]\\)$/)\n if (cycleMatch) {\n const items = parseArrayLiteral(cycleMatch[1]!)\n return items[ctx.index % items.length]\n }\n\n // pick([...])\n const pickMatch = expr.match(/^pick\\(\\[(.+)\\]\\)$/)\n if (pickMatch) {\n const items = parseArrayLiteral(pickMatch[1]!)\n return items[Math.floor(Math.random() * items.length)]\n }\n\n // random.int(a,b)\n const randIntMatch = expr.match(/^random\\.int\\((\\d+),\\s*(\\d+)\\)$/)\n if (randIntMatch) {\n const min = parseInt(randIntMatch[1]!, 10)\n const max = parseInt(randIntMatch[2]!, 10)\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n // random.float(a,b)\n const randFloatMatch = expr.match(/^random\\.float\\((\\d+(?:\\.\\d+)?),\\s*(\\d+(?:\\.\\d+)?)\\)$/)\n if (randFloatMatch) {\n const min = parseFloat(randFloatMatch[1]!)\n const max = parseFloat(randFloatMatch[2]!)\n return Math.random() * (max - min) + min\n }\n\n // now()\n if (expr === 'now()') return new Date().toISOString()\n\n // daysAgo(n)\n const daysAgoMatch = expr.match(/^daysAgo\\((\\d+)\\)$/)\n if (daysAgoMatch) {\n const d = new Date()\n d.setDate(d.getDate() - parseInt(daysAgoMatch[1]!, 10))\n return d.toISOString()\n }\n\n throw new Error(`Template error: unknown expression '${expr}'`)\n}\n\nfunction parseArrayLiteral(raw: string): string[] {\n return raw.split(',').map((s) => {\n s = s.trim()\n // Strip surrounding quotes\n if ((s.startsWith(\"'\") && s.endsWith(\"'\")) || (s.startsWith('\"') && s.endsWith('\"'))) {\n return s.slice(1, -1)\n }\n return s\n })\n}\n","import type { SchemaInfo, SchemaRelation } from './types'\nimport { resolveTemplate, type TemplateContext } from './template'\n\nconst RESERVED_KEYS = new Set(['_alias', '_ref', '_count', '_batch'])\n\n/** A create operation produced by the tree resolver */\nexport interface CreateOp {\n model: string\n fields: Record<string, unknown>\n tempId: string\n batch: boolean\n}\n\n/** Result of resolving a tree scenario */\nexport interface ResolvedTree {\n ops: CreateOp[]\n aliases: Map<string, string>\n}\n\n/** A resolved reference to another node's id */\nexport interface RefNode {\n _ref: string\n}\n\n/**\n * Resolve a nested scenario tree into an ordered list of create operations.\n *\n * Walks depth-first. Parent-child FKs are wired automatically.\n * Handles both directions:\n * - FK on child (Application.organizationId → Organization): set child FK to parent ID\n * - FK on parent (Member.userId → User): create child first, set parent FK to child ID\n */\nexport function resolveTree(\n create: Record<string, Record<string, unknown>[]>,\n schema: SchemaInfo,\n testRunId: string,\n): ResolvedTree {\n const relationByParentField = new Map<string, SchemaRelation>()\n for (const rel of schema.relations) {\n relationByParentField.set(`${rel.parentModel}.${rel.parentField}`, rel)\n }\n\n // Determine FK direction for each relation:\n // Is childField on the parent model or the child model?\n const fkOnParent = new Set<string>() // key: \"parentModel.parentField\"\n for (const rel of schema.relations) {\n const edge = schema.edges.find(\n (e) => e.localField === rel.childField && (e.from === rel.parentModel || e.from === rel.childModel),\n )\n if (edge && edge.from === rel.parentModel) {\n // FK column is on the parent model → create child first, then set parent FK\n fkOnParent.add(`${rel.parentModel}.${rel.parentField}`)\n }\n }\n\n const aliases = new Map<string, string>()\n const ops: CreateOp[] = []\n let tempCounter = 0\n\n function makeTempId(model: string): string {\n return `__temp_${model}_${tempCounter++}`\n }\n\n function walkNode(\n modelName: string,\n node: Record<string, unknown>,\n parentTempId: string | null,\n parentRelation: SchemaRelation | null,\n parentFkOnParent: boolean,\n index: number,\n ): string {\n const fields: Record<string, unknown> = {}\n const preChildren: Array<{ relation: SchemaRelation; value: unknown; fkOnParent: boolean }> = []\n const postChildren: Array<{ relation: SchemaRelation; value: unknown; fkOnParent: boolean }> = []\n const alias = node._alias as string | undefined\n const tempId = makeTempId(modelName)\n\n for (const [key, value] of Object.entries(node)) {\n if (RESERVED_KEYS.has(key)) continue\n\n const relation = relationByParentField.get(`${modelName}.${key}`)\n if (relation) {\n const isOnParent = fkOnParent.has(`${modelName}.${key}`)\n if (isOnParent) {\n // FK is on this model → need to create the child BEFORE this node\n preChildren.push({ relation, value, fkOnParent: true })\n } else {\n // FK is on the child → create child AFTER this node (normal)\n postChildren.push({ relation, value, fkOnParent: false })\n }\n continue\n }\n\n if (value && typeof value === 'object' && '_ref' in value) {\n const refAlias = (value as RefNode)._ref\n const refTempId = aliases.get(refAlias)\n if (!refTempId) {\n throw new Error(`_ref \"${refAlias}\" not found. Ensure the referenced node has _alias and is created before this one.`)\n }\n fields[key] = refTempId\n continue\n }\n\n const ctx: TemplateContext = { testRunId, index, }\n fields[key] = resolveTemplate(value, ctx)\n }\n\n // Wire FK to parent (if this node is a child and FK is on the child)\n if (parentRelation && parentTempId && !parentFkOnParent) {\n fields[parentRelation.childField] = parentTempId\n }\n\n // Process pre-children: these need to be created BEFORE this node\n // because this node's FK points to them\n for (const { relation, value, fkOnParent: isOnParent } of preChildren) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const childTempId = walkNode(relation.childModel, value[i] as Record<string, unknown>, tempId, relation, true, i)\n // Set this node's FK to point to the created child\n fields[relation.childField] = childTempId\n }\n }\n }\n\n // Create this node\n ops.push({ model: modelName, fields, tempId, batch: false })\n if (alias) aliases.set(alias, tempId)\n\n // Process post-children: normal case, FK is on the child\n for (const { relation, value } of postChildren) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n walkNode(relation.childModel, value[i] as Record<string, unknown>, tempId, relation, false, i)\n }\n } else if (value && typeof value === 'object' && '_count' in value) {\n const bulk = value as Record<string, unknown>\n const count = bulk._count as number\n const isBatch = (bulk._batch as boolean) ?? false\n\n for (let i = 0; i < count; i++) {\n const bulkFields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(bulk)) {\n if (k === '_count' || k === '_batch') continue\n const ctx: TemplateContext = { testRunId, index: i, }\n bulkFields[k] = resolveTemplate(v, ctx)\n }\n bulkFields[relation.childField] = tempId\n ops.push({ model: relation.childModel, fields: bulkFields, tempId: makeTempId(relation.childModel), batch: isBatch })\n }\n }\n }\n\n return tempId\n }\n\n for (const [modelName, nodes] of Object.entries(create)) {\n for (let i = 0; i < nodes.length; i++) {\n walkNode(modelName, nodes[i]!, null, null, false, i)\n }\n }\n\n return { ops, aliases }\n}\n","export class AutonomaError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number,\n ) {\n super(message)\n this.name = 'AutonomaError'\n }\n}\n\nexport const Errors = {\n unknownAction(action: string) {\n return new AutonomaError(\n `Unknown action: ${action}`,\n 'UNKNOWN_ACTION',\n 400,\n )\n },\n unknownEnvironment(name: string) {\n return new AutonomaError(\n `Unknown environment: ${name}`,\n 'UNKNOWN_ENVIRONMENT',\n 400,\n )\n },\n invalidSignature() {\n return new AutonomaError(\n 'Invalid HMAC signature',\n 'INVALID_SIGNATURE',\n 401,\n )\n },\n invalidRefsToken(reason: string) {\n return new AutonomaError(\n `Invalid refs token: ${reason}`,\n 'INVALID_REFS_TOKEN',\n 403,\n )\n },\n productionBlocked() {\n return new AutonomaError(\n 'Environment factory is disabled in production',\n 'PRODUCTION_BLOCKED',\n 404,\n )\n },\n invalidBody(reason: string) {\n return new AutonomaError(\n `Invalid request body: ${reason}`,\n 'INVALID_BODY',\n 400,\n )\n },\n} as const\n","import type {\n HandlerConfig,\n HandlerRequest,\n HandlerResponse,\n CreateContext,\n ResolvedEntitySpec,\n} from './types'\nimport { verifySignature } from './hmac'\nimport { signRefs, verifyRefs } from './refs'\nimport { resolveTree } from './tree'\nimport { AutonomaError, Errors } from './errors'\n\nexport async function handleRequest(\n config: HandlerConfig,\n req: HandlerRequest,\n): Promise<HandlerResponse> {\n try {\n if (config.sharedSecret === config.signingSecret) {\n throw new AutonomaError(\n 'sharedSecret and signingSecret must be different. The shared secret is known by Autonoma; the signing secret must be private.',\n 'SAME_SECRETS',\n 500,\n )\n }\n\n if (!config.allowProduction && process.env.NODE_ENV === 'production') {\n throw Errors.productionBlocked()\n }\n\n const signature = req.headers['x-signature'] ?? req.headers['X-Signature'] ?? ''\n if (!verifySignature(req.body, signature, config.sharedSecret)) {\n throw Errors.invalidSignature()\n }\n\n let body: Record<string, unknown>\n try {\n body = JSON.parse(req.body)\n } catch {\n throw Errors.invalidBody('invalid JSON')\n }\n\n const action = body.action as string\n if (!action) throw Errors.invalidBody('missing action')\n\n switch (action) {\n case 'discover':\n return handleDiscover(config)\n case 'up':\n return await handleUp(config, body)\n case 'down':\n return await handleDown(config, body)\n default:\n throw Errors.unknownAction(action)\n }\n } catch (err) {\n if (err instanceof AutonomaError) {\n return { status: err.status, body: { error: err.message, code: err.code } }\n }\n const message = err instanceof Error ? err.message : 'Internal error'\n return { status: 500, body: { error: message, code: 'INTERNAL_ERROR' } }\n }\n}\n\nfunction handleDiscover(config: HandlerConfig): HandlerResponse {\n const schema = config.adapter.getSchema()\n return { status: 200, body: { schema } }\n}\n\nasync function handleUp(\n config: HandlerConfig,\n body: Record<string, unknown>,\n): Promise<HandlerResponse> {\n const create = body.create as Record<string, Record<string, unknown>[]> | undefined\n if (!create) throw Errors.invalidBody('missing \"create\" in request body')\n\n const testRunId = (body.testRunId as string) ?? crypto.randomUUID()\n const schema = config.adapter.getSchema()\n\n const tree = resolveTree(create, schema, testRunId)\n const refs: Record<string, Record<string, unknown>[]> = {}\n const idMap = new Map<string, string>()\n\n let i = 0\n while (i < tree.ops.length) {\n const op = tree.ops[i]!\n const model = op.model\n\n // Collect consecutive ops for the same model with same batch flag\n const batch: typeof tree.ops = [op]\n while (i + 1 < tree.ops.length && tree.ops[i + 1]!.model === model && tree.ops[i + 1]!.batch === op.batch) {\n i++\n batch.push(tree.ops[i]!)\n }\n\n // Replace temp IDs with real IDs in all fields\n const resolvedFields = batch.map((b) => {\n const fields = { ...b.fields }\n delete fields.id\n for (const [key, value] of Object.entries(fields)) {\n if (typeof value === 'string' && value.startsWith('__temp_')) {\n const realId = idMap.get(value)\n if (realId) fields[key] = realId\n }\n }\n // Inject scope field if applicable\n const scopeEdge = schema.edges.find(\n (e) => e.from === model && e.localField.toLowerCase() === schema.scopeField.toLowerCase() && e.from !== e.to,\n )\n if (scopeEdge && !(scopeEdge.localField in fields)) {\n const scopeVal = detectScopeValue(refs, schema.scopeField)\n if (scopeVal) fields[scopeEdge.localField] = scopeVal\n }\n return fields\n })\n\n const spec: Record<string, ResolvedEntitySpec> = {\n [model]: { count: resolvedFields.length, fields: resolvedFields, batch: op.batch },\n }\n\n const context: CreateContext = { testRunId, refs }\n const created = await config.adapter.createEntities(spec, context)\n const records = created[model] ?? []\n\n if (!refs[model]) refs[model] = []\n refs[model].push(...records)\n\n for (let j = 0; j < batch.length; j++) {\n const record = records[j]\n if (record && typeof record.id === 'string') {\n idMap.set(batch[j]!.tempId, record.id)\n }\n }\n\n i++\n }\n\n const scopeValue = detectScopeValue(refs, schema.scopeField) ?? testRunId\n\n const firstUser = findFirstUser(refs)\n let auth = { token: '' }\n if (config.auth && firstUser) {\n auth = await config.auth(firstUser)\n }\n\n const refsToken = signRefs(\n { refs, testRunId: scopeValue, environment: '' },\n config.signingSecret,\n )\n\n return { status: 200, body: { auth, refs, refsToken } }\n}\n\nasync function handleDown(\n config: HandlerConfig,\n body: Record<string, unknown>,\n): Promise<HandlerResponse> {\n const refsToken = body.refsToken as string\n if (!refsToken) throw Errors.invalidBody('missing refsToken')\n\n let payload: ReturnType<typeof verifyRefs>\n try {\n payload = verifyRefs(refsToken, config.signingSecret)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'invalid token'\n throw Errors.invalidRefsToken(message)\n }\n\n await config.adapter.teardown(payload.testRunId, payload.refs)\n\n return { status: 200, body: { ok: true } }\n}\n\nfunction findFirstUser(\n refs: Record<string, Record<string, unknown>[]>,\n): Record<string, unknown> | null {\n for (const [model, records] of Object.entries(refs)) {\n if (model.toLowerCase() === 'user' && records.length > 0) {\n return records[0]!\n }\n }\n return null\n}\n\nfunction detectScopeValue(\n refs: Record<string, Record<string, unknown>[]>,\n scopeField: string,\n): string | null {\n const scopeLower = scopeField.toLowerCase()\n for (const records of Object.values(refs)) {\n for (const record of records) {\n for (const [key, value] of Object.entries(record)) {\n if (key.toLowerCase() === scopeLower && typeof value === 'string') {\n return value\n }\n }\n }\n }\n return null\n}\n","import { createHash } from 'node:crypto'\n\n/**\n * Compute a stable 16-char hex fingerprint of a scenario definition.\n * Uses sha256 of the JSON-serialized spec with sorted keys.\n */\nexport function fingerprint(value: unknown): string {\n const json = JSON.stringify(value, sortReplacer)\n return createHash('sha256').update(json).digest('hex').slice(0, 16)\n}\n\n/**\n * JSON replacer that sorts object keys for deterministic serialization.\n */\nfunction sortReplacer(_key: string, value: unknown): unknown {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return Object.keys(value as Record<string, unknown>)\n .sort()\n .reduce(\n (sorted, k) => {\n sorted[k] = (value as Record<string, unknown>)[k]\n return sorted\n },\n {} as Record<string, unknown>,\n )\n }\n return value\n}\n","import type {\n OrmAdapter,\n ScenarioDefinition,\n HandlerConfig,\n} from './types'\nimport { handleRequest } from './handler'\nimport { signBody } from './hmac'\n\nexport interface CheckResult {\n valid: boolean\n phase: 'up' | 'down' | 'ok'\n errors: CheckError[]\n timing?: { upMs: number; downMs: number }\n}\n\nexport interface CheckError {\n phase: 'up' | 'down'\n message: string\n fix?: string\n}\n\n/**\n * Dry-run a scenario against a real database.\n * Runs the full up → down cycle and returns structured errors.\n */\nexport async function checkScenario(\n adapter: OrmAdapter,\n scenario: ScenarioDefinition,\n options?: { sharedSecret?: string; signingSecret?: string; auth?: HandlerConfig['auth'] },\n): Promise<CheckResult> {\n const sharedSecret = options?.sharedSecret ?? 'autonoma-check-shared'\n const signingSecret = options?.signingSecret ?? 'autonoma-check-signing'\n\n const config: HandlerConfig = {\n adapter,\n sharedSecret,\n signingSecret,\n auth: options?.auth ?? (async () => ({ token: 'check-token' })),\n }\n\n // Up\n const upBody = JSON.stringify({ action: 'up', create: scenario.create })\n const upReq = {\n body: upBody,\n headers: { 'x-signature': signBody(upBody, sharedSecret) },\n }\n\n const t0 = performance.now()\n const upRes = await handleRequest(config, upReq)\n const upMs = Math.round(performance.now() - t0)\n\n if (upRes.status !== 200) {\n const errorMsg = (upRes.body as Record<string, string>).error ?? 'Unknown error'\n return {\n valid: false,\n phase: 'up',\n errors: [{ phase: 'up', message: errorMsg, fix: suggestFix(errorMsg) }],\n timing: { upMs, downMs: 0 },\n }\n }\n\n // Down\n const refsToken = (upRes.body as Record<string, string>).refsToken\n const downBody = JSON.stringify({ action: 'down', refsToken })\n const downReq = {\n body: downBody,\n headers: { 'x-signature': signBody(downBody, sharedSecret) },\n }\n\n const t1 = performance.now()\n const downRes = await handleRequest(config, downReq)\n const downMs = Math.round(performance.now() - t1)\n\n if (downRes.status !== 200) {\n const errorMsg = (downRes.body as Record<string, string>).error ?? 'Unknown error'\n return {\n valid: false,\n phase: 'down',\n errors: [{ phase: 'down', message: errorMsg }],\n timing: { upMs, downMs },\n }\n }\n\n return { valid: true, phase: 'ok', errors: [], timing: { upMs, downMs } }\n}\n\n/**\n * Check multiple scenarios sequentially.\n */\nexport async function checkAllScenarios(\n adapter: OrmAdapter,\n scenarios: ScenarioDefinition[],\n options?: { sharedSecret?: string; signingSecret?: string; auth?: HandlerConfig['auth'] },\n): Promise<CheckResult[]> {\n const results: CheckResult[] = []\n for (const scenario of scenarios) {\n results.push(await checkScenario(adapter, scenario, options))\n }\n return results\n}\n\nfunction suggestFix(errorMsg: string): string {\n if (errorMsg.includes('Unique constraint failed')) {\n const match = errorMsg.match(/fields: \\(`(.+?)`\\)/)\n if (match) return `Unique constraint on (${match[1]}). Add {{testRunId}} or {{index}} to make values unique.`\n return 'Unique constraint violation. Make field values unique across instances.'\n }\n if (errorMsg.includes('Foreign key constraint')) {\n return 'A referenced record does not exist. Check that parent entities are nested correctly.'\n }\n if (errorMsg.includes('Unknown argument')) {\n const match = errorMsg.match(/Unknown argument `(\\w+)`/)\n if (match) return `Field \"${match[1]}\" does not exist on this model. Remove it.`\n }\n if (errorMsg.includes('must not be null')) {\n return 'A required field is null. Add it to the node with a value.'\n }\n return ''\n}\n"],"mappings":"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","names":["createHmac"]}
1
+ {"version":3,"sources":["../src/hmac.ts","../src/refs.ts","../src/template.ts","../src/tree.ts","../src/errors.ts","../src/handler.ts","../src/fingerprint.ts","../src/check.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto'\n\nexport function signBody(body: string, secret: string): string {\n return createHmac('sha256', secret).update(body).digest('hex')\n}\n\nexport function verifySignature(\n body: string,\n signature: string,\n secret: string,\n): boolean {\n const expected = signBody(body, secret)\n if (expected.length !== signature.length) return false\n return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))\n}\n","import { createHmac } from 'node:crypto'\n\ninterface RefsPayload {\n refs: Record<string, Record<string, unknown>[]>\n testRunId: string\n environment: string\n}\n\n/**\n * Sign refs into a JWT-like token (header.payload.signature).\n * Uses HMAC-SHA256 — not a full JWT library to avoid dependencies.\n */\nexport function signRefs(payload: RefsPayload, secret: string): string {\n const header = base64url({ alg: 'HS256', typ: 'REFS' })\n const body = base64url(payload)\n const signature = hmac(`${header}.${body}`, secret)\n return `${header}.${body}.${signature}`\n}\n\n/**\n * Verify and decode a refs token. Returns the payload or throws.\n */\nexport function verifyRefs(\n token: string,\n secret: string,\n): RefsPayload {\n const parts = token.split('.')\n if (parts.length !== 3) throw new Error('malformed token')\n\n const [header, body, signature] = parts\n const expected = hmac(`${header}.${body}`, secret)\n\n if (expected !== signature) throw new Error('signature mismatch')\n\n return JSON.parse(Buffer.from(body!, 'base64url').toString())\n}\n\nfunction base64url(obj: unknown): string {\n return Buffer.from(JSON.stringify(obj)).toString('base64url')\n}\n\nfunction hmac(data: string, secret: string): string {\n return createHmac('sha256', secret).update(data).digest('base64url')\n}\n","const TEMPLATE_RE = /\\{\\{(.+?)\\}\\}/g\n\nexport interface TemplateContext {\n testRunId: string\n index: number\n}\n\n/**\n * Resolve all {{...}} expressions in a value. Handles strings, objects, and arrays recursively.\n */\nexport function resolveTemplate(value: unknown, ctx: TemplateContext): unknown {\n if (typeof value === 'string') return resolveString(value, ctx)\n if (Array.isArray(value)) return value.map((v) => resolveTemplate(v, ctx))\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = resolveTemplate(v, ctx)\n }\n return result\n }\n return value\n}\n\nfunction resolveString(str: string, ctx: TemplateContext): unknown {\n // If the entire string is a single expression, return the raw value (preserving type)\n const fullMatch = str.match(/^\\{\\{(.+?)\\}\\}$/)\n if (fullMatch) {\n return evaluateExpression(fullMatch[1]!, ctx)\n }\n\n // Otherwise, interpolate expressions into the string\n return str.replace(TEMPLATE_RE, (_, expr: string) => {\n const val = evaluateExpression(expr, ctx)\n return String(val)\n })\n}\n\nfunction evaluateExpression(expr: string, ctx: TemplateContext): unknown {\n expr = expr.trim()\n\n // Simple variables\n if (expr === 'testRunId') return ctx.testRunId\n if (expr === 'index') return ctx.index\n if (expr === 'index1') return ctx.index + 1\n\n // cycle([...])\n const cycleMatch = expr.match(/^cycle\\(\\[(.+)\\]\\)$/)\n if (cycleMatch) {\n const items = parseArrayLiteral(cycleMatch[1]!)\n return items[ctx.index % items.length]\n }\n\n // pick([...])\n const pickMatch = expr.match(/^pick\\(\\[(.+)\\]\\)$/)\n if (pickMatch) {\n const items = parseArrayLiteral(pickMatch[1]!)\n return items[Math.floor(Math.random() * items.length)]\n }\n\n // random.int(a,b)\n const randIntMatch = expr.match(/^random\\.int\\((\\d+),\\s*(\\d+)\\)$/)\n if (randIntMatch) {\n const min = parseInt(randIntMatch[1]!, 10)\n const max = parseInt(randIntMatch[2]!, 10)\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n // random.float(a,b)\n const randFloatMatch = expr.match(/^random\\.float\\((\\d+(?:\\.\\d+)?),\\s*(\\d+(?:\\.\\d+)?)\\)$/)\n if (randFloatMatch) {\n const min = parseFloat(randFloatMatch[1]!)\n const max = parseFloat(randFloatMatch[2]!)\n return Math.random() * (max - min) + min\n }\n\n // now()\n if (expr === 'now()') return new Date().toISOString()\n\n // daysAgo(n)\n const daysAgoMatch = expr.match(/^daysAgo\\((\\d+)\\)$/)\n if (daysAgoMatch) {\n const d = new Date()\n d.setDate(d.getDate() - parseInt(daysAgoMatch[1]!, 10))\n return d.toISOString()\n }\n\n throw new Error(`Template error: unknown expression '${expr}'`)\n}\n\nfunction parseArrayLiteral(raw: string): string[] {\n return raw.split(',').map((s) => {\n s = s.trim()\n // Strip surrounding quotes\n if ((s.startsWith(\"'\") && s.endsWith(\"'\")) || (s.startsWith('\"') && s.endsWith('\"'))) {\n return s.slice(1, -1)\n }\n return s\n })\n}\n","import type { SchemaInfo, SchemaRelation } from './types'\nimport { resolveTemplate, type TemplateContext } from './template'\n\nconst RESERVED_KEYS = new Set(['_alias', '_ref', '_count', '_batch'])\n\n/** A create operation produced by the tree resolver */\nexport interface CreateOp {\n model: string\n fields: Record<string, unknown>\n tempId: string\n batch: boolean\n}\n\n/**\n * A deferred FK update — emitted when a _ref points to a node that hasn't\n * been created yet (circular dependency). Resolved after all creates.\n */\nexport interface DeferredUpdate {\n /** Temp ID of the record that needs to be updated */\n targetTempId: string\n /** Model name of the record to update */\n model: string\n /** Field on the record that holds the deferred FK */\n field: string\n /** Alias that will resolve to the FK value once created */\n refAlias: string\n}\n\n/** Result of resolving a tree scenario */\nexport interface ResolvedTree {\n ops: CreateOp[]\n deferredUpdates: DeferredUpdate[]\n aliases: Map<string, string>\n}\n\n/** A resolved reference to another node's id */\nexport interface RefNode {\n _ref: string\n}\n\n/**\n * Resolve a nested scenario tree into an ordered list of create operations.\n *\n * Walks depth-first. Parent-child FKs are wired automatically.\n * Handles both directions:\n * - FK on child (Application.organizationId → Organization): set child FK to parent ID\n * - FK on parent (Member.userId → User): create child first, set parent FK to child ID\n *\n * Circular FK cycles (e.g. Application.mainBranchId ↔ Branch.applicationId) are handled\n * transparently: the nullable FK is omitted on the first create and emitted as a\n * DeferredUpdate to be applied via UPDATE after all records exist.\n */\nexport function resolveTree(\n create: Record<string, Record<string, unknown>[]>,\n schema: SchemaInfo,\n testRunId: string,\n): ResolvedTree {\n const relationByParentField = new Map<string, SchemaRelation>()\n for (const rel of schema.relations) {\n relationByParentField.set(`${rel.parentModel}.${rel.parentField}`, rel)\n }\n\n // Determine FK direction for each relation:\n // Is childField on the parent model or the child model?\n const fkOnParent = new Set<string>() // key: \"parentModel.parentField\"\n for (const rel of schema.relations) {\n const edge = schema.edges.find(\n (e) => e.localField === rel.childField && (e.from === rel.parentModel || e.from === rel.childModel),\n )\n if (edge && edge.from === rel.parentModel) {\n // FK column is on the parent model → create child first, then set parent FK\n fkOnParent.add(`${rel.parentModel}.${rel.parentField}`)\n }\n }\n\n const aliases = new Map<string, string>()\n const ops: CreateOp[] = []\n const deferredUpdates: DeferredUpdate[] = []\n let tempCounter = 0\n\n function makeTempId(model: string): string {\n return `__temp_${model}_${tempCounter++}`\n }\n\n function walkNode(\n modelName: string,\n node: Record<string, unknown>,\n parentTempId: string | null,\n parentRelation: SchemaRelation | null,\n parentFkOnParent: boolean,\n index: number,\n ): string {\n const fields: Record<string, unknown> = {}\n const preChildren: Array<{ relation: SchemaRelation; value: unknown; fkOnParent: boolean }> = []\n const postChildren: Array<{ relation: SchemaRelation; value: unknown; fkOnParent: boolean }> = []\n const alias = node._alias as string | undefined\n const tempId = makeTempId(modelName)\n\n for (const [key, value] of Object.entries(node)) {\n if (RESERVED_KEYS.has(key)) continue\n\n const relation = relationByParentField.get(`${modelName}.${key}`)\n if (relation) {\n const isOnParent = fkOnParent.has(`${modelName}.${key}`)\n if (isOnParent) {\n // FK is on this model → need to create the child BEFORE this node\n preChildren.push({ relation, value, fkOnParent: true })\n } else {\n // FK is on the child → create child AFTER this node (normal)\n postChildren.push({ relation, value, fkOnParent: false })\n }\n continue\n }\n\n if (value && typeof value === 'object' && '_ref' in value) {\n const refAlias = (value as RefNode)._ref\n const refTempId = aliases.get(refAlias)\n if (!refTempId) {\n // Alias not created yet — defer this FK as an UPDATE after all creates.\n // This handles circular FK cycles (e.g. Application.mainBranchId → Branch\n // where Branch.applicationId → Application).\n deferredUpdates.push({ targetTempId: tempId, model: modelName, field: key, refAlias })\n continue\n }\n fields[key] = refTempId\n continue\n }\n\n const ctx: TemplateContext = { testRunId, index, }\n fields[key] = resolveTemplate(value, ctx)\n }\n\n // Wire FK to parent (if this node is a child and FK is on the child)\n if (parentRelation && parentTempId && !parentFkOnParent) {\n fields[parentRelation.childField] = parentTempId\n }\n\n // Process pre-children: these need to be created BEFORE this node\n // because this node's FK points to them\n for (const { relation, value, fkOnParent: isOnParent } of preChildren) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const childTempId = walkNode(relation.childModel, value[i] as Record<string, unknown>, tempId, relation, true, i)\n // Set this node's FK to point to the created child\n fields[relation.childField] = childTempId\n }\n }\n }\n\n // Create this node\n ops.push({ model: modelName, fields, tempId, batch: false })\n if (alias) aliases.set(alias, tempId)\n\n // Process post-children: normal case, FK is on the child\n for (const { relation, value } of postChildren) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n walkNode(relation.childModel, value[i] as Record<string, unknown>, tempId, relation, false, i)\n }\n } else if (value && typeof value === 'object' && '_count' in value) {\n const bulk = value as Record<string, unknown>\n const count = bulk._count as number\n const isBatch = (bulk._batch as boolean) ?? false\n\n for (let i = 0; i < count; i++) {\n const bulkFields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(bulk)) {\n if (k === '_count' || k === '_batch') continue\n const ctx: TemplateContext = { testRunId, index: i, }\n bulkFields[k] = resolveTemplate(v, ctx)\n }\n bulkFields[relation.childField] = tempId\n ops.push({ model: relation.childModel, fields: bulkFields, tempId: makeTempId(relation.childModel), batch: isBatch })\n }\n }\n }\n\n return tempId\n }\n\n for (const [modelName, nodes] of Object.entries(create)) {\n for (let i = 0; i < nodes.length; i++) {\n walkNode(modelName, nodes[i]!, null, null, false, i)\n }\n }\n\n return { ops, deferredUpdates, aliases }\n}\n","export class AutonomaError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number,\n ) {\n super(message)\n this.name = 'AutonomaError'\n }\n}\n\nexport const Errors = {\n unknownAction(action: string) {\n return new AutonomaError(\n `Unknown action: ${action}`,\n 'UNKNOWN_ACTION',\n 400,\n )\n },\n unknownEnvironment(name: string) {\n return new AutonomaError(\n `Unknown environment: ${name}`,\n 'UNKNOWN_ENVIRONMENT',\n 400,\n )\n },\n invalidSignature() {\n return new AutonomaError(\n 'Invalid HMAC signature',\n 'INVALID_SIGNATURE',\n 401,\n )\n },\n invalidRefsToken(reason: string) {\n return new AutonomaError(\n `Invalid refs token: ${reason}`,\n 'INVALID_REFS_TOKEN',\n 403,\n )\n },\n productionBlocked() {\n return new AutonomaError(\n 'Environment factory is disabled in production',\n 'PRODUCTION_BLOCKED',\n 404,\n )\n },\n invalidBody(reason: string) {\n return new AutonomaError(\n `Invalid request body: ${reason}`,\n 'INVALID_BODY',\n 400,\n )\n },\n} as const\n","import type {\n HandlerConfig,\n HandlerRequest,\n HandlerResponse,\n CreateContext,\n ResolvedEntitySpec,\n} from './types'\nimport { verifySignature } from './hmac'\nimport { signRefs, verifyRefs } from './refs'\nimport { resolveTree } from './tree'\nimport { AutonomaError, Errors } from './errors'\n\nexport async function handleRequest(\n config: HandlerConfig,\n req: HandlerRequest,\n): Promise<HandlerResponse> {\n try {\n if (config.sharedSecret === config.signingSecret) {\n throw new AutonomaError(\n 'sharedSecret and signingSecret must be different. The shared secret is known by Autonoma; the signing secret must be private.',\n 'SAME_SECRETS',\n 500,\n )\n }\n\n if (!config.allowProduction && process.env.NODE_ENV === 'production') {\n throw Errors.productionBlocked()\n }\n\n const signature = req.headers['x-signature'] ?? req.headers['X-Signature'] ?? ''\n if (!verifySignature(req.body, signature, config.sharedSecret)) {\n throw Errors.invalidSignature()\n }\n\n let body: Record<string, unknown>\n try {\n body = JSON.parse(req.body)\n } catch {\n throw Errors.invalidBody('invalid JSON')\n }\n\n const action = body.action as string\n if (!action) throw Errors.invalidBody('missing action')\n\n switch (action) {\n case 'discover':\n return handleDiscover(config)\n case 'up':\n return await handleUp(config, body)\n case 'down':\n return await handleDown(config, body)\n default:\n throw Errors.unknownAction(action)\n }\n } catch (err) {\n if (err instanceof AutonomaError) {\n return { status: err.status, body: { error: err.message, code: err.code } }\n }\n const message = err instanceof Error ? err.message : 'Internal error'\n return { status: 500, body: { error: message, code: 'INTERNAL_ERROR' } }\n }\n}\n\nfunction handleDiscover(config: HandlerConfig): HandlerResponse {\n const schema = config.adapter.getSchema()\n return { status: 200, body: { schema } }\n}\n\nasync function handleUp(\n config: HandlerConfig,\n body: Record<string, unknown>,\n): Promise<HandlerResponse> {\n const create = body.create as Record<string, Record<string, unknown>[]> | undefined\n if (!create) throw Errors.invalidBody('missing \"create\" in request body')\n\n const testRunId = (body.testRunId as string) ?? crypto.randomUUID()\n const schema = config.adapter.getSchema()\n\n const tree = resolveTree(create, schema, testRunId)\n const refs: Record<string, Record<string, unknown>[]> = {}\n const idMap = new Map<string, string>()\n\n let i = 0\n while (i < tree.ops.length) {\n const op = tree.ops[i]!\n const model = op.model\n\n // Collect consecutive ops for the same model with same batch flag\n const batch: typeof tree.ops = [op]\n while (i + 1 < tree.ops.length && tree.ops[i + 1]!.model === model && tree.ops[i + 1]!.batch === op.batch) {\n i++\n batch.push(tree.ops[i]!)\n }\n\n // Replace temp IDs with real IDs in all fields\n const resolvedFields = batch.map((b) => {\n const fields = { ...b.fields }\n delete fields.id\n for (const [key, value] of Object.entries(fields)) {\n if (typeof value === 'string' && value.startsWith('__temp_')) {\n const realId = idMap.get(value)\n if (realId) fields[key] = realId\n }\n }\n // Inject scope field if applicable\n const scopeEdge = schema.edges.find(\n (e) => e.from === model && e.localField.toLowerCase() === schema.scopeField.toLowerCase() && e.from !== e.to,\n )\n if (scopeEdge && !(scopeEdge.localField in fields)) {\n const scopeVal = detectScopeValue(refs, schema.scopeField)\n if (scopeVal) fields[scopeEdge.localField] = scopeVal\n }\n return fields\n })\n\n const spec: Record<string, ResolvedEntitySpec> = {\n [model]: { count: resolvedFields.length, fields: resolvedFields, batch: op.batch },\n }\n\n const context: CreateContext = { testRunId, refs }\n const created = await config.adapter.createEntities(spec, context)\n const records = created[model] ?? []\n\n if (!refs[model]) refs[model] = []\n refs[model].push(...records)\n\n for (let j = 0; j < batch.length; j++) {\n const record = records[j]\n if (record && typeof record.id === 'string') {\n idMap.set(batch[j]!.tempId, record.id)\n }\n }\n\n i++\n }\n\n // Resolve deferred FK updates (circular dependency cycles)\n for (const deferred of tree.deferredUpdates) {\n const realTargetId = idMap.get(deferred.targetTempId)\n const refTempId = tree.aliases.get(deferred.refAlias)\n const realRefId = refTempId ? idMap.get(refTempId) : undefined\n\n if (!realTargetId || !realRefId) {\n throw new Error(\n `_ref \"${deferred.refAlias}\" could not be resolved. Ensure the referenced node has _alias defined in the scenario.`,\n )\n }\n\n if (!config.adapter.updateEntity) {\n throw new Error(\n `Circular FK detected (${deferred.model}.${deferred.field}), but the ORM adapter does not implement updateEntity. ` +\n `Upgrade @autonoma-ai/sdk-prisma or @autonoma-ai/sdk-drizzle to a version that supports circular FK resolution.`,\n )\n }\n\n await config.adapter.updateEntity(deferred.model, realTargetId, { [deferred.field]: realRefId })\n }\n\n const scopeValue = detectScopeValue(refs, schema.scopeField) ?? testRunId\n\n const firstUser = findFirstUser(refs)\n let auth = { token: '' }\n if (config.auth && firstUser) {\n auth = await config.auth(firstUser)\n }\n\n const refsToken = signRefs(\n { refs, testRunId: scopeValue, environment: '' },\n config.signingSecret,\n )\n\n return { status: 200, body: { auth, refs, refsToken } }\n}\n\nasync function handleDown(\n config: HandlerConfig,\n body: Record<string, unknown>,\n): Promise<HandlerResponse> {\n const refsToken = body.refsToken as string\n if (!refsToken) throw Errors.invalidBody('missing refsToken')\n\n let payload: ReturnType<typeof verifyRefs>\n try {\n payload = verifyRefs(refsToken, config.signingSecret)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'invalid token'\n throw Errors.invalidRefsToken(message)\n }\n\n await config.adapter.teardown(payload.testRunId, payload.refs)\n\n return { status: 200, body: { ok: true } }\n}\n\nfunction findFirstUser(\n refs: Record<string, Record<string, unknown>[]>,\n): Record<string, unknown> | null {\n for (const [model, records] of Object.entries(refs)) {\n if (model.toLowerCase() === 'user' && records.length > 0) {\n return records[0]!\n }\n }\n return null\n}\n\nfunction detectScopeValue(\n refs: Record<string, Record<string, unknown>[]>,\n scopeField: string,\n): string | null {\n const scopeLower = scopeField.toLowerCase()\n for (const records of Object.values(refs)) {\n for (const record of records) {\n for (const [key, value] of Object.entries(record)) {\n if (key.toLowerCase() === scopeLower && typeof value === 'string') {\n return value\n }\n }\n }\n }\n return null\n}\n","import { createHash } from 'node:crypto'\n\n/**\n * Compute a stable 16-char hex fingerprint of a scenario definition.\n * Uses sha256 of the JSON-serialized spec with sorted keys.\n */\nexport function fingerprint(value: unknown): string {\n const json = JSON.stringify(value, sortReplacer)\n return createHash('sha256').update(json).digest('hex').slice(0, 16)\n}\n\n/**\n * JSON replacer that sorts object keys for deterministic serialization.\n */\nfunction sortReplacer(_key: string, value: unknown): unknown {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return Object.keys(value as Record<string, unknown>)\n .sort()\n .reduce(\n (sorted, k) => {\n sorted[k] = (value as Record<string, unknown>)[k]\n return sorted\n },\n {} as Record<string, unknown>,\n )\n }\n return value\n}\n","import type {\n OrmAdapter,\n ScenarioDefinition,\n HandlerConfig,\n} from './types'\nimport { handleRequest } from './handler'\nimport { signBody } from './hmac'\n\nexport interface CheckResult {\n valid: boolean\n phase: 'up' | 'down' | 'ok'\n errors: CheckError[]\n timing?: { upMs: number; downMs: number }\n}\n\nexport interface CheckError {\n phase: 'up' | 'down'\n message: string\n fix?: string\n}\n\n/**\n * Dry-run a scenario against a real database.\n * Runs the full up → down cycle and returns structured errors.\n */\nexport async function checkScenario(\n adapter: OrmAdapter,\n scenario: ScenarioDefinition,\n options?: { sharedSecret?: string; signingSecret?: string; auth?: HandlerConfig['auth'] },\n): Promise<CheckResult> {\n const sharedSecret = options?.sharedSecret ?? 'autonoma-check-shared'\n const signingSecret = options?.signingSecret ?? 'autonoma-check-signing'\n\n const config: HandlerConfig = {\n adapter,\n sharedSecret,\n signingSecret,\n auth: options?.auth ?? (async () => ({ token: 'check-token' })),\n }\n\n // Up\n const upBody = JSON.stringify({ action: 'up', create: scenario.create })\n const upReq = {\n body: upBody,\n headers: { 'x-signature': signBody(upBody, sharedSecret) },\n }\n\n const t0 = performance.now()\n const upRes = await handleRequest(config, upReq)\n const upMs = Math.round(performance.now() - t0)\n\n if (upRes.status !== 200) {\n const errorMsg = (upRes.body as Record<string, string>).error ?? 'Unknown error'\n return {\n valid: false,\n phase: 'up',\n errors: [{ phase: 'up', message: errorMsg, fix: suggestFix(errorMsg) }],\n timing: { upMs, downMs: 0 },\n }\n }\n\n // Down\n const refsToken = (upRes.body as Record<string, string>).refsToken\n const downBody = JSON.stringify({ action: 'down', refsToken })\n const downReq = {\n body: downBody,\n headers: { 'x-signature': signBody(downBody, sharedSecret) },\n }\n\n const t1 = performance.now()\n const downRes = await handleRequest(config, downReq)\n const downMs = Math.round(performance.now() - t1)\n\n if (downRes.status !== 200) {\n const errorMsg = (downRes.body as Record<string, string>).error ?? 'Unknown error'\n return {\n valid: false,\n phase: 'down',\n errors: [{ phase: 'down', message: errorMsg }],\n timing: { upMs, downMs },\n }\n }\n\n return { valid: true, phase: 'ok', errors: [], timing: { upMs, downMs } }\n}\n\n/**\n * Check multiple scenarios sequentially.\n */\nexport async function checkAllScenarios(\n adapter: OrmAdapter,\n scenarios: ScenarioDefinition[],\n options?: { sharedSecret?: string; signingSecret?: string; auth?: HandlerConfig['auth'] },\n): Promise<CheckResult[]> {\n const results: CheckResult[] = []\n for (const scenario of scenarios) {\n results.push(await checkScenario(adapter, scenario, options))\n }\n return results\n}\n\nfunction suggestFix(errorMsg: string): string {\n if (errorMsg.includes('Unique constraint failed')) {\n const match = errorMsg.match(/fields: \\(`(.+?)`\\)/)\n if (match) return `Unique constraint on (${match[1]}). Add {{testRunId}} or {{index}} to make values unique.`\n return 'Unique constraint violation. Make field values unique across instances.'\n }\n if (errorMsg.includes('Foreign key constraint')) {\n return 'A referenced record does not exist. Check that parent entities are nested correctly.'\n }\n if (errorMsg.includes('Unknown argument')) {\n const match = errorMsg.match(/Unknown argument `(\\w+)`/)\n if (match) return `Field \"${match[1]}\" does not exist on this model. Remove it.`\n }\n if (errorMsg.includes('must not be null')) {\n return 'A required field is null. Add it to the node with a value.'\n }\n return ''\n}\n"],"mappings":"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","names":["createHmac"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autonoma-ai/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Autonoma Environment Factory SDK — protocol layer",
5
5
  "type": "module",
6
6
  "exports": {