@things-factory/auth-base 10.1.234 → 10.1.241

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.
@@ -25,7 +25,7 @@ tslib_1.__decorate([
25
25
  tslib_1.__metadata("design:type", String)
26
26
  ], AuditAction.prototype, "id", void 0);
27
27
  tslib_1.__decorate([
28
- (0, typeorm_1.Column)({ nullable: true, length: 36 }),
28
+ (0, typeorm_1.Column)({ type: 'uuid', nullable: true }),
29
29
  (0, type_graphql_1.Field)({ nullable: true, description: 'The request this was done in. Empty for work outside any request.' }),
30
30
  tslib_1.__metadata("design:type", String)
31
31
  ], AuditAction.prototype, "requestId", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"audit-action.js","sourceRoot":"","sources":["../../../server/service/audit/audit-action.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType } from 'type-graphql'\nimport { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { User } from '../user/user.js'\n\n/**\n * One thing done, as the audit keeps it (ADR-0141 §3.2 · §3.3).\n *\n * `kind` says which: `door.check` (a `@privilege` judgement), `door.result` (what a passed door\n * did), or an event a service or the audit subscriber wrote (`role.grant`, `auth.signin`, ...).\n * Only the columns below exist, and `detail` takes only the keys its kind registered\n * (`audit-kinds.ts`) - no business value, secret or request text has a place to go.\n *\n * Immutable like `AuditRequest`, and for the same reason without foreign keys.\n */\n@Entity()\n@Index('ix_audit_action_0', (action: AuditAction) => [action.domain, action.createdAt])\n@Index('ix_audit_action_1', (action: AuditAction) => [action.actor, action.createdAt])\n@Index('ix_audit_action_2', (action: AuditAction) => [action.requestId])\n@ObjectType({ description: 'One thing done, as the audit keeps it.' })\nexport class AuditAction {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier.' })\n readonly id: string\n\n @Column({ nullable: true, length: 36 })\n @Field({ nullable: true, description: 'The request this was done in. Empty for work outside any request.' })\n requestId?: string\n\n @ManyToOne(type => Domain, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => Domain, { nullable: true, description: 'The domain it was done in.' })\n domain?: Domain\n\n @RelationId((action: AuditAction) => action.domain)\n domainId?: string\n\n @ManyToOne(type => User, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => User, { nullable: true, description: 'Who did it. Empty when nobody is known - a sign-in to an account that does not exist.' })\n actor?: User\n\n @RelationId((action: AuditAction) => action.actor)\n actorId?: string\n\n @CreateDateColumn()\n @Field({ description: 'When it was written.' })\n createdAt: Date\n\n @Column({ length: 64 })\n @Field({ description: 'What kind of action: door.check, door.result, role.grant, auth.signin, ...' })\n kind: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The door, as category:privilege, or owner / super for a door that asks ownership only.' })\n door?: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'granted or denied - for a door check.' })\n decision?: string\n\n @Column({ nullable: true, length: 32 })\n @Field({ nullable: true, description: 'Why: role, domain-owner, superuser when granted; role, address, license, ownership, unknown when denied.' })\n basis?: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'ok or error - what was done after the door, or how an event ended.' })\n outcome?: string\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'A fixed code for an error or a refusal. Never a message.' })\n code?: string\n\n @Column({ type: 'int', default: 1 })\n @Field(type => Int, { description: 'How many times this happened in the request - equal checks are kept as one row.' })\n count: number\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'How many items a list returned, summed over the request.' })\n returned?: number\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Kind of the target - User, Role, ...' })\n targetKind?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true, description: 'Target ids, up to 100.' })\n targetIds?: string[]\n\n @Column({ default: false })\n @Field({ description: 'Whether more targets than were kept.' })\n truncated: boolean\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'requested - named by the caller; handled - confirmed by the service.' })\n targetRole?: string\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Kind of the second object - the Role granted, the Privilege added.' })\n objectKind?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'Id or name of the second object.' })\n objectId?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Further facts, only the keys the kind registered.' })\n detail?: Record<string, string | number | boolean | null>\n}\n"]}
