@objectstack/plugin-audit 3.2.5

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/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ SysAuditLog: () => SysAuditLog
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/objects/sys-audit-log.object.ts
28
+ var import_data = require("@objectstack/spec/data");
29
+ var SysAuditLog = import_data.ObjectSchema.create({
30
+ namespace: "sys",
31
+ name: "audit_log",
32
+ label: "Audit Log",
33
+ pluralLabel: "Audit Logs",
34
+ icon: "scroll-text",
35
+ isSystem: true,
36
+ description: "Immutable audit trail for platform events",
37
+ titleFormat: "{action} on {object_name} by {user_id}",
38
+ compactLayout: ["action", "object_name", "user_id", "created_at"],
39
+ fields: {
40
+ id: import_data.Field.text({
41
+ label: "Audit Log ID",
42
+ required: true,
43
+ readonly: true
44
+ }),
45
+ created_at: import_data.Field.datetime({
46
+ label: "Timestamp",
47
+ required: true,
48
+ defaultValue: "NOW()",
49
+ readonly: true
50
+ }),
51
+ user_id: import_data.Field.text({
52
+ label: "User ID",
53
+ required: false,
54
+ description: "User who performed the action (null for system actions)"
55
+ }),
56
+ action: import_data.Field.select(["create", "update", "delete", "restore", "login", "logout", "permission_change", "config_change", "export", "import"], {
57
+ label: "Action",
58
+ required: true,
59
+ description: "Action type (snake_case). Values: create, update, delete, restore, login, logout, permission_change, config_change, export, import"
60
+ }),
61
+ object_name: import_data.Field.text({
62
+ label: "Object Name",
63
+ required: false,
64
+ maxLength: 255,
65
+ description: "Target object (e.g. sys_user, project_task)"
66
+ }),
67
+ record_id: import_data.Field.text({
68
+ label: "Record ID",
69
+ required: false,
70
+ description: "ID of the affected record"
71
+ }),
72
+ old_value: import_data.Field.textarea({
73
+ label: "Old Value",
74
+ required: false,
75
+ description: "JSON-serialized previous state"
76
+ }),
77
+ new_value: import_data.Field.textarea({
78
+ label: "New Value",
79
+ required: false,
80
+ description: "JSON-serialized new state"
81
+ }),
82
+ ip_address: import_data.Field.text({
83
+ label: "IP Address",
84
+ required: false,
85
+ maxLength: 45
86
+ }),
87
+ user_agent: import_data.Field.textarea({
88
+ label: "User Agent",
89
+ required: false
90
+ }),
91
+ tenant_id: import_data.Field.text({
92
+ label: "Tenant ID",
93
+ required: false,
94
+ description: "Tenant context for multi-tenant isolation"
95
+ }),
96
+ metadata: import_data.Field.textarea({
97
+ label: "Metadata",
98
+ required: false,
99
+ description: "JSON-serialized additional context"
100
+ })
101
+ },
102
+ indexes: [
103
+ { fields: ["created_at"] },
104
+ { fields: ["user_id"] },
105
+ { fields: ["object_name", "record_id"] },
106
+ { fields: ["action"] },
107
+ { fields: ["tenant_id"] }
108
+ ],
109
+ enable: {
110
+ trackHistory: false,
111
+ // Audit logs are themselves the audit trail
112
+ searchable: true,
113
+ apiEnabled: true,
114
+ apiMethods: ["get", "list"],
115
+ // Read-only — audit logs are immutable; creation happens via internal system hooks only
116
+ trash: false,
117
+ // Never soft-delete audit logs
118
+ mru: false,
119
+ clone: false
120
+ }
121
+ });
122
+ // Annotate the CommonJS export names for ESM import in node:
123
+ 0 && (module.exports = {
124
+ SysAuditLog
125
+ });
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/objects/sys-audit-log.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-audit\n *\n * Audit Plugin for ObjectStack\n * Provides the sys_audit_log system object definition for immutable audit trails.\n */\n\n// System Object Definitions (sys namespace)\nexport { SysAuditLog } from './objects/index.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_audit_log — System Audit Log Object\n *\n * Immutable audit trail for all significant platform events.\n * Records who did what, when, and the before/after state.\n *\n * @namespace sys\n */\nexport const SysAuditLog = ObjectSchema.create({\n namespace: 'sys',\n name: 'audit_log',\n label: 'Audit Log',\n pluralLabel: 'Audit Logs',\n icon: 'scroll-text',\n isSystem: true,\n description: 'Immutable audit trail for platform events',\n titleFormat: '{action} on {object_name} by {user_id}',\n compactLayout: ['action', 'object_name', 'user_id', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Audit Log ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Timestamp',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: false,\n description: 'User who performed the action (null for system actions)',\n }),\n \n action: Field.select(['create', 'update', 'delete', 'restore', 'login', 'logout', 'permission_change', 'config_change', 'export', 'import'], {\n label: 'Action',\n required: true,\n description: 'Action type (snake_case). Values: create, update, delete, restore, login, logout, permission_change, config_change, export, import',\n }),\n \n object_name: Field.text({\n label: 'Object Name',\n required: false,\n maxLength: 255,\n description: 'Target object (e.g. sys_user, project_task)',\n }),\n \n record_id: Field.text({\n label: 'Record ID',\n required: false,\n description: 'ID of the affected record',\n }),\n \n old_value: Field.textarea({\n label: 'Old Value',\n required: false,\n description: 'JSON-serialized previous state',\n }),\n \n new_value: Field.textarea({\n label: 'New Value',\n required: false,\n description: 'JSON-serialized new state',\n }),\n \n ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45,\n }),\n \n user_agent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n \n tenant_id: Field.text({\n label: 'Tenant ID',\n required: false,\n description: 'Tenant context for multi-tenant isolation',\n }),\n \n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized additional context',\n }),\n },\n \n indexes: [\n { fields: ['created_at'] },\n { fields: ['user_id'] },\n { fields: ['object_name', 'record_id'] },\n { fields: ['action'] },\n { fields: ['tenant_id'] },\n ],\n \n enable: {\n trackHistory: false, // Audit logs are themselves the audit trail\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list'], // Read-only — audit logs are immutable; creation happens via internal system hooks only\n trash: false, // Never soft-delete audit logs\n mru: false,\n clone: false,\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,kBAAoC;AAU7B,IAAM,cAAc,yBAAa,OAAO;AAAA,EAC7C,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AAAA,EACb,eAAe,CAAC,UAAU,eAAe,WAAW,YAAY;AAAA,EAEhE,QAAQ;AAAA,IACN,IAAI,kBAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,YAAY,kBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,SAAS,kBAAM,KAAK;AAAA,MAClB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,QAAQ,kBAAM,OAAO,CAAC,UAAU,UAAU,UAAU,WAAW,SAAS,UAAU,qBAAqB,iBAAiB,UAAU,QAAQ,GAAG;AAAA,MAC3I,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,kBAAM,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,kBAAM,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,kBAAM,SAAS;AAAA,MACxB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,kBAAM,SAAS;AAAA,MACxB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,kBAAM,KAAK;AAAA,MACrB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,IAED,YAAY,kBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,WAAW,kBAAM,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,kBAAM,SAAS;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,YAAY,EAAE;AAAA,IACzB,EAAE,QAAQ,CAAC,SAAS,EAAE;AAAA,IACtB,EAAE,QAAQ,CAAC,eAAe,WAAW,EAAE;AAAA,IACvC,EAAE,QAAQ,CAAC,QAAQ,EAAE;AAAA,IACrB,EAAE,QAAQ,CAAC,WAAW,EAAE;AAAA,EAC1B;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,MAAM;AAAA;AAAA,IAC1B,OAAO;AAAA;AAAA,IACP,KAAK;AAAA,IACL,OAAO;AAAA,EACT;AACF,CAAC;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,99 @@
1
+ // src/objects/sys-audit-log.object.ts
2
+ import { ObjectSchema, Field } from "@objectstack/spec/data";
3
+ var SysAuditLog = ObjectSchema.create({
4
+ namespace: "sys",
5
+ name: "audit_log",
6
+ label: "Audit Log",
7
+ pluralLabel: "Audit Logs",
8
+ icon: "scroll-text",
9
+ isSystem: true,
10
+ description: "Immutable audit trail for platform events",
11
+ titleFormat: "{action} on {object_name} by {user_id}",
12
+ compactLayout: ["action", "object_name", "user_id", "created_at"],
13
+ fields: {
14
+ id: Field.text({
15
+ label: "Audit Log ID",
16
+ required: true,
17
+ readonly: true
18
+ }),
19
+ created_at: Field.datetime({
20
+ label: "Timestamp",
21
+ required: true,
22
+ defaultValue: "NOW()",
23
+ readonly: true
24
+ }),
25
+ user_id: Field.text({
26
+ label: "User ID",
27
+ required: false,
28
+ description: "User who performed the action (null for system actions)"
29
+ }),
30
+ action: Field.select(["create", "update", "delete", "restore", "login", "logout", "permission_change", "config_change", "export", "import"], {
31
+ label: "Action",
32
+ required: true,
33
+ description: "Action type (snake_case). Values: create, update, delete, restore, login, logout, permission_change, config_change, export, import"
34
+ }),
35
+ object_name: Field.text({
36
+ label: "Object Name",
37
+ required: false,
38
+ maxLength: 255,
39
+ description: "Target object (e.g. sys_user, project_task)"
40
+ }),
41
+ record_id: Field.text({
42
+ label: "Record ID",
43
+ required: false,
44
+ description: "ID of the affected record"
45
+ }),
46
+ old_value: Field.textarea({
47
+ label: "Old Value",
48
+ required: false,
49
+ description: "JSON-serialized previous state"
50
+ }),
51
+ new_value: Field.textarea({
52
+ label: "New Value",
53
+ required: false,
54
+ description: "JSON-serialized new state"
55
+ }),
56
+ ip_address: Field.text({
57
+ label: "IP Address",
58
+ required: false,
59
+ maxLength: 45
60
+ }),
61
+ user_agent: Field.textarea({
62
+ label: "User Agent",
63
+ required: false
64
+ }),
65
+ tenant_id: Field.text({
66
+ label: "Tenant ID",
67
+ required: false,
68
+ description: "Tenant context for multi-tenant isolation"
69
+ }),
70
+ metadata: Field.textarea({
71
+ label: "Metadata",
72
+ required: false,
73
+ description: "JSON-serialized additional context"
74
+ })
75
+ },
76
+ indexes: [
77
+ { fields: ["created_at"] },
78
+ { fields: ["user_id"] },
79
+ { fields: ["object_name", "record_id"] },
80
+ { fields: ["action"] },
81
+ { fields: ["tenant_id"] }
82
+ ],
83
+ enable: {
84
+ trackHistory: false,
85
+ // Audit logs are themselves the audit trail
86
+ searchable: true,
87
+ apiEnabled: true,
88
+ apiMethods: ["get", "list"],
89
+ // Read-only — audit logs are immutable; creation happens via internal system hooks only
90
+ trash: false,
91
+ // Never soft-delete audit logs
92
+ mru: false,
93
+ clone: false
94
+ }
95
+ });
96
+ export {
97
+ SysAuditLog
98
+ };
99
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/objects/sys-audit-log.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_audit_log — System Audit Log Object\n *\n * Immutable audit trail for all significant platform events.\n * Records who did what, when, and the before/after state.\n *\n * @namespace sys\n */\nexport const SysAuditLog = ObjectSchema.create({\n namespace: 'sys',\n name: 'audit_log',\n label: 'Audit Log',\n pluralLabel: 'Audit Logs',\n icon: 'scroll-text',\n isSystem: true,\n description: 'Immutable audit trail for platform events',\n titleFormat: '{action} on {object_name} by {user_id}',\n compactLayout: ['action', 'object_name', 'user_id', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Audit Log ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Timestamp',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: false,\n description: 'User who performed the action (null for system actions)',\n }),\n \n action: Field.select(['create', 'update', 'delete', 'restore', 'login', 'logout', 'permission_change', 'config_change', 'export', 'import'], {\n label: 'Action',\n required: true,\n description: 'Action type (snake_case). Values: create, update, delete, restore, login, logout, permission_change, config_change, export, import',\n }),\n \n object_name: Field.text({\n label: 'Object Name',\n required: false,\n maxLength: 255,\n description: 'Target object (e.g. sys_user, project_task)',\n }),\n \n record_id: Field.text({\n label: 'Record ID',\n required: false,\n description: 'ID of the affected record',\n }),\n \n old_value: Field.textarea({\n label: 'Old Value',\n required: false,\n description: 'JSON-serialized previous state',\n }),\n \n new_value: Field.textarea({\n label: 'New Value',\n required: false,\n description: 'JSON-serialized new state',\n }),\n \n ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45,\n }),\n \n user_agent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n \n tenant_id: Field.text({\n label: 'Tenant ID',\n required: false,\n description: 'Tenant context for multi-tenant isolation',\n }),\n \n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized additional context',\n }),\n },\n \n indexes: [\n { fields: ['created_at'] },\n { fields: ['user_id'] },\n { fields: ['object_name', 'record_id'] },\n { fields: ['action'] },\n { fields: ['tenant_id'] },\n ],\n \n enable: {\n trackHistory: false, // Audit logs are themselves the audit trail\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list'], // Read-only — audit logs are immutable; creation happens via internal system hooks only\n trash: false, // Never soft-delete audit logs\n mru: false,\n clone: false,\n },\n});\n"],"mappings":";AAEA,SAAS,cAAc,aAAa;AAU7B,IAAM,cAAc,aAAa,OAAO;AAAA,EAC7C,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AAAA,EACb,eAAe,CAAC,UAAU,eAAe,WAAW,YAAY;AAAA,EAEhE,QAAQ;AAAA,IACN,IAAI,MAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,YAAY,MAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,SAAS,MAAM,KAAK;AAAA,MAClB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,QAAQ,MAAM,OAAO,CAAC,UAAU,UAAU,UAAU,WAAW,SAAS,UAAU,qBAAqB,iBAAiB,UAAU,QAAQ,GAAG;AAAA,MAC3I,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,MAAM,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,MAAM,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,MAAM,SAAS;AAAA,MACxB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,MAAM,SAAS;AAAA,MACxB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,MAAM,KAAK;AAAA,MACrB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,IAED,YAAY,MAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,WAAW,MAAM,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,MAAM,SAAS;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,YAAY,EAAE;AAAA,IACzB,EAAE,QAAQ,CAAC,SAAS,EAAE;AAAA,IACtB,EAAE,QAAQ,CAAC,eAAe,WAAW,EAAE;AAAA,IACvC,EAAE,QAAQ,CAAC,QAAQ,EAAE;AAAA,IACrB,EAAE,QAAQ,CAAC,WAAW,EAAE;AAAA,EAC1B;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,MAAM;AAAA;AAAA,IAC1B,OAAO;AAAA;AAAA,IACP,KAAK;AAAA,IACL,OAAO;AAAA,EACT;AACF,CAAC;","names":[]}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@objectstack/plugin-audit",
3
+ "version": "3.2.5",
4
+ "license": "Apache-2.0",
5
+ "description": "Audit Plugin for ObjectStack — System audit log object and audit trail",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "dependencies": {
16
+ "@objectstack/spec": "3.2.5"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^25.3.5",
20
+ "typescript": "^5.0.0",
21
+ "vitest": "^4.0.18"
22
+ },
23
+ "scripts": {
24
+ "build": "tsup --config ../../../tsup.config.ts",
25
+ "test": "vitest run"
26
+ }
27
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
+
3
+ /**
4
+ * @objectstack/plugin-audit
5
+ *
6
+ * Audit Plugin for ObjectStack
7
+ * Provides the sys_audit_log system object definition for immutable audit trails.
8
+ */
9
+
10
+ // System Object Definitions (sys namespace)
11
+ export { SysAuditLog } from './objects/index.js';
@@ -0,0 +1,9 @@
1
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
+
3
+ /**
4
+ * Audit Plugin — System Object Definitions (sys namespace)
5
+ *
6
+ * Canonical ObjectSchema definitions for audit-related system objects.
7
+ */
8
+
9
+ export { SysAuditLog } from './sys-audit-log.object.js';
@@ -0,0 +1,116 @@
1
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
+
3
+ import { ObjectSchema, Field } from '@objectstack/spec/data';
4
+
5
+ /**
6
+ * sys_audit_log — System Audit Log Object
7
+ *
8
+ * Immutable audit trail for all significant platform events.
9
+ * Records who did what, when, and the before/after state.
10
+ *
11
+ * @namespace sys
12
+ */
13
+ export const SysAuditLog = ObjectSchema.create({
14
+ namespace: 'sys',
15
+ name: 'audit_log',
16
+ label: 'Audit Log',
17
+ pluralLabel: 'Audit Logs',
18
+ icon: 'scroll-text',
19
+ isSystem: true,
20
+ description: 'Immutable audit trail for platform events',
21
+ titleFormat: '{action} on {object_name} by {user_id}',
22
+ compactLayout: ['action', 'object_name', 'user_id', 'created_at'],
23
+
24
+ fields: {
25
+ id: Field.text({
26
+ label: 'Audit Log ID',
27
+ required: true,
28
+ readonly: true,
29
+ }),
30
+
31
+ created_at: Field.datetime({
32
+ label: 'Timestamp',
33
+ required: true,
34
+ defaultValue: 'NOW()',
35
+ readonly: true,
36
+ }),
37
+
38
+ user_id: Field.text({
39
+ label: 'User ID',
40
+ required: false,
41
+ description: 'User who performed the action (null for system actions)',
42
+ }),
43
+
44
+ action: Field.select(['create', 'update', 'delete', 'restore', 'login', 'logout', 'permission_change', 'config_change', 'export', 'import'], {
45
+ label: 'Action',
46
+ required: true,
47
+ description: 'Action type (snake_case). Values: create, update, delete, restore, login, logout, permission_change, config_change, export, import',
48
+ }),
49
+
50
+ object_name: Field.text({
51
+ label: 'Object Name',
52
+ required: false,
53
+ maxLength: 255,
54
+ description: 'Target object (e.g. sys_user, project_task)',
55
+ }),
56
+
57
+ record_id: Field.text({
58
+ label: 'Record ID',
59
+ required: false,
60
+ description: 'ID of the affected record',
61
+ }),
62
+
63
+ old_value: Field.textarea({
64
+ label: 'Old Value',
65
+ required: false,
66
+ description: 'JSON-serialized previous state',
67
+ }),
68
+
69
+ new_value: Field.textarea({
70
+ label: 'New Value',
71
+ required: false,
72
+ description: 'JSON-serialized new state',
73
+ }),
74
+
75
+ ip_address: Field.text({
76
+ label: 'IP Address',
77
+ required: false,
78
+ maxLength: 45,
79
+ }),
80
+
81
+ user_agent: Field.textarea({
82
+ label: 'User Agent',
83
+ required: false,
84
+ }),
85
+
86
+ tenant_id: Field.text({
87
+ label: 'Tenant ID',
88
+ required: false,
89
+ description: 'Tenant context for multi-tenant isolation',
90
+ }),
91
+
92
+ metadata: Field.textarea({
93
+ label: 'Metadata',
94
+ required: false,
95
+ description: 'JSON-serialized additional context',
96
+ }),
97
+ },
98
+
99
+ indexes: [
100
+ { fields: ['created_at'] },
101
+ { fields: ['user_id'] },
102
+ { fields: ['object_name', 'record_id'] },
103
+ { fields: ['action'] },
104
+ { fields: ['tenant_id'] },
105
+ ],
106
+
107
+ enable: {
108
+ trackHistory: false, // Audit logs are themselves the audit trail
109
+ searchable: true,
110
+ apiEnabled: true,
111
+ apiMethods: ['get', 'list'], // Read-only — audit logs are immutable; creation happens via internal system hooks only
112
+ trash: false, // Never soft-delete audit logs
113
+ mru: false,
114
+ clone: false,
115
+ },
116
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["dist", "node_modules", "**/*.test.ts"]
9
+ }