@campfire-interactive/master-data-client 5.24.0 → 5.26.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/equipment.d.ts +9 -1
- package/dist/equipment.d.ts.map +1 -1
- package/dist/equipment.js +12 -0
- package/dist/equipment.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/programs.d.ts +65 -0
- package/dist/programs.d.ts.map +1 -0
- package/dist/programs.js +193 -0
- package/dist/programs.js.map +1 -0
- package/dist/quotes.d.ts +11 -1
- package/dist/quotes.d.ts.map +1 -1
- package/dist/quotes.js +21 -0
- package/dist/quotes.js.map +1 -1
- package/dist/scopeGate.d.ts +103 -0
- package/dist/scopeGate.d.ts.map +1 -0
- package/dist/scopeGate.js +155 -0
- package/dist/scopeGate.js.map +1 -0
- package/dist/standardAttributes.d.ts +80 -0
- package/dist/standardAttributes.d.ts.map +1 -0
- package/dist/standardAttributes.js +188 -0
- package/dist/standardAttributes.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +31 -31
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { HttpTransport } from './http';
|
|
2
|
+
import type { ScopeDimension, SingleResponse } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* The scope gate: who may see which records, once a tenant turns gating on.
|
|
5
|
+
*
|
|
6
|
+
* ONE implementation, shared. master-data can express the gate as an RLS policy
|
|
7
|
+
* because it owns the tables; OMSF and pm cannot — they have no RLS extension,
|
|
8
|
+
* so their gate is a clause in a query builder. A clause copied into a dozen
|
|
9
|
+
* call sites is a clause that gets missed in one of them, and a missed scope
|
|
10
|
+
* clause is a data leak rather than a cosmetic bug. So it lives here, with the
|
|
11
|
+
* fetching and caching it needs, and callers spread the result.
|
|
12
|
+
*
|
|
13
|
+
* TWO RULES SHAPE EVERYTHING, and both fail OPEN by deliberate decision
|
|
14
|
+
* (nextgen ADR 2026-09-14, decisions 3 and 4):
|
|
15
|
+
*
|
|
16
|
+
* - A user with NO assignment is unrestricted. On the day gating ships nobody
|
|
17
|
+
* has an assignment, and failing closed would lock out every user in the
|
|
18
|
+
* tenant at once — with the omission that caused it looking exactly like
|
|
19
|
+
* the feature working.
|
|
20
|
+
* - A record with NO scope is visible to everyone. Almost nothing is scoped
|
|
21
|
+
* at first, so failing closed would hide the entire dataset until someone
|
|
22
|
+
* hand-scoped it.
|
|
23
|
+
*
|
|
24
|
+
* The consequence, which is easy to misread as the gate being broken: gating
|
|
25
|
+
* restricts nothing until BOTH a user is assigned AND records are scoped.
|
|
26
|
+
*/
|
|
27
|
+
export interface UserScopeSets {
|
|
28
|
+
userId: string;
|
|
29
|
+
geographicScopeIds: string[];
|
|
30
|
+
productScopeIds: string[];
|
|
31
|
+
}
|
|
32
|
+
/** A Prisma-shaped `where` fragment. Deliberately a plain object: this package
|
|
33
|
+
* has no Prisma dependency and does not want one, and every consumer speaks
|
|
34
|
+
* this shape. Spread it into an existing `where`. */
|
|
35
|
+
export type ScopeGatePredicate = Record<string, unknown>;
|
|
36
|
+
export interface BuildScopeGateOptions {
|
|
37
|
+
/** Which dimensions the tenant has gating switched ON for. A dimension that
|
|
38
|
+
* is off contributes no clause at all. */
|
|
39
|
+
gatedDimensions: ScopeDimension[];
|
|
40
|
+
/** Column names, so a consumer whose table spells them differently can say
|
|
41
|
+
* so. Defaults match master-data and OMSF. */
|
|
42
|
+
columns?: {
|
|
43
|
+
geographic?: string;
|
|
44
|
+
product?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the `where` fragment restricting a list to what this user may see.
|
|
49
|
+
*
|
|
50
|
+
* Returns an EMPTY object when the gate should not restrict — spreading `{}`
|
|
51
|
+
* into a `where` is a no-op, so a caller never has to branch on "is gating on".
|
|
52
|
+
*
|
|
53
|
+
* Per dimension, when gating is on for it AND the user has assignments:
|
|
54
|
+
*
|
|
55
|
+
* { OR: [ { <col>: null }, { <col>: { in: [...] } } ] }
|
|
56
|
+
*
|
|
57
|
+
* The `null` branch is rule 2 — an unscoped record is visible to everyone. Drop
|
|
58
|
+
* it and the gate hides almost the whole dataset on day one.
|
|
59
|
+
*
|
|
60
|
+
* Both dimensions gated produces an AND of the two, so a user must match on
|
|
61
|
+
* each. That is intersection, not union: someone assigned to Europe and to
|
|
62
|
+
* Doors sees European Doors work, which is what "my slice" means to the person
|
|
63
|
+
* asking for this feature.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildScopeGate(scopes: UserScopeSets | null, options: BuildScopeGateOptions): ScopeGatePredicate;
|
|
66
|
+
/** Clear everything. Exposed for tests and for a process that wants a clean
|
|
67
|
+
* slate; ordinary revocation is handled by the TTL. */
|
|
68
|
+
export declare function clearScopeCache(): void;
|
|
69
|
+
export declare class UserScopeResource {
|
|
70
|
+
private readonly http;
|
|
71
|
+
private readonly ttlMs;
|
|
72
|
+
private readonly cache;
|
|
73
|
+
constructor(http: HttpTransport, ttlMs?: number);
|
|
74
|
+
/** The caller's own sets, uncached. */
|
|
75
|
+
me(): Promise<SingleResponse<UserScopeSets>>;
|
|
76
|
+
/**
|
|
77
|
+
* The caller's own sets, cached for the TTL.
|
|
78
|
+
*
|
|
79
|
+
* Returns `null` rather than throwing when master-data cannot be reached.
|
|
80
|
+
* That is deliberate and it is the fail-open rule again: a gate that throws
|
|
81
|
+
* on a network blip takes every list in the app down, which is a worse
|
|
82
|
+
* outcome than briefly not restricting a feature that restricts nothing for
|
|
83
|
+
* most tenants anyway. Callers pass the null straight to buildScopeGate.
|
|
84
|
+
*/
|
|
85
|
+
mineCached(cacheKey: string): Promise<UserScopeSets | null>;
|
|
86
|
+
/** Drop a cached entry, so an admin who just changed an assignment can see it
|
|
87
|
+
* take effect without waiting out the TTL. */
|
|
88
|
+
invalidate(cacheKey: string): void;
|
|
89
|
+
/** Admin surface: every user in the tenant WITH an assignment. Users with
|
|
90
|
+
* none are absent — master-data does not know the tenant's roster, so the
|
|
91
|
+
* caller joins this against identity's user list. */
|
|
92
|
+
list(): Promise<{
|
|
93
|
+
data: UserScopeSets[];
|
|
94
|
+
}>;
|
|
95
|
+
get(userId: string): Promise<SingleResponse<UserScopeSets>>;
|
|
96
|
+
/** Replace a user's sets. Omit a dimension to leave it alone; send `[]` to
|
|
97
|
+
* clear it, which returns the user to unrestricted. */
|
|
98
|
+
set(userId: string, input: {
|
|
99
|
+
geographicScopeIds?: string[];
|
|
100
|
+
productScopeIds?: string[];
|
|
101
|
+
}, idempotencyKey?: string): Promise<SingleResponse<UserScopeSets>>;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=scopeGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopeGate.d.ts","sourceRoot":"","sources":["../src/scopeGate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;sDAEsD;AACtD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD,MAAM,WAAW,qBAAqB;IACpC;+CAC2C;IAC3C,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC;mDAC+C;IAC/C,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,GAAG,IAAI,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,kBAAkB,CAyBpB;AAiCD;wDACwD;AACxD,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;gBAGjB,IAAI,EAAE,aAAa,EACnB,KAAK,GAAE,MAAe;IAGzC,uCAAuC;IACjC,EAAE,IAAI,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAOlD;;;;;;;;OAQG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAejE;mDAC+C;IAC/C,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIlC;;0DAEsD;IAChD,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC;IAO1C,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAOjE;4DACwD;IAClD,GAAG,CACP,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;QAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,EACpE,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;CAQ1C"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UserScopeResource = void 0;
|
|
4
|
+
exports.buildScopeGate = buildScopeGate;
|
|
5
|
+
exports.clearScopeCache = clearScopeCache;
|
|
6
|
+
/**
|
|
7
|
+
* Build the `where` fragment restricting a list to what this user may see.
|
|
8
|
+
*
|
|
9
|
+
* Returns an EMPTY object when the gate should not restrict — spreading `{}`
|
|
10
|
+
* into a `where` is a no-op, so a caller never has to branch on "is gating on".
|
|
11
|
+
*
|
|
12
|
+
* Per dimension, when gating is on for it AND the user has assignments:
|
|
13
|
+
*
|
|
14
|
+
* { OR: [ { <col>: null }, { <col>: { in: [...] } } ] }
|
|
15
|
+
*
|
|
16
|
+
* The `null` branch is rule 2 — an unscoped record is visible to everyone. Drop
|
|
17
|
+
* it and the gate hides almost the whole dataset on day one.
|
|
18
|
+
*
|
|
19
|
+
* Both dimensions gated produces an AND of the two, so a user must match on
|
|
20
|
+
* each. That is intersection, not union: someone assigned to Europe and to
|
|
21
|
+
* Doors sees European Doors work, which is what "my slice" means to the person
|
|
22
|
+
* asking for this feature.
|
|
23
|
+
*/
|
|
24
|
+
function buildScopeGate(scopes, options) {
|
|
25
|
+
// No scope information at all — treat as unrestricted rather than guessing.
|
|
26
|
+
// A resolver that failed is the likely cause, and failing a read closed on a
|
|
27
|
+
// network blip would take the app down for everyone.
|
|
28
|
+
if (!scopes)
|
|
29
|
+
return {};
|
|
30
|
+
const geoColumn = options.columns?.geographic ?? 'geographicScopeId';
|
|
31
|
+
const productColumn = options.columns?.product ?? 'productScopeId';
|
|
32
|
+
const clauses = [];
|
|
33
|
+
if (options.gatedDimensions.includes('geographic') && scopes.geographicScopeIds.length > 0) {
|
|
34
|
+
clauses.push({
|
|
35
|
+
OR: [{ [geoColumn]: null }, { [geoColumn]: { in: [...scopes.geographicScopeIds] } }],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (options.gatedDimensions.includes('product') && scopes.productScopeIds.length > 0) {
|
|
39
|
+
clauses.push({
|
|
40
|
+
OR: [{ [productColumn]: null }, { [productColumn]: { in: [...scopes.productScopeIds] } }],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (clauses.length === 0)
|
|
44
|
+
return {};
|
|
45
|
+
if (clauses.length === 1)
|
|
46
|
+
return clauses[0];
|
|
47
|
+
return { AND: clauses };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The caller's own scope sets, cached briefly.
|
|
51
|
+
*
|
|
52
|
+
* The cache exists because the gate needs this on EVERY request in OMSF and pm,
|
|
53
|
+
* and a cross-service hop in front of every list query is the one place latency
|
|
54
|
+
* is most visible. master-data itself needs none of this — its tables are local.
|
|
55
|
+
*
|
|
56
|
+
* **The TTL is a revocation window.** Removing someone's scope does not take
|
|
57
|
+
* effect until their entry expires. 60 seconds is the agreed value: short
|
|
58
|
+
* enough that "I removed her access and she can still see it" never becomes a
|
|
59
|
+
* support call, long enough that a warm Lambda makes roughly one call per user
|
|
60
|
+
* per container lifetime.
|
|
61
|
+
*
|
|
62
|
+
* Keyed by tenant AND user: a container serves many callers, and the whole
|
|
63
|
+
* point of the gate is that they get different answers.
|
|
64
|
+
*/
|
|
65
|
+
/**
|
|
66
|
+
* MODULE-LEVEL, not per-instance, and that is not an optimization — it is the
|
|
67
|
+
* only thing that makes the cache work at all.
|
|
68
|
+
*
|
|
69
|
+
* OMSF constructs a fresh `MasterDataClient` on every call, because the auth
|
|
70
|
+
* token comes from the request context. A cache living on the resource instance
|
|
71
|
+
* would therefore be born and discarded inside a single request and never once
|
|
72
|
+
* be read, while looking entirely correct. Hoisting it to the module makes the
|
|
73
|
+
* lifetime what the design assumes: the container's.
|
|
74
|
+
*
|
|
75
|
+
* Safe to share because every key carries the tenant AND the user — two callers
|
|
76
|
+
* can never collide, which is the whole point of the gate.
|
|
77
|
+
*/
|
|
78
|
+
const scopeCache = new Map();
|
|
79
|
+
/** Clear everything. Exposed for tests and for a process that wants a clean
|
|
80
|
+
* slate; ordinary revocation is handled by the TTL. */
|
|
81
|
+
function clearScopeCache() {
|
|
82
|
+
scopeCache.clear();
|
|
83
|
+
}
|
|
84
|
+
class UserScopeResource {
|
|
85
|
+
http;
|
|
86
|
+
ttlMs;
|
|
87
|
+
cache = scopeCache;
|
|
88
|
+
constructor(http, ttlMs = 60_000) {
|
|
89
|
+
this.http = http;
|
|
90
|
+
this.ttlMs = ttlMs;
|
|
91
|
+
}
|
|
92
|
+
/** The caller's own sets, uncached. */
|
|
93
|
+
async me() {
|
|
94
|
+
return this.http.request({
|
|
95
|
+
method: 'GET',
|
|
96
|
+
path: '/v1/user-scopes/me',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The caller's own sets, cached for the TTL.
|
|
101
|
+
*
|
|
102
|
+
* Returns `null` rather than throwing when master-data cannot be reached.
|
|
103
|
+
* That is deliberate and it is the fail-open rule again: a gate that throws
|
|
104
|
+
* on a network blip takes every list in the app down, which is a worse
|
|
105
|
+
* outcome than briefly not restricting a feature that restricts nothing for
|
|
106
|
+
* most tenants anyway. Callers pass the null straight to buildScopeGate.
|
|
107
|
+
*/
|
|
108
|
+
async mineCached(cacheKey) {
|
|
109
|
+
const hit = this.cache.get(cacheKey);
|
|
110
|
+
if (hit && Date.now() - hit.at < this.ttlMs)
|
|
111
|
+
return hit.value;
|
|
112
|
+
try {
|
|
113
|
+
const response = await this.me();
|
|
114
|
+
this.cache.set(cacheKey, { at: Date.now(), value: response.data });
|
|
115
|
+
return response.data;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Serve a stale entry if we have one — it is closer to the truth than
|
|
119
|
+
// nothing, and it keeps the revocation window bounded to the outage.
|
|
120
|
+
return hit ? hit.value : null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Drop a cached entry, so an admin who just changed an assignment can see it
|
|
124
|
+
* take effect without waiting out the TTL. */
|
|
125
|
+
invalidate(cacheKey) {
|
|
126
|
+
this.cache.delete(cacheKey);
|
|
127
|
+
}
|
|
128
|
+
/** Admin surface: every user in the tenant WITH an assignment. Users with
|
|
129
|
+
* none are absent — master-data does not know the tenant's roster, so the
|
|
130
|
+
* caller joins this against identity's user list. */
|
|
131
|
+
async list() {
|
|
132
|
+
return this.http.request({
|
|
133
|
+
method: 'GET',
|
|
134
|
+
path: '/v1/user-scopes',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async get(userId) {
|
|
138
|
+
return this.http.request({
|
|
139
|
+
method: 'GET',
|
|
140
|
+
path: `/v1/user-scopes/${encodeURIComponent(userId)}`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/** Replace a user's sets. Omit a dimension to leave it alone; send `[]` to
|
|
144
|
+
* clear it, which returns the user to unrestricted. */
|
|
145
|
+
async set(userId, input, idempotencyKey) {
|
|
146
|
+
return this.http.request({
|
|
147
|
+
method: 'PUT',
|
|
148
|
+
path: `/v1/user-scopes/${encodeURIComponent(userId)}`,
|
|
149
|
+
body: input,
|
|
150
|
+
idempotencyKey,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.UserScopeResource = UserScopeResource;
|
|
155
|
+
//# sourceMappingURL=scopeGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopeGate.js","sourceRoot":"","sources":["../src/scopeGate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { HttpTransport } from './http';
|
|
2
|
+
import type { StandardAttribute, CreateStandardAttributeInput, CreateStandardAttributeDefaultInput, UpdateStandardAttributeInput, StandardAttributeValue, SetStandardAttributeValueInput, SetStandardAttributeValueResult, StandardAttributeHistoryEntry, StandardAttributeDefault, UpdateStandardAttributeDefaultInput, SingleResponse, ListResponse } from './types';
|
|
3
|
+
export declare class StandardAttributeResource {
|
|
4
|
+
private readonly http;
|
|
5
|
+
constructor(http: HttpTransport);
|
|
6
|
+
/** Add an attribute to THIS TENANT. Filled by a person — the enrichment
|
|
7
|
+
* pass only knows the platform catalog. */
|
|
8
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
9
|
+
create(input: CreateStandardAttributeInput, idempotencyKey?: string): Promise<SingleResponse<StandardAttribute>>;
|
|
10
|
+
/** ARCHIVE one. It stops being offered and every value already recorded
|
|
11
|
+
* against it stays readable — so this never conflicts with what is stored,
|
|
12
|
+
* and it is reversible. */
|
|
13
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
14
|
+
archive(id: string): Promise<SingleResponse<StandardAttribute>>;
|
|
15
|
+
/** This tenant's attribute catalog, in display order. */
|
|
16
|
+
list(options?: {
|
|
17
|
+
enabledOnly?: boolean;
|
|
18
|
+
}): Promise<ListResponse<StandardAttribute>>;
|
|
19
|
+
/** Rename, reorder, enable or disable one attribute. `key` is immutable. */
|
|
20
|
+
update(id: string, input: UpdateStandardAttributeInput, idempotencyKey?: string): Promise<SingleResponse<StandardAttribute>>;
|
|
21
|
+
/**
|
|
22
|
+
* Quote ids whose attribute VALUES match free text.
|
|
23
|
+
*
|
|
24
|
+
* Prefer `quotes.list({ q })` — it matches these too, and it filters the page,
|
|
25
|
+
* so the count and the cursor agree with what you get. Reach for this only
|
|
26
|
+
* when you are narrowing an already-fetched list in a browser and need to know
|
|
27
|
+
* which rows matched on an attribute rather than on a visible column.
|
|
28
|
+
*
|
|
29
|
+
* Enabled, active attributes only: one switched off or archived is not offered
|
|
30
|
+
* on a quote, so a row returned because it matched one would be returned for a
|
|
31
|
+
* reason the user cannot see anywhere on screen.
|
|
32
|
+
*/
|
|
33
|
+
searchQuoteIds(q: string): Promise<SingleResponse<{
|
|
34
|
+
ids: string[];
|
|
35
|
+
}>>;
|
|
36
|
+
/** Every stored value on one quote, in catalog order. */
|
|
37
|
+
listValues(quoteId: string): Promise<ListResponse<StandardAttributeValue>>;
|
|
38
|
+
/**
|
|
39
|
+
* Write values on a quote.
|
|
40
|
+
*
|
|
41
|
+
* Send the whole set in one call rather than looping: the server writes them
|
|
42
|
+
* in a single transaction, and `onlyIfBlank` on each input is what makes the
|
|
43
|
+
* enrichment pass fill blanks without ever overwriting a rep's correction.
|
|
44
|
+
*/
|
|
45
|
+
setValues(quoteId: string, values: SetStandardAttributeValueInput[], idempotencyKey?: string): Promise<ListResponse<SetStandardAttributeValueResult>>;
|
|
46
|
+
/** Every stored value on one opportunity, in catalog order. */
|
|
47
|
+
listOpportunityValues(opportunityId: string): Promise<ListResponse<StandardAttributeValue>>;
|
|
48
|
+
/** Write values on an opportunity. Send the whole set in one call. */
|
|
49
|
+
setOpportunityValues(opportunityId: string, values: SetStandardAttributeValueInput[], idempotencyKey?: string): Promise<ListResponse<SetStandardAttributeValueResult>>;
|
|
50
|
+
/** One attribute's timeline on an opportunity, or the whole one's when no key. */
|
|
51
|
+
listOpportunityHistory(opportunityId: string, key?: string): Promise<ListResponse<StandardAttributeHistoryEntry>>;
|
|
52
|
+
/** One attribute's timeline on a quote, or the whole quote's when no key. */
|
|
53
|
+
listHistory(quoteId: string, key?: string): Promise<ListResponse<StandardAttributeHistoryEntry>>;
|
|
54
|
+
/** Add an attribute to the PLATFORM catalog. Seeds NEW tenants only —
|
|
55
|
+
* tenants already provisioned keep the copy they have. */
|
|
56
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
57
|
+
createDefault(input: CreateStandardAttributeDefaultInput, idempotencyKey?: string): Promise<SingleResponse<StandardAttributeDefault>>;
|
|
58
|
+
/** Stop seeding one into new tenants. Existing tenant copies and every value
|
|
59
|
+
* ever recorded against the key are untouched. */
|
|
60
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
61
|
+
removeDefault(id: string): Promise<SingleResponse<{
|
|
62
|
+
id: string;
|
|
63
|
+
}>>;
|
|
64
|
+
/**
|
|
65
|
+
* The PLATFORM-wide defaults, in display order — what a new tenant's copy is
|
|
66
|
+
* seeded from. Readable by any tenant; only the platform tenant can write.
|
|
67
|
+
*/
|
|
68
|
+
listDefaults(): Promise<ListResponse<StandardAttributeDefault>>;
|
|
69
|
+
/**
|
|
70
|
+
* Rename or reorder one platform default.
|
|
71
|
+
*
|
|
72
|
+
* Changes what the NEXT tenant is seeded with. It does not reach tenants
|
|
73
|
+
* already provisioned — their copy is theirs to name.
|
|
74
|
+
*
|
|
75
|
+
* `key` is immutable — it is what every stored value references.
|
|
76
|
+
*/
|
|
77
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
78
|
+
updateDefault(id: string, input: UpdateStandardAttributeDefaultInput, idempotencyKey?: string): Promise<SingleResponse<StandardAttributeDefault>>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=standardAttributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standardAttributes.d.ts","sourceRoot":"","sources":["../src/standardAttributes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StandardAttributeResource = void 0;
|
|
4
|
+
// Standard Attributes: the platform-owned set of vehicle and program facts a
|
|
5
|
+
// quote carries, each with the source it came from and a full change history.
|
|
6
|
+
// See nextgen docs/decisions/2026-09-18-standard-attributes.md.
|
|
7
|
+
//
|
|
8
|
+
// The catalog is landlord-owned and provisioned per tenant, and a tenant can
|
|
9
|
+
// add its own beside the seeded ones. Nothing is ever destroyed: a tenant
|
|
10
|
+
// ARCHIVES an attribute, which stops it being offered and leaves every recorded
|
|
11
|
+
// value readable. `key` is immutable throughout.
|
|
12
|
+
class StandardAttributeResource {
|
|
13
|
+
http;
|
|
14
|
+
constructor(http) {
|
|
15
|
+
this.http = http;
|
|
16
|
+
}
|
|
17
|
+
/** Add an attribute to THIS TENANT. Filled by a person — the enrichment
|
|
18
|
+
* pass only knows the platform catalog. */
|
|
19
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
20
|
+
async create(input, idempotencyKey) {
|
|
21
|
+
return this.http.request({
|
|
22
|
+
method: 'POST',
|
|
23
|
+
path: '/v1/standard-attributes',
|
|
24
|
+
body: input,
|
|
25
|
+
idempotencyKey,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** ARCHIVE one. It stops being offered and every value already recorded
|
|
29
|
+
* against it stays readable — so this never conflicts with what is stored,
|
|
30
|
+
* and it is reversible. */
|
|
31
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
32
|
+
async archive(id) {
|
|
33
|
+
return this.http.request({
|
|
34
|
+
method: 'DELETE',
|
|
35
|
+
path: `/v1/standard-attributes/${encodeURIComponent(id)}`,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** This tenant's attribute catalog, in display order. */
|
|
39
|
+
async list(options) {
|
|
40
|
+
const query = options?.enabledOnly ? '?enabledOnly=true' : '';
|
|
41
|
+
return this.http.request({
|
|
42
|
+
method: 'GET',
|
|
43
|
+
path: `/v1/standard-attributes${query}`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/** Rename, reorder, enable or disable one attribute. `key` is immutable. */
|
|
47
|
+
async update(id, input, idempotencyKey) {
|
|
48
|
+
return this.http.request({
|
|
49
|
+
method: 'PATCH',
|
|
50
|
+
path: `/v1/standard-attributes/${encodeURIComponent(id)}`,
|
|
51
|
+
body: input,
|
|
52
|
+
idempotencyKey,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Quote ids whose attribute VALUES match free text.
|
|
57
|
+
*
|
|
58
|
+
* Prefer `quotes.list({ q })` — it matches these too, and it filters the page,
|
|
59
|
+
* so the count and the cursor agree with what you get. Reach for this only
|
|
60
|
+
* when you are narrowing an already-fetched list in a browser and need to know
|
|
61
|
+
* which rows matched on an attribute rather than on a visible column.
|
|
62
|
+
*
|
|
63
|
+
* Enabled, active attributes only: one switched off or archived is not offered
|
|
64
|
+
* on a quote, so a row returned because it matched one would be returned for a
|
|
65
|
+
* reason the user cannot see anywhere on screen.
|
|
66
|
+
*/
|
|
67
|
+
async searchQuoteIds(q) {
|
|
68
|
+
return this.http.request({
|
|
69
|
+
method: 'GET',
|
|
70
|
+
path: `/v1/standard-attributes/search?q=${encodeURIComponent(q)}`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Every stored value on one quote, in catalog order. */
|
|
74
|
+
async listValues(quoteId) {
|
|
75
|
+
return this.http.request({
|
|
76
|
+
method: 'GET',
|
|
77
|
+
path: `/v1/quotes/${encodeURIComponent(quoteId)}/standard-attributes`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Write values on a quote.
|
|
82
|
+
*
|
|
83
|
+
* Send the whole set in one call rather than looping: the server writes them
|
|
84
|
+
* in a single transaction, and `onlyIfBlank` on each input is what makes the
|
|
85
|
+
* enrichment pass fill blanks without ever overwriting a rep's correction.
|
|
86
|
+
*/
|
|
87
|
+
async setValues(quoteId, values, idempotencyKey) {
|
|
88
|
+
return this.http.request({
|
|
89
|
+
method: 'PUT',
|
|
90
|
+
path: `/v1/quotes/${encodeURIComponent(quoteId)}/standard-attributes`,
|
|
91
|
+
body: { values },
|
|
92
|
+
idempotencyKey,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// ── The same three, against an opportunity ────────────────────────────────
|
|
96
|
+
//
|
|
97
|
+
// An opportunity's Program & Vehicle values used to be resolved live and
|
|
98
|
+
// stored nowhere, so there was no home for a value somebody typed or for a
|
|
99
|
+
// migration to land. These give it the same store a quote has.
|
|
100
|
+
//
|
|
101
|
+
// The opportunity is an OMSF record; master-data holds the values against a
|
|
102
|
+
// loose id and does not check that it names anything. Values on an
|
|
103
|
+
// opportunity are independent of its quotes' — a quote copies at create via
|
|
104
|
+
// the enrichment pass and then diverges, so that an approver's figures cannot
|
|
105
|
+
// move because somebody edited the opportunity.
|
|
106
|
+
/** Every stored value on one opportunity, in catalog order. */
|
|
107
|
+
async listOpportunityValues(opportunityId) {
|
|
108
|
+
return this.http.request({
|
|
109
|
+
method: 'GET',
|
|
110
|
+
path: `/v1/opportunities/${encodeURIComponent(opportunityId)}/standard-attributes`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Write values on an opportunity. Send the whole set in one call. */
|
|
114
|
+
async setOpportunityValues(opportunityId, values, idempotencyKey) {
|
|
115
|
+
return this.http.request({
|
|
116
|
+
method: 'PUT',
|
|
117
|
+
path: `/v1/opportunities/${encodeURIComponent(opportunityId)}/standard-attributes`,
|
|
118
|
+
body: { values },
|
|
119
|
+
idempotencyKey,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** One attribute's timeline on an opportunity, or the whole one's when no key. */
|
|
123
|
+
async listOpportunityHistory(opportunityId, key) {
|
|
124
|
+
const query = key ? `?key=${encodeURIComponent(key)}` : '';
|
|
125
|
+
return this.http.request({
|
|
126
|
+
method: 'GET',
|
|
127
|
+
path: `/v1/opportunities/${encodeURIComponent(opportunityId)}/standard-attributes/history${query}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** One attribute's timeline on a quote, or the whole quote's when no key. */
|
|
131
|
+
async listHistory(quoteId, key) {
|
|
132
|
+
const query = key ? `?key=${encodeURIComponent(key)}` : '';
|
|
133
|
+
return this.http.request({
|
|
134
|
+
method: 'GET',
|
|
135
|
+
path: `/v1/quotes/${encodeURIComponent(quoteId)}/standard-attributes/history${query}`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// ── The landlord catalog ───────────────────────────────────────────────────
|
|
139
|
+
/** Add an attribute to the PLATFORM catalog. Seeds NEW tenants only —
|
|
140
|
+
* tenants already provisioned keep the copy they have. */
|
|
141
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
142
|
+
async createDefault(input, idempotencyKey) {
|
|
143
|
+
return this.http.request({
|
|
144
|
+
method: 'POST',
|
|
145
|
+
path: '/v1/standard-attribute-defaults',
|
|
146
|
+
body: input,
|
|
147
|
+
idempotencyKey,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Stop seeding one into new tenants. Existing tenant copies and every value
|
|
151
|
+
* ever recorded against the key are untouched. */
|
|
152
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
153
|
+
async removeDefault(id) {
|
|
154
|
+
return this.http.request({
|
|
155
|
+
method: 'DELETE',
|
|
156
|
+
path: `/v1/standard-attribute-defaults/${encodeURIComponent(id)}`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The PLATFORM-wide defaults, in display order — what a new tenant's copy is
|
|
161
|
+
* seeded from. Readable by any tenant; only the platform tenant can write.
|
|
162
|
+
*/
|
|
163
|
+
async listDefaults() {
|
|
164
|
+
return this.http.request({
|
|
165
|
+
method: 'GET',
|
|
166
|
+
path: '/v1/standard-attribute-defaults',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Rename or reorder one platform default.
|
|
171
|
+
*
|
|
172
|
+
* Changes what the NEXT tenant is seeded with. It does not reach tenants
|
|
173
|
+
* already provisioned — their copy is theirs to name.
|
|
174
|
+
*
|
|
175
|
+
* `key` is immutable — it is what every stored value references.
|
|
176
|
+
*/
|
|
177
|
+
/** @deprecated Since 5.13.0 the server answers 410 Gone: standard attributes are default definitions, authored in `client.defaultAttributes` and switched per tenant with `attributeDefinitions.setEnabled`. */
|
|
178
|
+
async updateDefault(id, input, idempotencyKey) {
|
|
179
|
+
return this.http.request({
|
|
180
|
+
method: 'PATCH',
|
|
181
|
+
path: `/v1/standard-attribute-defaults/${encodeURIComponent(id)}`,
|
|
182
|
+
body: input,
|
|
183
|
+
idempotencyKey,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.StandardAttributeResource = StandardAttributeResource;
|
|
188
|
+
//# sourceMappingURL=standardAttributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standardAttributes.js","sourceRoot":"","sources":["../src/standardAttributes.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -299,6 +299,16 @@ export interface Quote {
|
|
|
299
299
|
effectiveCostBreakdown: unknown;
|
|
300
300
|
/** Quote-level line-item cost detail for OEM cost-form export (4.18.0). */
|
|
301
301
|
effectiveCostDetail: unknown;
|
|
302
|
+
/**
|
|
303
|
+
* "Contract in place" on an awarded quote — see `quotes.setContract`. Null
|
|
304
|
+
* until recorded. A program is Contracted once every quote behind its
|
|
305
|
+
* finished goods has one. (5.26.0)
|
|
306
|
+
*/
|
|
307
|
+
contractedAt: string | null;
|
|
308
|
+
contractedBy: string | null;
|
|
309
|
+
contractReference: string | null;
|
|
310
|
+
/** The signed contract in DMS, when it was filed there. */
|
|
311
|
+
contractDocumentId: string | null;
|
|
302
312
|
effectiveUnitPrice: string | null;
|
|
303
313
|
effectivePriceSource: string | null;
|
|
304
314
|
effectivePriceBasis: string | null;
|
|
@@ -2144,6 +2154,8 @@ export interface Equipment {
|
|
|
2144
2154
|
defaultAutomationPct: number;
|
|
2145
2155
|
defaultMachinesPerOperator: number;
|
|
2146
2156
|
defaultSetupCrew: number;
|
|
2157
|
+
/** Custom-attribute values, keyed by registry definition key (entityType 'equipment'). */
|
|
2158
|
+
attributes: Record<string, unknown>;
|
|
2147
2159
|
active: boolean;
|
|
2148
2160
|
createdAt: string;
|
|
2149
2161
|
updatedAt: string;
|
|
@@ -2161,6 +2173,8 @@ export interface CreateEquipmentInput {
|
|
|
2161
2173
|
defaultAutomationPct?: number;
|
|
2162
2174
|
defaultMachinesPerOperator?: number;
|
|
2163
2175
|
defaultSetupCrew?: number;
|
|
2176
|
+
/** Custom-attribute values, keyed by registry definition key (entityType 'equipment'). On update, keys merge into the stored bag and a null value clears that key. */
|
|
2177
|
+
attributes?: Record<string, unknown>;
|
|
2164
2178
|
active?: boolean;
|
|
2165
2179
|
}
|
|
2166
2180
|
export interface UpdateEquipmentInput {
|
|
@@ -2175,6 +2189,8 @@ export interface UpdateEquipmentInput {
|
|
|
2175
2189
|
defaultAutomationPct?: number;
|
|
2176
2190
|
defaultMachinesPerOperator?: number;
|
|
2177
2191
|
defaultSetupCrew?: number;
|
|
2192
|
+
/** Custom-attribute values, keyed by registry definition key (entityType 'equipment'). On update, keys merge into the stored bag and a null value clears that key. */
|
|
2193
|
+
attributes?: Record<string, unknown>;
|
|
2178
2194
|
active?: boolean;
|
|
2179
2195
|
}
|
|
2180
2196
|
/** Outcome of `equipment.batchUpsert`. A bad row is reported, not fatal — a
|
|
@@ -3667,6 +3683,23 @@ export type BatchChildItemResult = {
|
|
|
3667
3683
|
code: string;
|
|
3668
3684
|
details?: unknown[];
|
|
3669
3685
|
};
|
|
3686
|
+
/** An equipment import row. `updated` means the machine already existed and the row's custom-attribute
|
|
3687
|
+
* values were merged into it (nothing else on the machine was touched). */
|
|
3688
|
+
export type BatchEquipmentImportItemResult = BatchChildItemResult | {
|
|
3689
|
+
index: number;
|
|
3690
|
+
status: 'updated';
|
|
3691
|
+
data: unknown;
|
|
3692
|
+
};
|
|
3693
|
+
export interface BatchEquipmentImportResult {
|
|
3694
|
+
results: BatchEquipmentImportItemResult[];
|
|
3695
|
+
/** `updated` is present only when the file merged attributes into existing machines. */
|
|
3696
|
+
summary: {
|
|
3697
|
+
total: number;
|
|
3698
|
+
created: number;
|
|
3699
|
+
errors: number;
|
|
3700
|
+
updated?: number;
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3670
3703
|
export interface BatchCreateChildResult {
|
|
3671
3704
|
results: BatchChildItemResult[];
|
|
3672
3705
|
summary: {
|
|
@@ -3726,6 +3759,8 @@ export interface ImportCommitResult {
|
|
|
3726
3759
|
parts?: BatchCreateMaterialsResult;
|
|
3727
3760
|
programs?: BatchCreateChildResult;
|
|
3728
3761
|
partCategories?: BatchCreateChildResult;
|
|
3762
|
+
/** Equipment sheets: new machines created, plus existing machines whose attribute values were merged. */
|
|
3763
|
+
equipment?: BatchEquipmentImportResult;
|
|
3729
3764
|
rateLibraries?: BatchCreateChildResult;
|
|
3730
3765
|
rateEntries?: BatchCreateChildResult;
|
|
3731
3766
|
/** Child rows skipped because their parent failed to commit (contacts /
|
|
@@ -4334,4 +4369,11 @@ export interface PutWorkingCalendarExceptionInput {
|
|
|
4334
4369
|
working?: boolean;
|
|
4335
4370
|
reason: string;
|
|
4336
4371
|
}
|
|
4372
|
+
/** Body of `quotes.setContract` (5.26.0). Both optional; omitted keeps the stored value. */
|
|
4373
|
+
export interface SetQuoteContractInput {
|
|
4374
|
+
/** A contract number or other identifier, as the customer writes it. */
|
|
4375
|
+
reference?: string | null;
|
|
4376
|
+
/** The signed contract's DMS document id. */
|
|
4377
|
+
documentId?: string | null;
|
|
4378
|
+
}
|
|
4337
4379
|
//# sourceMappingURL=types.d.ts.map
|