1
+ {"version":3,"file":"audit-action.js","sourceRoot":"","sources":["../../../server/service/audit/audit-action.ts"],"names":[],"mappings":";;;;AAAA,+CAAyD;AACzD,qCAAgH;AAEhH,iDAA4D;AAE5D,6CAAsC;AAEtC;;;;;;;;;GASG;AAMI,IAAM,WAAW,GAAjB,MAAM,WAAW;CAsFvB,CAAA;AAtFY,kCAAW;AAGb;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;;uCACtC;AAInB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mEAAmE,EAAE,CAAC;;8CAC1F;AAIlB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,CAAC;IACjF,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;sCAC5E,cAAM;2CAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,MAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;;6CAClC;AAIjB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,CAAC;IAC/E,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uFAAuF,EAAE,CAAC;sCACtI,cAAI;0CAAA;AAGZ;IADC,IAAA,oBAAU,EAAC,CAAC,MAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;;4CAClC;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sBAAsB,EAAE,CAAC;sCACpC,IAAI;8CAAA;AAIf;IAFC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtB,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,4EAA4E,EAAE,CAAC;;yCACzF;AAIZ;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wFAAwF,EAAE,CAAC;;yCACpH;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uCAAuC,EAAE,CAAC;;6CAC/D;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0GAA0G,EAAE,CAAC;;0CACrI;AAId;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oEAAoE,EAAE,CAAC;;4CAC7F;AAIhB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0DAA0D,EAAE,CAAC;;yCACtF;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACnC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,iFAAiF,EAAE,CAAC;;0CAC1G;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0DAA0D,EAAE,CAAC;;6CAC/F;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;;+CAC5D;AAInB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC;;8CAC/D;AAIpB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;;8CAC7C;AAIlB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,sEAAsE,EAAE,CAAC;;+CAC5F;AAInB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oEAAoE,EAAE,CAAC;;+CAC1F;AAInB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC;;6CAC1D;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;;2CACzD;sBArF9C,WAAW;IALvB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,mBAAmB,EAAE,CAAC,MAAmB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACtF,IAAA,eAAK,EAAC,mBAAmB,EAAE,CAAC,MAAmB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACrF,IAAA,eAAK,EAAC,mBAAmB,EAAE,CAAC,MAAmB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACvE,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;GACzD,WAAW,CAsFvB","sourcesContent":["import { Field, ID, Int, ObjectType } from 'type-graphql'\nimport { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { User } from '../user/user.js'\n\n/**\n * One thing done, as the audit keeps it (ADR-0141 §3.2 · §3.3).\n *\n * `kind` says which: `door.check` (a `@privilege` judgement), `door.result` (what a passed door\n * did), or an event a service or the audit subscriber wrote (`role.grant`, `auth.signin`, ...).\n * Only the columns below exist, and `detail` takes only the keys its kind registered\n * (`audit-kinds.ts`) - no business value, secret or request text has a place to go.\n *\n * Immutable like `AuditRequest`, and for the same reason without foreign keys.\n */\n@Entity()\n@Index('ix_audit_action_0', (action: AuditAction) => [action.domain, action.createdAt])\n@Index('ix_audit_action_1', (action: AuditAction) => [action.actor, action.createdAt])\n@Index('ix_audit_action_2', (action: AuditAction) => [action.requestId])\n@ObjectType({ description: 'One thing done, as the audit keeps it.' })\nexport class AuditAction {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier.' })\n readonly id: string\n\n @Column({ type: 'uuid', nullable: true })\n @Field({ nullable: true, description: 'The request this was done in. Empty for work outside any request.' })\n requestId?: string\n\n @ManyToOne(type => Domain, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => Domain, { nullable: true, description: 'The domain it was done in.' })\n domain?: Domain\n\n @RelationId((action: AuditAction) => action.domain)\n domainId?: string\n\n @ManyToOne(type => User, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => User, { nullable: true, description: 'Who did it. Empty when nobody is known - a sign-in to an account that does not exist.' })\n actor?: User\n\n @RelationId((action: AuditAction) => action.actor)\n actorId?: string\n\n @CreateDateColumn()\n @Field({ description: 'When it was written.' })\n createdAt: Date\n\n @Column({ length: 64 })\n @Field({ description: 'What kind of action: door.check, door.result, role.grant, auth.signin, ...' })\n kind: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The door, as category:privilege, or owner / super for a door that asks ownership only.' })\n door?: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'granted or denied - for a door check.' })\n decision?: string\n\n @Column({ nullable: true, length: 32 })\n @Field({ nullable: true, description: 'Why: role, domain-owner, superuser when granted; role, address, license, ownership, unknown when denied.' })\n basis?: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'ok or error - what was done after the door, or how an event ended.' })\n outcome?: string\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'A fixed code for an error or a refusal. Never a message.' })\n code?: string\n\n @Column({ type: 'int', default: 1 })\n @Field(type => Int, { description: 'How many times this happened in the request - equal checks are kept as one row.' })\n count: number\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'How many items a list returned, summed over the request.' })\n returned?: number\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Kind of the target - User, Role, ...' })\n targetKind?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true, description: 'Target ids, up to 100.' })\n targetIds?: string[]\n\n @Column({ default: false })\n @Field({ description: 'Whether more targets than were kept.' })\n truncated: boolean\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'requested - named by the caller; handled - confirmed by the service.' })\n targetRole?: string\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Kind of the second object - the Role granted, the Privilege added.' })\n objectKind?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'Id or name of the second object.' })\n objectId?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Further facts, only the keys the kind registered.' })\n detail?: Record<string, string | number | boolean | null>\n}\n"]}
@@ -20,7 +20,7 @@ let AuditRequest = class AuditRequest {
20
20
  };
