@mj-biz-apps/issues-core-entities-server 0.0.1 → 1.0.0
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/IssueEntityServer.d.ts +53 -0
- package/dist/IssueEntityServer.d.ts.map +1 -0
- package/dist/IssueEntityServer.js +201 -0
- package/dist/IssueEntityServer.js.map +1 -0
- package/dist/SequenceService.d.ts +48 -0
- package/dist/SequenceService.d.ts.map +1 -0
- package/dist/SequenceService.js +83 -0
- package/dist/SequenceService.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -7
- package/README.md +0 -45
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { mjBizAppsIssuesIssueEntity } from '@mj-biz-apps/issues-entities';
|
|
3
|
+
/**
|
|
4
|
+
* Server-side subclass of {@link mjBizAppsIssuesIssueEntity}.
|
|
5
|
+
*
|
|
6
|
+
* Owns the SERVER-ONLY lifecycle side-effects that must fire on EVERY save path
|
|
7
|
+
* (UI, API, automation) — not just when callers route through IssueService:
|
|
8
|
+
*
|
|
9
|
+
* 1. **IssueNumber assignment** (insert only) — via the atomic
|
|
10
|
+
* spAssignNextIssueNumber proc, before super.Save(); immutable thereafter.
|
|
11
|
+
* 2. **Lifecycle timestamp stamping** (in Save(), before super.Save()) — when
|
|
12
|
+
* StatusID changes: stamp ResolvedAt on entering a Resolved/Terminal status,
|
|
13
|
+
* ClosedAt on entering a Terminal status, and clear them on reopen. These
|
|
14
|
+
* mutate the row being written, so they happen inline.
|
|
15
|
+
* 3. **IssueType action hooks** (post-save, via RegisterEventHandler) — fire
|
|
16
|
+
* OnCreate (insert), OnStatusChange (+ OnClose on terminal), and OnAssign
|
|
17
|
+
* (assignee change) through the Action engine. These are decoupled reactions
|
|
18
|
+
* that must NOT be able to fail or slow the save, so they run after the save
|
|
19
|
+
* event finalizes — mirroring bizapps-tasks' TaskNotificationHandler and
|
|
20
|
+
* SaaS's OrganizationPersonRoleEntityServer event-handler pattern.
|
|
21
|
+
*
|
|
22
|
+
* Registered at priority 2 so this server subclass wins over the priority-1
|
|
23
|
+
* client-shared entity.
|
|
24
|
+
*/
|
|
25
|
+
export declare class IssueEntityServer extends mjBizAppsIssuesIssueEntity {
|
|
26
|
+
private _hookHandlerRegistered;
|
|
27
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
28
|
+
/** Allocates and sets IssueNumber for a new Issue based on its AppScope. */
|
|
29
|
+
private assignIssueNumber;
|
|
30
|
+
/**
|
|
31
|
+
* Stamps ResolvedAt / ClosedAt based on the NEW status's flags:
|
|
32
|
+
* - entering an IsResolved OR IsTerminal status → set ResolvedAt (if not already set)
|
|
33
|
+
* - entering an IsTerminal status → set ClosedAt
|
|
34
|
+
* - leaving into a non-terminal, non-resolved (active) status (reopen) → clear both
|
|
35
|
+
* Loads the engine for the IsResolved/IsTerminal lookup.
|
|
36
|
+
*/
|
|
37
|
+
private stampLifecycleTimestamps;
|
|
38
|
+
private _pendingHookContext;
|
|
39
|
+
/**
|
|
40
|
+
* Registers a per-instance save-event handler (once) that fires the IssueType
|
|
41
|
+
* action hooks AFTER the save finalizes. Fire-and-forget; failures are logged,
|
|
42
|
+
* never propagated — a misconfigured hook must not break the save.
|
|
43
|
+
*/
|
|
44
|
+
private ensureHookHandler;
|
|
45
|
+
/** Dispatches the IssueType action hooks for the events that occurred this save. */
|
|
46
|
+
private fireLifecycleHooks;
|
|
47
|
+
/**
|
|
48
|
+
* Fires a single IssueType action hook by Action ID, passing the issue's identity
|
|
49
|
+
* as input params. No-op when actionID is null. Failures are logged, not thrown.
|
|
50
|
+
*/
|
|
51
|
+
private fireHook;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=IssueEntityServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueEntityServer.d.ts","sourceRoot":"","sources":["../src/IssueEntityServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,iBAAiB,EAAsB,MAAM,sBAAsB,CAAC;AAI1G,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAK1E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,iBAAkB,SAAQ,0BAA0B;IAC/D,OAAO,CAAC,sBAAsB,CAAS;IAEjB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAmCzE,4EAA4E;YAC9D,iBAAiB;IAc/B;;;;;;OAMG;YACW,wBAAwB;IA6BtC,OAAO,CAAC,mBAAmB,CAA4B;IAEvD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAsBzB,oFAAoF;YACtE,kBAAkB;IAqBhC;;;OAGG;YACW,QAAQ;CAiCvB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseEntity, LogError } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
9
|
+
import { ActionEngineServer } from '@memberjunction/actions';
|
|
10
|
+
import { mjBizAppsIssuesIssueEntity } from '@mj-biz-apps/issues-entities';
|
|
11
|
+
import { IssueEngine } from '@mj-biz-apps/issues-core';
|
|
12
|
+
import { SequenceService } from './SequenceService.js';
|
|
13
|
+
/**
|
|
14
|
+
* Server-side subclass of {@link mjBizAppsIssuesIssueEntity}.
|
|
15
|
+
*
|
|
16
|
+
* Owns the SERVER-ONLY lifecycle side-effects that must fire on EVERY save path
|
|
17
|
+
* (UI, API, automation) — not just when callers route through IssueService:
|
|
18
|
+
*
|
|
19
|
+
* 1. **IssueNumber assignment** (insert only) — via the atomic
|
|
20
|
+
* spAssignNextIssueNumber proc, before super.Save(); immutable thereafter.
|
|
21
|
+
* 2. **Lifecycle timestamp stamping** (in Save(), before super.Save()) — when
|
|
22
|
+
* StatusID changes: stamp ResolvedAt on entering a Resolved/Terminal status,
|
|
23
|
+
* ClosedAt on entering a Terminal status, and clear them on reopen. These
|
|
24
|
+
* mutate the row being written, so they happen inline.
|
|
25
|
+
* 3. **IssueType action hooks** (post-save, via RegisterEventHandler) — fire
|
|
26
|
+
* OnCreate (insert), OnStatusChange (+ OnClose on terminal), and OnAssign
|
|
27
|
+
* (assignee change) through the Action engine. These are decoupled reactions
|
|
28
|
+
* that must NOT be able to fail or slow the save, so they run after the save
|
|
29
|
+
* event finalizes — mirroring bizapps-tasks' TaskNotificationHandler and
|
|
30
|
+
* SaaS's OrganizationPersonRoleEntityServer event-handler pattern.
|
|
31
|
+
*
|
|
32
|
+
* Registered at priority 2 so this server subclass wins over the priority-1
|
|
33
|
+
* client-shared entity.
|
|
34
|
+
*/
|
|
35
|
+
let IssueEntityServer = class IssueEntityServer extends mjBizAppsIssuesIssueEntity {
|
|
36
|
+
constructor() {
|
|
37
|
+
super(...arguments);
|
|
38
|
+
this._hookHandlerRegistered = false;
|
|
39
|
+
// ------------------------------------------------------------------
|
|
40
|
+
// 3. Action hooks (post-save reaction via event handler)
|
|
41
|
+
// ------------------------------------------------------------------
|
|
42
|
+
this._pendingHookContext = null;
|
|
43
|
+
}
|
|
44
|
+
async Save(options) {
|
|
45
|
+
this.ensureHookHandler();
|
|
46
|
+
const isNew = !this.IsSaved;
|
|
47
|
+
// Snapshot the status transition BEFORE super.Save() resets dirty flags.
|
|
48
|
+
const statusField = this.GetFieldByName('StatusID');
|
|
49
|
+
const statusChanged = statusField?.Dirty ?? false;
|
|
50
|
+
const oldStatusID = statusField?.OldValue ?? null;
|
|
51
|
+
const assigneeField = this.GetFieldByName('AssigneeRecordID');
|
|
52
|
+
const assigneeEntityField = this.GetFieldByName('AssigneeEntityID');
|
|
53
|
+
const assigneeChanged = (assigneeField?.Dirty ?? false) || (assigneeEntityField?.Dirty ?? false);
|
|
54
|
+
// 1. IssueNumber (insert only, immutable)
|
|
55
|
+
if (isNew && !this.IssueNumber) {
|
|
56
|
+
await this.assignIssueNumber();
|
|
57
|
+
}
|
|
58
|
+
// 2. Lifecycle timestamps — stamp inline so they're part of this write.
|
|
59
|
+
// On insert, treat the initial status as "entered" too.
|
|
60
|
+
if (statusChanged || isNew) {
|
|
61
|
+
await this.stampLifecycleTimestamps();
|
|
62
|
+
}
|
|
63
|
+
// Stash what the post-save hook handler needs (dirty flags are gone after save).
|
|
64
|
+
this._pendingHookContext = { isNew, statusChanged: statusChanged && !isNew, oldStatusID, assigneeChanged: assigneeChanged && !isNew };
|
|
65
|
+
return super.Save(options);
|
|
66
|
+
}
|
|
67
|
+
// ------------------------------------------------------------------
|
|
68
|
+
// 1. IssueNumber assignment
|
|
69
|
+
// ------------------------------------------------------------------
|
|
70
|
+
/** Allocates and sets IssueNumber for a new Issue based on its AppScope. */
|
|
71
|
+
async assignIssueNumber() {
|
|
72
|
+
try {
|
|
73
|
+
this.IssueNumber = await SequenceService.assignNextIssueNumber(this.AppScope, this);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
77
|
+
LogError(`IssueEntityServer: failed to assign IssueNumber (AppScope=${this.AppScope ?? '(null)'}): ${msg}`);
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ------------------------------------------------------------------
|
|
82
|
+
// 2. Lifecycle timestamp stamping (inline, mutates the row)
|
|
83
|
+
// ------------------------------------------------------------------
|
|
84
|
+
/**
|
|
85
|
+
* Stamps ResolvedAt / ClosedAt based on the NEW status's flags:
|
|
86
|
+
* - entering an IsResolved OR IsTerminal status → set ResolvedAt (if not already set)
|
|
87
|
+
* - entering an IsTerminal status → set ClosedAt
|
|
88
|
+
* - leaving into a non-terminal, non-resolved (active) status (reopen) → clear both
|
|
89
|
+
* Loads the engine for the IsResolved/IsTerminal lookup.
|
|
90
|
+
*/
|
|
91
|
+
async stampLifecycleTimestamps() {
|
|
92
|
+
await IssueEngine.Instance.Config(false, this.ContextCurrentUser);
|
|
93
|
+
const isResolved = IssueEngine.Instance.IsResolvedStatus(this.StatusID);
|
|
94
|
+
const isTerminal = IssueEngine.Instance.IsTerminalStatus(this.StatusID);
|
|
95
|
+
const now = new Date();
|
|
96
|
+
if (isTerminal) {
|
|
97
|
+
if (!this.ResolvedAt) {
|
|
98
|
+
this.ResolvedAt = now;
|
|
99
|
+
}
|
|
100
|
+
this.ClosedAt = now;
|
|
101
|
+
}
|
|
102
|
+
else if (isResolved) {
|
|
103
|
+
if (!this.ResolvedAt) {
|
|
104
|
+
this.ResolvedAt = now;
|
|
105
|
+
}
|
|
106
|
+
// Resolved-but-not-closed: ensure not marked closed.
|
|
107
|
+
this.ClosedAt = null;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Active (reopened or never resolved): clear lifecycle stamps.
|
|
111
|
+
this.ResolvedAt = null;
|
|
112
|
+
this.ClosedAt = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Registers a per-instance save-event handler (once) that fires the IssueType
|
|
117
|
+
* action hooks AFTER the save finalizes. Fire-and-forget; failures are logged,
|
|
118
|
+
* never propagated — a misconfigured hook must not break the save.
|
|
119
|
+
*/
|
|
120
|
+
ensureHookHandler() {
|
|
121
|
+
if (this._hookHandlerRegistered) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this._hookHandlerRegistered = true;
|
|
125
|
+
this.RegisterEventHandler((event) => {
|
|
126
|
+
if (event.type !== 'save') {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const ctx = this._pendingHookContext;
|
|
130
|
+
this._pendingHookContext = null;
|
|
131
|
+
if (!ctx) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.fireLifecycleHooks(ctx).catch((err) => {
|
|
135
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
LogError(`IssueEntityServer: lifecycle hook firing failed for issue ${this.ID}: ${msg}`);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** Dispatches the IssueType action hooks for the events that occurred this save. */
|
|
141
|
+
async fireLifecycleHooks(ctx) {
|
|
142
|
+
await IssueEngine.Instance.Config(false, this.ContextCurrentUser);
|
|
143
|
+
const issueType = IssueEngine.Instance.IssueTypeByID(this.IssueTypeID);
|
|
144
|
+
if (!issueType) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (ctx.isNew) {
|
|
148
|
+
await this.fireHook(issueType.OnCreateActionID);
|
|
149
|
+
}
|
|
150
|
+
if (ctx.statusChanged) {
|
|
151
|
+
await this.fireHook(issueType.OnStatusChangeActionID);
|
|
152
|
+
if (IssueEngine.Instance.IsTerminalStatus(this.StatusID)) {
|
|
153
|
+
await this.fireHook(issueType.OnCloseActionID);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (ctx.assigneeChanged) {
|
|
157
|
+
await this.fireHook(issueType.OnAssignActionID);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Fires a single IssueType action hook by Action ID, passing the issue's identity
|
|
162
|
+
* as input params. No-op when actionID is null. Failures are logged, not thrown.
|
|
163
|
+
*/
|
|
164
|
+
async fireHook(actionID) {
|
|
165
|
+
if (!actionID) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const contextUser = this.ContextCurrentUser;
|
|
170
|
+
await ActionEngineServer.Instance.Config(false, contextUser);
|
|
171
|
+
const action = ActionEngineServer.Instance.Actions.find((a) => a.ID === actionID);
|
|
172
|
+
if (!action) {
|
|
173
|
+
LogError(`IssueEntityServer.fireHook: Action ${actionID} not found`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const params = [
|
|
177
|
+
{ Name: 'IssueID', Value: this.ID, Type: 'Input' },
|
|
178
|
+
{ Name: 'IssueNumber', Value: this.IssueNumber, Type: 'Input' },
|
|
179
|
+
{ Name: 'Title', Value: this.Title, Type: 'Input' },
|
|
180
|
+
{ Name: 'StatusID', Value: this.StatusID, Type: 'Input' },
|
|
181
|
+
{ Name: 'Priority', Value: this.Priority, Type: 'Input' },
|
|
182
|
+
{ Name: 'Severity', Value: this.Severity, Type: 'Input' },
|
|
183
|
+
];
|
|
184
|
+
await ActionEngineServer.Instance.RunAction({
|
|
185
|
+
Action: action,
|
|
186
|
+
ContextUser: contextUser,
|
|
187
|
+
Params: params,
|
|
188
|
+
Filters: [],
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
193
|
+
LogError(`IssueEntityServer.fireHook: failed to run Action ${actionID}: ${msg}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
IssueEntityServer = __decorate([
|
|
198
|
+
RegisterClass(BaseEntity, 'MJ_BizApps_Issues: Issues', 2)
|
|
199
|
+
], IssueEntityServer);
|
|
200
|
+
export { IssueEntityServer };
|
|
201
|
+
//# sourceMappingURL=IssueEntityServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueEntityServer.js","sourceRoot":"","sources":["../src/IssueEntityServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BaseEntity } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* SequenceService — calls the DB-level atomic numbering routine (spAssignNextIssueNumber)
|
|
4
|
+
* from TypeScript so the IssueEntityServer hook can assign IssueNumber before
|
|
5
|
+
* super.Save() commits the row.
|
|
6
|
+
*
|
|
7
|
+
* The routine is intentionally kept at DB level because it requires atomic
|
|
8
|
+
* read-modify-write semantics that don't translate safely to app-level code
|
|
9
|
+
* under concurrency. It normalizes the scope (trim/UPPER, null/blank → 'ISS')
|
|
10
|
+
* and returns the formatted, unpadded `{SCOPE}-{seq}`.
|
|
11
|
+
*
|
|
12
|
+
* Platform-aware: MemberJunction runs on SQL Server or PostgreSQL, and the two
|
|
13
|
+
* expose the routine differently —
|
|
14
|
+
* * SQL Server: a PROCEDURE with an OUTPUT parameter, invoked via
|
|
15
|
+
* `DECLARE @x …; EXEC … @IssueNumber = @x OUTPUT; SELECT @x`.
|
|
16
|
+
* * PostgreSQL: a FUNCTION RETURNING TEXT (PG has no clean OUTPUT-param EXEC
|
|
17
|
+
* idiom), invoked via `SELECT schema.spAssignNextIssueNumber(:scope)`. The
|
|
18
|
+
* PG definition ships as a `.pg-only.sql` supplement under `migrations-pg/`.
|
|
19
|
+
* The dialect is selected from `DB_PLATFORM` (the same env var the MJ CLI and
|
|
20
|
+
* runtime use), defaulting to SQL Server when unset — matching the rest of the stack.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SequenceService {
|
|
23
|
+
/**
|
|
24
|
+
* Atomically allocates the next IssueNumber for the given AppScope and returns the
|
|
25
|
+
* formatted value (e.g. `MJC-42`, or `ISS-7` when AppScope is null/blank).
|
|
26
|
+
*
|
|
27
|
+
* The provider is taken from the calling entity so the call runs on the same
|
|
28
|
+
* (per-request) provider that owns the entity — never the process-global default.
|
|
29
|
+
*
|
|
30
|
+
* @param appScope The Issue's AppScope (may be null/blank — the routine defaults it to 'ISS').
|
|
31
|
+
* @param entity The Issue entity instance driving the save (supplies the provider + user).
|
|
32
|
+
*/
|
|
33
|
+
static assignNextIssueNumber(appScope: string | null, entity: BaseEntity): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* SQL Server: call the OUTPUT-parameter procedure and surface its value as a column.
|
|
36
|
+
* The proc re-normalizes the scope regardless of what we pass; we inline it as an escaped
|
|
37
|
+
* literal (the verified pattern across MJ's generated resolvers, which pass `undefined` params).
|
|
38
|
+
*/
|
|
39
|
+
private static buildSqlServerSQL;
|
|
40
|
+
/**
|
|
41
|
+
* PostgreSQL: call the function form and alias its scalar result to the `IssueNumber` column the
|
|
42
|
+
* caller reads. The function name is emitted UNQUOTED so PostgreSQL folds it to the same lowercase
|
|
43
|
+
* identifier the `CREATE FUNCTION` produced. The schema is likewise unquoted (folds to lowercase),
|
|
44
|
+
* matching how `mj codegen` and the MJServer runtime reference app-schema objects on PG.
|
|
45
|
+
*/
|
|
46
|
+
private static buildPostgresSQL;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=SequenceService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SequenceService.d.ts","sourceRoot":"","sources":["../src/SequenceService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkC,MAAM,sBAAsB,CAAC;AAKlF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,eAAe;IAC1B;;;;;;;;;OASG;WACiB,qBAAqB,CACvC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,MAAM,CAAC;IAkClB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAWhC;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAIhC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { LogError } from '@memberjunction/core';
|
|
2
|
+
import { resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
|
|
3
|
+
const ISSUES_SCHEMA = '__mj_BizAppsIssues';
|
|
4
|
+
/**
|
|
5
|
+
* SequenceService — calls the DB-level atomic numbering routine (spAssignNextIssueNumber)
|
|
6
|
+
* from TypeScript so the IssueEntityServer hook can assign IssueNumber before
|
|
7
|
+
* super.Save() commits the row.
|
|
8
|
+
*
|
|
9
|
+
* The routine is intentionally kept at DB level because it requires atomic
|
|
10
|
+
* read-modify-write semantics that don't translate safely to app-level code
|
|
11
|
+
* under concurrency. It normalizes the scope (trim/UPPER, null/blank → 'ISS')
|
|
12
|
+
* and returns the formatted, unpadded `{SCOPE}-{seq}`.
|
|
13
|
+
*
|
|
14
|
+
* Platform-aware: MemberJunction runs on SQL Server or PostgreSQL, and the two
|
|
15
|
+
* expose the routine differently —
|
|
16
|
+
* * SQL Server: a PROCEDURE with an OUTPUT parameter, invoked via
|
|
17
|
+
* `DECLARE @x …; EXEC … @IssueNumber = @x OUTPUT; SELECT @x`.
|
|
18
|
+
* * PostgreSQL: a FUNCTION RETURNING TEXT (PG has no clean OUTPUT-param EXEC
|
|
19
|
+
* idiom), invoked via `SELECT schema.spAssignNextIssueNumber(:scope)`. The
|
|
20
|
+
* PG definition ships as a `.pg-only.sql` supplement under `migrations-pg/`.
|
|
21
|
+
* The dialect is selected from `DB_PLATFORM` (the same env var the MJ CLI and
|
|
22
|
+
* runtime use), defaulting to SQL Server when unset — matching the rest of the stack.
|
|
23
|
+
*/
|
|
24
|
+
export class SequenceService {
|
|
25
|
+
/**
|
|
26
|
+
* Atomically allocates the next IssueNumber for the given AppScope and returns the
|
|
27
|
+
* formatted value (e.g. `MJC-42`, or `ISS-7` when AppScope is null/blank).
|
|
28
|
+
*
|
|
29
|
+
* The provider is taken from the calling entity so the call runs on the same
|
|
30
|
+
* (per-request) provider that owns the entity — never the process-global default.
|
|
31
|
+
*
|
|
32
|
+
* @param appScope The Issue's AppScope (may be null/blank — the routine defaults it to 'ISS').
|
|
33
|
+
* @param entity The Issue entity instance driving the save (supplies the provider + user).
|
|
34
|
+
*/
|
|
35
|
+
static async assignNextIssueNumber(appScope, entity) {
|
|
36
|
+
// ProviderToUse is typed IEntityDataProvider, but every concrete MJ provider (SQL Server /
|
|
37
|
+
// PostgreSQL) is a DatabaseProviderBase subclass that also implements IEntityDataProvider. The two
|
|
38
|
+
// interfaces don't structurally overlap, so TS requires the widening cast through `unknown` — this
|
|
39
|
+
// is the sanctioned mechanism for a cast between compatible-at-runtime types, NOT an `any` escape.
|
|
40
|
+
const provider = entity.ProviderToUse;
|
|
41
|
+
if (!provider) {
|
|
42
|
+
LogError('SequenceService.assignNextIssueNumber: entity has no provider');
|
|
43
|
+
throw new Error('SequenceService: no provider available on the entity');
|
|
44
|
+
}
|
|
45
|
+
// DB_PLATFORM defaults to SQL Server when unset (resolveDbPlatformFromEnv returns undefined).
|
|
46
|
+
const platform = resolveDbPlatformFromEnv() ?? 'sqlserver';
|
|
47
|
+
const sql = platform === 'postgresql'
|
|
48
|
+
? this.buildPostgresSQL(appScope)
|
|
49
|
+
: this.buildSqlServerSQL(appScope);
|
|
50
|
+
const rows = await provider.ExecuteSQL(sql, undefined, { isMutation: true, description: 'spAssignNextIssueNumber' }, entity.ContextCurrentUser);
|
|
51
|
+
const value = rows?.[0]?.IssueNumber;
|
|
52
|
+
if (!value || typeof value !== 'string') {
|
|
53
|
+
throw new Error(`SequenceService.assignNextIssueNumber: routine returned no value for AppScope=${appScope ?? '(null)'}`);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* SQL Server: call the OUTPUT-parameter procedure and surface its value as a column.
|
|
59
|
+
* The proc re-normalizes the scope regardless of what we pass; we inline it as an escaped
|
|
60
|
+
* literal (the verified pattern across MJ's generated resolvers, which pass `undefined` params).
|
|
61
|
+
*/
|
|
62
|
+
static buildSqlServerSQL(appScope) {
|
|
63
|
+
const scopeLiteral = appScope == null ? 'NULL' : `N'${appScope.replace(/'/g, "''")}'`;
|
|
64
|
+
return `
|
|
65
|
+
DECLARE @issueNumber NVARCHAR(50);
|
|
66
|
+
EXEC ${ISSUES_SCHEMA}.spAssignNextIssueNumber
|
|
67
|
+
@AppScope = ${scopeLiteral},
|
|
68
|
+
@IssueNumber = @issueNumber OUTPUT;
|
|
69
|
+
SELECT @issueNumber AS IssueNumber;
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* PostgreSQL: call the function form and alias its scalar result to the `IssueNumber` column the
|
|
74
|
+
* caller reads. The function name is emitted UNQUOTED so PostgreSQL folds it to the same lowercase
|
|
75
|
+
* identifier the `CREATE FUNCTION` produced. The schema is likewise unquoted (folds to lowercase),
|
|
76
|
+
* matching how `mj codegen` and the MJServer runtime reference app-schema objects on PG.
|
|
77
|
+
*/
|
|
78
|
+
static buildPostgresSQL(appScope) {
|
|
79
|
+
const scopeLiteral = appScope == null ? 'NULL' : `'${appScope.replace(/'/g, "''")}'`;
|
|
80
|
+
return `SELECT ${ISSUES_SCHEMA}.spAssignNextIssueNumber(${scopeLiteral}) AS "IssueNumber";`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=SequenceService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SequenceService.js","sourceRoot":"","sources":["../src/SequenceService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AAErF,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,eAAe;IAC1B;;;;;;;;;OASG;IACI,MAAM,CAAC,KAAK,CAAC,qBAAqB,CACvC,QAAuB,EACvB,MAAkB;QAElB,2FAA2F;QAC3F,mGAAmG;QACnG,mGAAmG;QACnG,mGAAmG;QACnG,MAAM,QAAQ,GAAG,MAAM,CAAC,aAA4D,CAAC;QACrF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,CAAC,+DAA+D,CAAC,CAAC;YAC1E,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QAED,8FAA8F;QAC9F,MAAM,QAAQ,GAAG,wBAAwB,EAAE,IAAI,WAAW,CAAC;QAC3D,MAAM,GAAG,GACP,QAAQ,KAAK,YAAY;YACvB,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YACjC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAEvC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,CACpC,GAAG,EACH,SAAS,EACT,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,yBAAyB,EAAE,EAC5D,MAAM,CAAC,kBAAkB,CAC1B,CAAC;QAEF,MAAM,KAAK,GAAI,IAAI,EAAE,CAAC,CAAC,CAA2C,EAAE,WAAW,CAAC;QAChF,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACb,iFAAiF,QAAQ,IAAI,QAAQ,EAAE,CACxG,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,iBAAiB,CAAC,QAAuB;QACtD,MAAM,YAAY,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;QACtF,OAAO;;aAEE,aAAa;wBACF,YAAY;;;KAG/B,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAC,gBAAgB,CAAC,QAAuB;QACrD,MAAM,YAAY,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;QACrF,OAAO,UAAU,aAAa,4BAA4B,YAAY,qBAAqB,CAAC;IAC9F,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mj-biz-apps/issues-core-entities-server
|
|
3
|
+
*
|
|
4
|
+
* Server-side entity subclasses for BizApps Issues entities. These hold side-effects
|
|
5
|
+
* that must run server-only and authoritatively (not in the browser) — currently the
|
|
6
|
+
* assignment of the human-readable Issue.IssueNumber via an atomic DB sequence proc.
|
|
7
|
+
*
|
|
8
|
+
* Import this package (or call LoadBizAppsIssuesEntitiesServer) from the server
|
|
9
|
+
* bootstrap so the @RegisterClass decorators fire at startup.
|
|
10
|
+
*/
|
|
11
|
+
export { IssueEntityServer } from './IssueEntityServer.js';
|
|
12
|
+
export { SequenceService } from './SequenceService.js';
|
|
13
|
+
/**
|
|
14
|
+
* Forces the server-side entity subclasses to load so their @RegisterClass
|
|
15
|
+
* decorators register (priority 2, overriding the client-shared entities).
|
|
16
|
+
* Tree-shaking would otherwise drop them since they're referenced only via the
|
|
17
|
+
* class factory.
|
|
18
|
+
*/
|
|
19
|
+
export declare function LoadBizAppsIssuesEntitiesServer(): void;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,IAAI,CAGtD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mj-biz-apps/issues-core-entities-server
|
|
3
|
+
*
|
|
4
|
+
* Server-side entity subclasses for BizApps Issues entities. These hold side-effects
|
|
5
|
+
* that must run server-only and authoritatively (not in the browser) — currently the
|
|
6
|
+
* assignment of the human-readable Issue.IssueNumber via an atomic DB sequence proc.
|
|
7
|
+
*
|
|
8
|
+
* Import this package (or call LoadBizAppsIssuesEntitiesServer) from the server
|
|
9
|
+
* bootstrap so the @RegisterClass decorators fire at startup.
|
|
10
|
+
*/
|
|
11
|
+
import { IssueEntityServer } from './IssueEntityServer.js';
|
|
12
|
+
export { IssueEntityServer } from './IssueEntityServer.js';
|
|
13
|
+
export { SequenceService } from './SequenceService.js';
|
|
14
|
+
/**
|
|
15
|
+
* Forces the server-side entity subclasses to load so their @RegisterClass
|
|
16
|
+
* decorators register (priority 2, overriding the client-shared entities).
|
|
17
|
+
* Tree-shaking would otherwise drop them since they're referenced only via the
|
|
18
|
+
* class factory.
|
|
19
|
+
*/
|
|
20
|
+
export function LoadBizAppsIssuesEntitiesServer() {
|
|
21
|
+
// Reference the class so the import is retained and its decorator runs.
|
|
22
|
+
void IssueEntityServer;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B;IAC7C,wEAAwE;IACxE,KAAK,iBAAiB,CAAC;AACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mj-biz-apps/issues-core-entities-server",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Server-side entity subclasses for BizApps Issues — lifecycle hooks for Issue, IssueComment, etc. (stamp ResolvedAt/ClosedAt, fire IssueType action hooks).",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"/dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && tsc-alias -f",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest"
|
|
18
|
+
},
|
|
19
|
+
"author": "MemberJunction.com",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"typescript": "^5.9.3"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@mj-biz-apps/issues-entities": "1.0.0",
|
|
26
|
+
"@mj-biz-apps/issues-core": "1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@memberjunction/core": "^5.40.2",
|
|
30
|
+
"@memberjunction/core-entities": "^5.40.2",
|
|
31
|
+
"@memberjunction/generic-database-provider": "^5.40.2",
|
|
32
|
+
"@memberjunction/global": "^5.40.2",
|
|
33
|
+
"@memberjunction/actions": "^5.40.2",
|
|
34
|
+
"@memberjunction/actions-base": "^5.40.2"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/MemberJunction/bizapps-issues"
|
|
39
|
+
}
|
|
10
40
|
}
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# @mj-biz-apps/issues-core-entities-server
|
|
2
|
-
|
|
3
|
-
## ⚠️ IMPORTANT NOTICE ⚠️
|
|
4
|
-
|
|
5
|
-
**This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
|
|
6
|
-
|
|
7
|
-
This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
This package exists to:
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@mj-biz-apps/issues-core-entities-server`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
15
|
-
|
|
16
|
-
## What is OIDC Trusted Publishing?
|
|
17
|
-
|
|
18
|
-
OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
|
|
19
|
-
|
|
20
|
-
## Setup Instructions
|
|
21
|
-
|
|
22
|
-
To properly configure OIDC trusted publishing for this package:
|
|
23
|
-
|
|
24
|
-
1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
28
|
-
|
|
29
|
-
## DO NOT USE THIS PACKAGE
|
|
30
|
-
|
|
31
|
-
This package is a placeholder for OIDC configuration only. It:
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
-
|
|
37
|
-
## More Information
|
|
38
|
-
|
|
39
|
-
For more details about npm's trusted publishing feature, see:
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
**Maintained for OIDC setup purposes only**
|