21
21
  exports.AuditRequest = AuditRequest;
22
22
  tslib_1.__decorate([
23
- (0, typeorm_1.PrimaryColumn)({ type: 'varchar', length: 36 }),
23
+ (0, typeorm_1.PrimaryColumn)('uuid'),
24
24
  (0, type_graphql_1.Field)(type => type_graphql_1.ID, { description: 'Request id, shared by the actions of this request.' }),
25
25
  tslib_1.__metadata("design:type", String)
26
26
  ], AuditRequest.prototype, "id", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"audit-request.js","sourceRoot":"","sources":["../../../server/service/audit/audit-request.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType } from 'type-graphql'\nimport { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryColumn, RelationId } from 'typeorm'\n\nimport { Domain } from '@things-factory/shell'\n\nimport { User } from '../user/user.js'\n\n/**\n * One request that reached the server, as the audit keeps it (ADR-0141 §3.1).\n *\n * Every GraphQL request has one; any other request has one when it left at least one action\n * (a sign-in, a check-in). What happened inside is in `AuditAction` rows carrying this id.\n *\n * The row is never changed or deleted by the application (ADR-0141 §4-6), so the entity has no\n * updater, `updatedAt` or `deletedAt`. Its relations carry no foreign key: an audit row must\n * neither stop a user or domain from being removed nor go with them.\n */\n@Entity()\n@Index('ix_audit_request_0', (request: AuditRequest) => [request.domain, request.createdAt])\n@Index('ix_audit_request_1', (request: AuditRequest) => [request.actor, request.createdAt])\n@ObjectType({ description: 'A request that reached the server, as the audit keeps it.' })\nexport class AuditRequest {\n /* Given by the recorder at the start of the request, so actions written mid-request can name it. */\n @PrimaryColumn({ type: 'varchar', length: 36 })\n @Field(type => ID, { description: 'Request id, shared by the actions of this request.' })\n id: string\n\n @ManyToOne(type => Domain, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => Domain, { nullable: true, description: 'The domain the request was made in.' })\n domain?: Domain\n\n @RelationId((request: AuditRequest) => request.domain)\n domainId?: string\n\n @ManyToOne(type => User, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => User, { nullable: true, description: 'Who made the request. Empty when nobody was signed in.' })\n actor?: User\n\n @RelationId((request: AuditRequest) => request.actor)\n actorId?: string\n\n @CreateDateColumn()\n @Field({ description: 'When the server finished the request.' })\n createdAt: Date\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Address the request came from.' })\n ip?: string\n\n @Column({ nullable: true, length: 256 })\n @Field({ nullable: true, description: 'User-Agent header, cut at 256 characters.' })\n userAgent?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Milliseconds the server spent on the request.' })\n durationMs?: number\n\n @Column({ length: 16 })\n @Field({ description: 'graphql, or http for any other request.' })\n channel: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'query, mutation or subscription - for a GraphQL request.' })\n operationType?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The operation name the client gave. For reference only - the client chooses it.' })\n operationName?: string\n\n @Column({ nullable: true, length: 256 })\n @Field({ nullable: true, description: 'The root fields a GraphQL request asked, by their schema names - never an argument.' })\n fields?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The route pattern of a request outside GraphQL. Never the path itself.' })\n route?: string\n}\n"]}
1
+ {"version":3,"file":"audit-request.js","sourceRoot":"","sources":["../../../server/service/audit/audit-request.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType } from 'type-graphql'\nimport { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryColumn, RelationId } from 'typeorm'\n\nimport { Domain } from '@things-factory/shell'\n\nimport { User } from '../user/user.js'\n\n/**\n * One request that reached the server, as the audit keeps it (ADR-0141 §3.1).\n *\n * Every GraphQL request has one; any other request has one when it left at least one action\n * (a sign-in, a check-in). What happened inside is in `AuditAction` rows carrying this id.\n *\n * The row is never changed or deleted by the application (ADR-0141 §4-6), so the entity has no\n * updater, `updatedAt` or `deletedAt`. Its relations carry no foreign key: an audit row must\n * neither stop a user or domain from being removed nor go with them.\n */\n@Entity()\n@Index('ix_audit_request_0', (request: AuditRequest) => [request.domain, request.createdAt])\n@Index('ix_audit_request_1', (request: AuditRequest) => [request.actor, request.createdAt])\n@ObjectType({ description: 'A request that reached the server, as the audit keeps it.' })\nexport class AuditRequest {\n /* Given by the recorder at the start of the request, so actions written mid-request can name it. */\n @PrimaryColumn('uuid')\n @Field(type => ID, { description: 'Request id, shared by the actions of this request.' })\n id: string\n\n @ManyToOne(type => Domain, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => Domain, { nullable: true, description: 'The domain the request was made in.' })\n domain?: Domain\n\n @RelationId((request: AuditRequest) => request.domain)\n domainId?: string\n\n @ManyToOne(type => User, { nullable: true, createForeignKeyConstraints: false })\n @Field(type => User, { nullable: true, description: 'Who made the request. Empty when nobody was signed in.' })\n actor?: User\n\n @RelationId((request: AuditRequest) => request.actor)\n actorId?: string\n\n @CreateDateColumn()\n @Field({ description: 'When the server finished the request.' })\n createdAt: Date\n\n @Column({ nullable: true, length: 64 })\n @Field({ nullable: true, description: 'Address the request came from.' })\n ip?: string\n\n @Column({ nullable: true, length: 256 })\n @Field({ nullable: true, description: 'User-Agent header, cut at 256 characters.' })\n userAgent?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Milliseconds the server spent on the request.' })\n durationMs?: number\n\n @Column({ length: 16 })\n @Field({ description: 'graphql, or http for any other request.' })\n channel: string\n\n @Column({ nullable: true, length: 16 })\n @Field({ nullable: true, description: 'query, mutation or subscription - for a GraphQL request.' })\n operationType?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The operation name the client gave. For reference only - the client chooses it.' })\n operationName?: string\n\n @Column({ nullable: true, length: 256 })\n @Field({ nullable: true, description: 'The root fields a GraphQL request asked, by their schema names - never an argument.' })\n fields?: string\n\n @Column({ nullable: true, length: 128 })\n @Field({ nullable: true, description: 'The route pattern of a request outside GraphQL. Never the path itself.' })\n route?: string\n}\n"]}