sg-widgets-core 0.1.0 → 0.2.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.
|
@@ -577,6 +577,57 @@ interface FollowingOptions {
|
|
|
577
577
|
entity?: string;
|
|
578
578
|
projectId?: number;
|
|
579
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* One write of a batch, in the shape `POST /entity/_batch` takes. `entity` is the
|
|
582
|
+
* schema name, never the URL slug, and the id key is `record_id` (recipes/002).
|
|
583
|
+
*/
|
|
584
|
+
type BatchRequest = {
|
|
585
|
+
request_type: 'create';
|
|
586
|
+
entity: string;
|
|
587
|
+
data: Record<string, unknown>;
|
|
588
|
+
} | {
|
|
589
|
+
request_type: 'update';
|
|
590
|
+
entity: string;
|
|
591
|
+
record_id: number;
|
|
592
|
+
data: Record<string, unknown>;
|
|
593
|
+
} | {
|
|
594
|
+
request_type: 'delete';
|
|
595
|
+
entity: string;
|
|
596
|
+
record_id: number;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* One row of a batch answer. A create or an update carries its record under `data`;
|
|
600
|
+
* a delete row is flat, and its `uuid` is generated per request (recipes/002).
|
|
601
|
+
*/
|
|
602
|
+
type BatchResult = {
|
|
603
|
+
request_type: 'create';
|
|
604
|
+
data: EntityRow;
|
|
605
|
+
} | {
|
|
606
|
+
request_type: 'update';
|
|
607
|
+
data: EntityRow;
|
|
608
|
+
} | {
|
|
609
|
+
request_type: 'delete';
|
|
610
|
+
type: string;
|
|
611
|
+
id: number;
|
|
612
|
+
uuid: string;
|
|
613
|
+
did_delete: boolean;
|
|
614
|
+
};
|
|
615
|
+
/** A row of the `_batch` answer before it is paired with its request. */
|
|
616
|
+
type RawBatchRow = {
|
|
617
|
+
data: EntityRow;
|
|
618
|
+
} | {
|
|
619
|
+
request_type: 'delete';
|
|
620
|
+
type: string;
|
|
621
|
+
id: number;
|
|
622
|
+
uuid: string;
|
|
623
|
+
did_delete: boolean;
|
|
624
|
+
};
|
|
625
|
+
/**
|
|
626
|
+
* Pair each row of a batch answer with the request at its position. Rows come back
|
|
627
|
+
* one per request in request order, so position is the key: two creates can share a
|
|
628
|
+
* `code` (recipes/002).
|
|
629
|
+
*/
|
|
630
|
+
declare function batchResults(requests: readonly BatchRequest[], rows: readonly RawBatchRow[]): BatchResult[];
|
|
580
631
|
interface SgClient {
|
|
581
632
|
/** Enabled entity types on the site with their display names. */
|
|
582
633
|
entityTypes(): Promise<EntityTypeInfo[]>;
|
|
@@ -675,6 +726,32 @@ interface SgClient {
|
|
|
675
726
|
* (get_entity_human_users_id_following).
|
|
676
727
|
*/
|
|
677
728
|
following(userId: number, options?: FollowingOptions): Promise<EntityRef[]>;
|
|
729
|
+
/**
|
|
730
|
+
* Retire one row. It is not erased: it reads 404 and comes back with `revive`.
|
|
731
|
+
* A second delete is 404 (delete_entity_type_id). Deleting a row changes others:
|
|
732
|
+
* a Shot retires its Versions (probe 060), and a Task retires its dependencies and
|
|
733
|
+
* nulls `Version.sg_task` and `PublishedFile.task` without saying so
|
|
734
|
+
* (089_task_delete_side_effects).
|
|
735
|
+
*/
|
|
736
|
+
delete(entityType: string, id: number): Promise<void>;
|
|
737
|
+
/**
|
|
738
|
+
* Bring a retired row back with the values it had, and answer whether it was
|
|
739
|
+
* retired: `false` means it was already live (post_entity_type_id). A revived Task
|
|
740
|
+
* gets its links back and its chain rescheduled (089_task_delete_side_effects).
|
|
741
|
+
*/
|
|
742
|
+
revive(entityType: string, id: number): Promise<boolean>;
|
|
743
|
+
/**
|
|
744
|
+
* Apply creates, updates and deletes in one atomic call, one result per request in
|
|
745
|
+
* request order.
|
|
746
|
+
*
|
|
747
|
+
* One failing request rolls back every other one and rejects with its status and
|
|
748
|
+
* title. A request cannot point at a row another request of the same batch creates:
|
|
749
|
+
* send one batch per level. A create inside a batch skips the `project` check a
|
|
750
|
+
* single create makes and answers the id of a row no read reaches (report 001), so
|
|
751
|
+
* validate the payload first. A read timeout says nothing about what landed; keep a
|
|
752
|
+
* batch to about 200 requests and make it re-runnable (recipes/002).
|
|
753
|
+
*/
|
|
754
|
+
batch(requests: BatchRequest[]): Promise<BatchResult[]>;
|
|
678
755
|
}
|
|
679
756
|
/** The node shape `/hierarchy/_expand` answers, before normalising. */
|
|
680
757
|
interface RawHierarchyNode {
|
|
@@ -725,6 +802,9 @@ declare class RestClient implements SgClient {
|
|
|
725
802
|
}): Promise<TextSearchRow[]>;
|
|
726
803
|
update(entityType: string, id: number, patch: Record<string, unknown>): Promise<EntityRow>;
|
|
727
804
|
create(entityType: string, body: Record<string, unknown>): Promise<EntityRow>;
|
|
805
|
+
delete(entityType: string, id: number): Promise<void>;
|
|
806
|
+
revive(entityType: string, id: number): Promise<boolean>;
|
|
807
|
+
batch(requests: BatchRequest[]): Promise<BatchResult[]>;
|
|
728
808
|
upload(entityType: string, id: number, file: UploadFile): Promise<UploadResult>;
|
|
729
809
|
summarize(entityType: string, options?: SummarizeOptions): Promise<SummarizeResult>;
|
|
730
810
|
threadContents(noteId: number, entityFields?: Record<string, string[]>): Promise<ThreadRow[]>;
|
|
@@ -737,4 +817,4 @@ declare class RestClient implements SgClient {
|
|
|
737
817
|
/** One `_search` row of `EventLogEntry`, with `meta` decoded as the API returns it. */
|
|
738
818
|
declare function normalizeEventLogEntry(row: EntityRow): EventLogEntry;
|
|
739
819
|
//#endregion
|
|
740
|
-
export {
|
|
820
|
+
export { NativeStatus as $, isDataType as $t, UploadFile as A, TextSearchFilter as At, StatusOption as B, toApi3Hash as Bt, SummaryField as C, ConditionValue as Ct, TextSearchRow as D, FilterNode as Dt, SummaryType as E, FilterGroup as Et, normalizeEventLogEntry as F, fromWire as Ft, parseBgColor as G, NEGATING_OPERATORS as Gt, StatusRecord as H, walk as Ht, normalizeHierarchyNode as I, group as It, statusGlyph as J, Operator as Jt, relativeLuminance as K, OPERATORS as Kt, Rgb as L, isBlankCondition as Lt, batchResults as M, WireGroup as Mt, eventLogFilters as N, condition as Nt, ThreadAuthor as O, LogicalOperator as Ot, hierarchyEntity as P, emptyFilter as Pt, NATIVE_STATUSES as Q, ValueShape as Qt, StatusGlyph as R, isEmptyFilter as Rt, SummarizeResult as S, undeclaredField as St, SummaryGrouping as T, FilterCondition as Tt, foregroundFor as U, DATA_TYPES as Ut, StatusPaint as V, toFilterArray as Vt, intersectStatuses as W, DataType as Wt, statusPaint as X, TimeUnit as Xt, statusLabel as Y, TIME_UNITS as Yt, usableStatuses as Z, VALUE_SHAPE as Zt, SearchOptions as _, fieldSchemaOverride as _t, EntityTypeInfo as a, operatorsFor as an, StockIconSource as at, SgClient as b, statusFieldFor as bt, EventLogResult as c, spriteStyle as ct, HierarchyPath as d, FIELD_SCHEMA_OVERRIDES as dt, isFilterable as en, STOCK_ICON_CELLS as et, HierarchyRef as f, FieldSchema as ft, RestClientOptions as g, displayNameOf as gt, RestClient as h, RawProperty as ht, EntityRow as i, isTemporalType as in, SpriteCell as it, UploadResult as j, WireCondition as jt, ThreadRow as k, Scalar as kt, FollowingOptions as l, stockIconSource as lt, RawHierarchyNode as m, RawFieldsResponse as mt, BatchResult as n, isNumericType as nn, STOCK_ICON_KEYS as nt, EventLogEntry as o, supportsOperator as on, isNativeStatus as ot, RawBatchRow as p, RawFieldSchema as pt, rgbToCss as q, OPERATORS_BY_TYPE as qt, EVENT_LOG_FIELDS as r, isOperator as rn, STOCK_SPRITE_PATH as rt, EventLogOptions as s, nativeStatus as st, BatchRequest as t, isLinkType as tn, STOCK_ICON_DATA_URLS as tt, HierarchyNode as u, DISPLAY_NAME_FIELDS as ut, SearchResult as v, normalizeField as vt, SummaryGroup as w, EntityRef as wt, SummarizeOptions as x, statusFieldNameFor as xt, SgApiError as y, normalizeFields as yt, StatusIcon as z, referencedPaths as zt };
|
|
@@ -607,6 +607,30 @@ const EVENT_LOG_FIELDS = [
|
|
|
607
607
|
"user"
|
|
608
608
|
];
|
|
609
609
|
/**
|
|
610
|
+
* Pair each row of a batch answer with the request at its position. Rows come back
|
|
611
|
+
* one per request in request order, so position is the key: two creates can share a
|
|
612
|
+
* `code` (recipes/002).
|
|
613
|
+
*/
|
|
614
|
+
function batchResults(requests, rows) {
|
|
615
|
+
return rows.map((row, i) => {
|
|
616
|
+
const kind = requests[i]?.request_type;
|
|
617
|
+
if (kind === "delete" || !("data" in row)) {
|
|
618
|
+
const flat = row;
|
|
619
|
+
return {
|
|
620
|
+
request_type: "delete",
|
|
621
|
+
type: flat.type,
|
|
622
|
+
id: flat.id,
|
|
623
|
+
uuid: flat.uuid,
|
|
624
|
+
did_delete: flat.did_delete
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
return {
|
|
628
|
+
request_type: kind === "update" ? "update" : "create",
|
|
629
|
+
data: row.data
|
|
630
|
+
};
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
610
634
|
* Normalise one node and the level below it.
|
|
611
635
|
*
|
|
612
636
|
* The sample response gives a child a `label`, a `ref` and `has_children` but not
|
|
@@ -755,6 +779,15 @@ var RestClient = class {
|
|
|
755
779
|
async create(entityType, body) {
|
|
756
780
|
return (await this.request("POST", `/entity/${pluralPath(entityType)}`, body, void 0, "application/json")).data;
|
|
757
781
|
}
|
|
782
|
+
async delete(entityType, id) {
|
|
783
|
+
await this.request("DELETE", `/entity/${pluralPath(entityType)}/${id}`);
|
|
784
|
+
}
|
|
785
|
+
async revive(entityType, id) {
|
|
786
|
+
return (await this.request("POST", `/entity/${pluralPath(entityType)}/${id}`, void 0, { revive: 1 })).meta?.did_revive === true;
|
|
787
|
+
}
|
|
788
|
+
async batch(requests) {
|
|
789
|
+
return batchResults(requests, (await this.request("POST", "/entity/_batch", { requests }, void 0, "application/json")).data);
|
|
790
|
+
}
|
|
758
791
|
async upload(entityType, id, file) {
|
|
759
792
|
const field = file.field === void 0 ? "" : `/${file.field}`;
|
|
760
793
|
const ticket = await this.request("GET", `/entity/${pluralPath(entityType)}/${id}${field}/_upload`, void 0, { filename: file.filename });
|
|
@@ -1012,4 +1045,4 @@ function toStatusIcon(a) {
|
|
|
1012
1045
|
}
|
|
1013
1046
|
}
|
|
1014
1047
|
//#endregion
|
|
1015
|
-
export {
|
|
1048
|
+
export { NEGATING_OPERATORS as A, isTemporalType as B, isBlankCondition as C, toFilterArray as D, toApi3Hash as E, isDataType as F, supportsOperator as H, isFilterable as I, isLinkType as L, OPERATORS_BY_TYPE as M, TIME_UNITS as N, walk as O, VALUE_SHAPE as P, isNumericType as R, group as S, referencedPaths as T, operatorsFor as V, undeclaredField as _, eventLogFilters as a, emptyFilter as b, normalizeHierarchyNode as c, displayNameOf as d, fieldSchemaOverride as f, statusFieldNameFor as g, statusFieldFor as h, batchResults as i, OPERATORS as j, DATA_TYPES as k, DISPLAY_NAME_FIELDS as l, normalizeFields as m, RestClient as n, hierarchyEntity as o, normalizeField as p, SgApiError as r, normalizeEventLogEntry as s, EVENT_LOG_FIELDS as t, FIELD_SCHEMA_OVERRIDES as u, pluralPath as v, isEmptyFilter as w, fromWire as x, condition as y, isOperator as z };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as NativeStatus, $t as isDataType, A as UploadFile, At as TextSearchFilter, B as StatusOption, Bt as toApi3Hash, C as SummaryField, Ct as ConditionValue, D as TextSearchRow, Dt as FilterNode, E as SummaryType, Et as FilterGroup, F as normalizeEventLogEntry, Ft as fromWire, G as parseBgColor, Gt as NEGATING_OPERATORS, H as StatusRecord, Ht as walk, I as normalizeHierarchyNode, It as group, J as statusGlyph, Jt as Operator, K as relativeLuminance, Kt as OPERATORS, L as Rgb, Lt as isBlankCondition, M as batchResults, Mt as WireGroup, N as eventLogFilters, Nt as condition, O as ThreadAuthor, Ot as LogicalOperator, P as hierarchyEntity, Pt as emptyFilter, Q as NATIVE_STATUSES, Qt as ValueShape, R as StatusGlyph, Rt as isEmptyFilter, S as SummarizeResult, St as undeclaredField, T as SummaryGrouping, Tt as FilterCondition, U as foregroundFor, Ut as DATA_TYPES, V as StatusPaint, Vt as toFilterArray, W as intersectStatuses, Wt as DataType, X as statusPaint, Xt as TimeUnit, Y as statusLabel, Yt as TIME_UNITS, Z as usableStatuses, Zt as VALUE_SHAPE, _ as SearchOptions, _t as fieldSchemaOverride, a as EntityTypeInfo, an as operatorsFor, at as StockIconSource, b as SgClient, bt as statusFieldFor, c as EventLogResult, ct as spriteStyle, d as HierarchyPath, dt as FIELD_SCHEMA_OVERRIDES, en as isFilterable, et as STOCK_ICON_CELLS, f as HierarchyRef, ft as FieldSchema, g as RestClientOptions, gt as displayNameOf, h as RestClient, ht as RawProperty, i as EntityRow, in as isTemporalType, it as SpriteCell, j as UploadResult, jt as WireCondition, k as ThreadRow, kt as Scalar, l as FollowingOptions, lt as stockIconSource, m as RawHierarchyNode, mt as RawFieldsResponse, n as BatchResult, nn as isNumericType, nt as STOCK_ICON_KEYS, o as EventLogEntry, on as supportsOperator, ot as isNativeStatus, p as RawBatchRow, pt as RawFieldSchema, q as rgbToCss, qt as OPERATORS_BY_TYPE, r as EVENT_LOG_FIELDS, rn as isOperator, rt as STOCK_SPRITE_PATH, s as EventLogOptions, st as nativeStatus, t as BatchRequest, tn as isLinkType, tt as STOCK_ICON_DATA_URLS, u as HierarchyNode, ut as DISPLAY_NAME_FIELDS, v as SearchResult, vt as normalizeField, w as SummaryGroup, wt as EntityRef, x as SummarizeOptions, xt as statusFieldNameFor, y as SgApiError, yt as normalizeFields, z as StatusIcon, zt as referencedPaths } from "./client-B2PCySg9.mjs";
|
|
2
2
|
//#region src/field-icons.d.ts
|
|
3
3
|
/** The catch-all glyph, used for a data type this build does not know. */
|
|
4
4
|
export declare const DEFAULT_FIELD_ICON = "file-text";
|
|
@@ -1772,6 +1772,9 @@ export declare class ProxyClient implements SgClient {
|
|
|
1772
1772
|
}): Promise<TextSearchRow[]>;
|
|
1773
1773
|
statuses(): Promise<StatusRecord[]>;
|
|
1774
1774
|
create(entityType: string, body: Record<string, unknown>): Promise<EntityRow>;
|
|
1775
|
+
delete(entityType: string, id: number): Promise<void>;
|
|
1776
|
+
revive(entityType: string, id: number): Promise<boolean>;
|
|
1777
|
+
batch(requests: BatchRequest[]): Promise<BatchResult[]>;
|
|
1775
1778
|
/** The bytes cross the protocol base64-encoded; the handler runs the three calls. */
|
|
1776
1779
|
upload(entityType: string, id: number, file: UploadFile): Promise<UploadResult>;
|
|
1777
1780
|
update(entityType: string, id: number, patch: Record<string, unknown>): Promise<EntityRow>;
|
|
@@ -1785,7 +1788,7 @@ export declare class ProxyClient implements SgClient {
|
|
|
1785
1788
|
//#endregion
|
|
1786
1789
|
//#region src/proxy-handler.d.ts
|
|
1787
1790
|
/** The methods the protocol carries, one POST each. */
|
|
1788
|
-
export declare const PROXY_METHODS: readonly ['entityTypes', 'fields', 'fieldWithProject', 'search', 'textSearch', 'statuses', 'create', 'update', 'upload', 'hierarchyExpand', 'hierarchySearch', 'summarize', 'threadContents', 'eventLog', 'following'];
|
|
1791
|
+
export declare const PROXY_METHODS: readonly ['entityTypes', 'fields', 'fieldWithProject', 'search', 'textSearch', 'statuses', 'create', 'update', 'upload', 'hierarchyExpand', 'hierarchySearch', 'summarize', 'threadContents', 'eventLog', 'following', 'delete', 'revive', 'batch'];
|
|
1789
1792
|
export type ProxyMethod = (typeof PROXY_METHODS)[number];
|
|
1790
1793
|
/** An error as it crosses the wire. `ProxyClient` rebuilds an `SgApiError` from it. */
|
|
1791
1794
|
export interface ProxyError {
|
|
@@ -2723,4 +2726,4 @@ export declare function markOverflow(list: HTMLElement | null | undefined): bool
|
|
|
2723
2726
|
*/
|
|
2724
2727
|
export declare function watchOverflow(list: HTMLElement | null | undefined): () => void;
|
|
2725
2728
|
//#endregion
|
|
2726
|
-
export { ConditionValue, DATA_TYPES, DISPLAY_NAME_FIELDS, DataType, EVENT_LOG_FIELDS, EntityRef, EntityRow, EntityTypeInfo, EventLogEntry, EventLogOptions, EventLogResult, FIELD_SCHEMA_OVERRIDES, FieldSchema, FilterCondition, FilterGroup, FilterNode, FollowingOptions, HierarchyNode, HierarchyPath, HierarchyRef, LogicalOperator, NATIVE_STATUSES, NEGATING_OPERATORS, NativeStatus, OPERATORS, OPERATORS_BY_TYPE, Operator, RawFieldSchema, RawFieldsResponse, RawHierarchyNode, RawProperty, RestClient, RestClientOptions, Rgb, STOCK_ICON_CELLS, STOCK_ICON_DATA_URLS, STOCK_ICON_KEYS, STOCK_SPRITE_PATH, Scalar, SearchOptions, SearchResult, SgApiError, SgClient, SpriteCell, StatusGlyph, StatusIcon, StatusOption, StatusPaint, StatusRecord, StockIconSource, SummarizeOptions, SummarizeResult, SummaryField, SummaryGroup, SummaryGrouping, SummaryType, TIME_UNITS, TextSearchFilter, TextSearchRow, ThreadAuthor, ThreadRow, TimeUnit, UploadFile, UploadResult, VALUE_SHAPE, ValueShape, WireCondition, WireGroup, condition, displayNameOf, emptyFilter, eventLogFilters, fieldSchemaOverride, foregroundFor, fromWire, group, hierarchyEntity, intersectStatuses, isBlankCondition, isDataType, isEmptyFilter, isFilterable, isLinkType, isNativeStatus, isNumericType, isOperator, isTemporalType, nativeStatus, normalizeEventLogEntry, normalizeField, normalizeFields, normalizeHierarchyNode, operatorsFor, parseBgColor, referencedPaths, relativeLuminance, rgbToCss, spriteStyle, statusFieldFor, statusFieldNameFor, statusGlyph, statusLabel, statusPaint, stockIconSource, supportsOperator, toApi3Hash, toFilterArray, undeclaredField, usableStatuses, walk };
|
|
2729
|
+
export { BatchRequest, BatchResult, ConditionValue, DATA_TYPES, DISPLAY_NAME_FIELDS, DataType, EVENT_LOG_FIELDS, EntityRef, EntityRow, EntityTypeInfo, EventLogEntry, EventLogOptions, EventLogResult, FIELD_SCHEMA_OVERRIDES, FieldSchema, FilterCondition, FilterGroup, FilterNode, FollowingOptions, HierarchyNode, HierarchyPath, HierarchyRef, LogicalOperator, NATIVE_STATUSES, NEGATING_OPERATORS, NativeStatus, OPERATORS, OPERATORS_BY_TYPE, Operator, RawBatchRow, RawFieldSchema, RawFieldsResponse, RawHierarchyNode, RawProperty, RestClient, RestClientOptions, Rgb, STOCK_ICON_CELLS, STOCK_ICON_DATA_URLS, STOCK_ICON_KEYS, STOCK_SPRITE_PATH, Scalar, SearchOptions, SearchResult, SgApiError, SgClient, SpriteCell, StatusGlyph, StatusIcon, StatusOption, StatusPaint, StatusRecord, StockIconSource, SummarizeOptions, SummarizeResult, SummaryField, SummaryGroup, SummaryGrouping, SummaryType, TIME_UNITS, TextSearchFilter, TextSearchRow, ThreadAuthor, ThreadRow, TimeUnit, UploadFile, UploadResult, VALUE_SHAPE, ValueShape, WireCondition, WireGroup, batchResults, condition, displayNameOf, emptyFilter, eventLogFilters, fieldSchemaOverride, foregroundFor, fromWire, group, hierarchyEntity, intersectStatuses, isBlankCondition, isDataType, isEmptyFilter, isFilterable, isLinkType, isNativeStatus, isNumericType, isOperator, isTemporalType, nativeStatus, normalizeEventLogEntry, normalizeField, normalizeFields, normalizeHierarchyNode, operatorsFor, parseBgColor, referencedPaths, relativeLuminance, rgbToCss, spriteStyle, statusFieldFor, statusFieldNameFor, statusGlyph, statusLabel, statusPaint, stockIconSource, supportsOperator, toApi3Hash, toFilterArray, undeclaredField, usableStatuses, walk };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as NEGATING_OPERATORS, B as isTemporalType, C as isBlankCondition, D as toFilterArray, E as toApi3Hash, F as isDataType, H as supportsOperator, I as isFilterable, L as isLinkType, M as OPERATORS_BY_TYPE, N as TIME_UNITS, O as walk, P as VALUE_SHAPE, R as isNumericType, S as group, T as referencedPaths, V as operatorsFor, _ as undeclaredField, a as eventLogFilters, b as emptyFilter, c as normalizeHierarchyNode, d as displayNameOf, f as fieldSchemaOverride, g as statusFieldNameFor, h as statusFieldFor, i as batchResults, j as OPERATORS, k as DATA_TYPES, l as DISPLAY_NAME_FIELDS, m as normalizeFields, n as RestClient, o as hierarchyEntity, p as normalizeField, r as SgApiError, s as normalizeEventLogEntry, t as EVENT_LOG_FIELDS, u as FIELD_SCHEMA_OVERRIDES, w as isEmptyFilter, x as fromWire, y as condition, z as isOperator } from "./client-BdePDloQ.mjs";
|
|
2
2
|
//#region src/field-icons.ts
|
|
3
3
|
const ICONS = {
|
|
4
4
|
text: "type",
|
|
@@ -3700,6 +3700,21 @@ function createQueryCache(client, options = {}) {
|
|
|
3700
3700
|
function invalidateThreads() {
|
|
3701
3701
|
drop("threadContents");
|
|
3702
3702
|
}
|
|
3703
|
+
/**
|
|
3704
|
+
* A delete retires and unlinks rows of other types, a Shot's Versions (probe 060)
|
|
3705
|
+
* and a Task's dependencies, `Version.sg_task` and `PublishedFile.task`, and a
|
|
3706
|
+
* revive puts them back (089_task_delete_side_effects). Every row read goes.
|
|
3707
|
+
*/
|
|
3708
|
+
function invalidateAllRows() {
|
|
3709
|
+
for (const prefix of [
|
|
3710
|
+
"search",
|
|
3711
|
+
"textSearch",
|
|
3712
|
+
"summarize",
|
|
3713
|
+
"threadContents",
|
|
3714
|
+
"hierarchyExpand",
|
|
3715
|
+
"hierarchySearch"
|
|
3716
|
+
]) drop(prefix);
|
|
3717
|
+
}
|
|
3703
3718
|
return {
|
|
3704
3719
|
entityTypes() {
|
|
3705
3720
|
return run("entityTypes", [], () => client.entityTypes());
|
|
@@ -3768,6 +3783,22 @@ function createQueryCache(client, options = {}) {
|
|
|
3768
3783
|
invalidateThreads();
|
|
3769
3784
|
return row;
|
|
3770
3785
|
},
|
|
3786
|
+
async delete(entityType, id) {
|
|
3787
|
+
await client.delete(entityType, id);
|
|
3788
|
+
invalidateAllRows();
|
|
3789
|
+
},
|
|
3790
|
+
async revive(entityType, id) {
|
|
3791
|
+
const revived = await client.revive(entityType, id);
|
|
3792
|
+
invalidateAllRows();
|
|
3793
|
+
return revived;
|
|
3794
|
+
},
|
|
3795
|
+
async batch(requests) {
|
|
3796
|
+
const results = await client.batch(requests);
|
|
3797
|
+
if (requests.some((r) => r.request_type === "delete")) invalidateAllRows();
|
|
3798
|
+
else for (const type of new Set(requests.map((r) => r.entity))) invalidateSearches(type);
|
|
3799
|
+
invalidateThreads();
|
|
3800
|
+
return results;
|
|
3801
|
+
},
|
|
3771
3802
|
invalidate(prefix) {
|
|
3772
3803
|
if (prefix === void 0) {
|
|
3773
3804
|
entries.clear();
|
|
@@ -4689,7 +4720,10 @@ const PROXY_METHODS = [
|
|
|
4689
4720
|
"summarize",
|
|
4690
4721
|
"threadContents",
|
|
4691
4722
|
"eventLog",
|
|
4692
|
-
"following"
|
|
4723
|
+
"following",
|
|
4724
|
+
"delete",
|
|
4725
|
+
"revive",
|
|
4726
|
+
"batch"
|
|
4693
4727
|
];
|
|
4694
4728
|
function isProxyMethod(value) {
|
|
4695
4729
|
return PROXY_METHODS.includes(value);
|
|
@@ -4739,6 +4773,12 @@ function entityRef(value, name) {
|
|
|
4739
4773
|
id: num(ref.id, `${name}.id`)
|
|
4740
4774
|
};
|
|
4741
4775
|
}
|
|
4776
|
+
/** The list is passed on as sent; the API names what is wrong with a request (recipes/002). */
|
|
4777
|
+
function requestList(value, name) {
|
|
4778
|
+
if (!Array.isArray(value)) throw new BadRequest(`'${name}' must be a list`);
|
|
4779
|
+
for (const [i, request] of value.entries()) obj(request, `${name}[${i}]`);
|
|
4780
|
+
return value;
|
|
4781
|
+
}
|
|
4742
4782
|
function str(value, name) {
|
|
4743
4783
|
if (typeof value !== "string" || value.length === 0) throw new BadRequest(`'${name}' must be a non-empty string`);
|
|
4744
4784
|
return value;
|
|
@@ -4799,6 +4839,9 @@ function call(client, method, p) {
|
|
|
4799
4839
|
case "threadContents": return client.threadContents(num(p.noteId, "noteId"), p.entityFields ?? void 0);
|
|
4800
4840
|
case "eventLog": return client.eventLog(p.options ?? {});
|
|
4801
4841
|
case "following": return client.following(num(p.userId, "userId"), p.options ?? {});
|
|
4842
|
+
case "delete": return client.delete(str(p.entityType, "entityType"), num(p.id, "id")).then(() => null);
|
|
4843
|
+
case "revive": return client.revive(str(p.entityType, "entityType"), num(p.id, "id"));
|
|
4844
|
+
case "batch": return client.batch(requestList(p.requests, "requests"));
|
|
4802
4845
|
}
|
|
4803
4846
|
}
|
|
4804
4847
|
//#endregion
|
|
@@ -4878,6 +4921,21 @@ var ProxyClient = class {
|
|
|
4878
4921
|
body
|
|
4879
4922
|
});
|
|
4880
4923
|
}
|
|
4924
|
+
async delete(entityType, id) {
|
|
4925
|
+
await this.post("delete", {
|
|
4926
|
+
entityType,
|
|
4927
|
+
id
|
|
4928
|
+
});
|
|
4929
|
+
}
|
|
4930
|
+
revive(entityType, id) {
|
|
4931
|
+
return this.post("revive", {
|
|
4932
|
+
entityType,
|
|
4933
|
+
id
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
batch(requests) {
|
|
4937
|
+
return this.post("batch", { requests });
|
|
4938
|
+
}
|
|
4881
4939
|
/** The bytes cross the protocol base64-encoded; the handler runs the three calls. */
|
|
4882
4940
|
upload(entityType, id, file) {
|
|
4883
4941
|
return this.post("upload", {
|
|
@@ -7929,4 +7987,4 @@ function watchOverflow(list) {
|
|
|
7929
7987
|
};
|
|
7930
7988
|
}
|
|
7931
7989
|
//#endregion
|
|
7932
|
-
export { AppSessionError, COLOR_SENTINEL, DATA_TYPES, DEFAULT_FIELD_ICON, DISPLAY_NAME_FIELDS, ELLIPSIS_CHIPS, ERROR_LABEL, EVENT_LOG_FIELDS, FIELD_ICON_NAMES, FIELD_SCHEMA_OVERRIDES, FLOAT_PRECISION, HIERARCHY_LEAF_LIMIT, INT32_MAX, INT32_MIN, LOADING_LABEL, NAME_HUES, NATIVE_STATUSES, NEGATING_OPERATORS, NOTHING_CHOSEN_LABEL, NO_MATCH_LABEL, NO_ROWS_LABEL, OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OVERFLOW_END_VAR, OVERFLOW_START_VAR, PATH_SEPARATOR, PRESS_WINDOW_MS, PROJECT_PICKER_FIELDS, PROXY_METHODS, ProxyClient, RestClient, SCROLL_THRESHOLD, SEARCHING_LABEL, SEARCH_DEBOUNCE_MS, SEARCH_PAGE_SIZE, SORTABLE_HANDLE_ATTRIBUTE, SORTABLE_ID_ATTRIBUTE, STOCK_ICON_CELLS, STOCK_ICON_DATA_URLS, STOCK_ICON_KEYS, STOCK_SPRITE_PATH, SgApiError, THUMBNAIL_PENDING_PATH, TIME_UNITS, TIME_UNIT_LABELS, TREE_STATUS_FIELDS, UNRESOLVED_PATH_LABEL, USER_PICKER_FIELDS, VALUE_SHAPE, appendAt, applyPreset, asCollapseState, asFilterGroup, base64ToBytes, breadcrumb, bytesToBase64, canLoadNext, cellValue, clearableForField, collapseAll, collapseStateFrom, collapsedKeys, collectionBottom, collectionView, colorToHex, condition, conditionArity, conditionList, conditionParts, conditionValues, contextFromClient, countActiveConditions, countConditions, countLine, createEntitySearch, createEntitySource, createProxyHandler, createQueryCache, createSchemaService, createSessionTokenAuth, createSgContext, createSortable, createSortableController, createStatusService, createTree, currentPlatform, currentType, defaultCondition, defaultValueFor, deriveFieldOptions, describeCondition, describeEntityCard, describePaging, displayNameOf, editorKindFor, editorNeedsContext, editorPlacementFor, emptyFilter, emptyValueFor, entityCardFields, entityCardSlot, entityDetailUrl, entityKey, entityTypeOptions, errorText, eventLogFilters, expandAll, facetCounts, facetLists, facetPresets, facetScopes, facetShape, facetValues, facetValuesFromGroups, fieldOperators, fieldPathOf, fieldSchemaOverride, fieldText, fileHref, fileNameFromUrl, filterEntityTypes, filterableFields, findCondition, findFacet, firstEnabledIndex, fitChips, flattenRow, focusChip, foregroundFor, formatCurrency, formatDate, formatDateTime, formatDuration, formatFloat, formatNumberInput, formatPercent, formatTimecode, friendlyFieldPath, fromApiDateTime, fromSortString, fromWire, group, groupKeyText, groupRows, groupRowsKeyed, hasFailedPage, hasMorePage, hierarchyEntity, hierarchyLoader, hierarchySearcher, hydrate, iconNameFor, idsForRefs, imageState, initialsOf, intersectStatuses, isBareRef, isBlankCondition, isCollapsed, isDataType, isEditableType, isEmptyFilter, isEmptyValue, isFilterable, isGroupingRefusal, isHiddenPath, isLinkType, isNativeStatus, isNumericType, isOperator, isParseError, isPinned, isProxyMethod, isSortable, isTemporalType, isValidListValue, isoDay, isoDayParts, listStatus, loadEntityCard, loadsOnArrowDown, markOverflow, matchRuns, matchesEveryWord, measureSortable, mergeFilters, moveAt, moveFieldPath, nameColorIndex, nameHue, nameSearchFilter, nativeStatus, nextEnabledIndex, nodeAt, normalizeEventLogEntry, normalizeField, normalizeFields, normalizeHierarchyNode, normalizeSiteUrl, numberDigits, numberDraft, numberSteps, numberWire, operatorLabel, operatorMenu, operatorsFor, overflowEdges, parseBgColor, parseColorInput, parseDurationInput, parseFloatInput, parseInteger, parseNumberInput, parseTextInput, parseTimecodeInput, parseUrlInput, pathLabel, pathOf, pathRefs, pathTypes, pickerKeyIntent, placeholderName, playSortableFlip, pollAppSession, preferencesOf, prependRecent, presetById, presetIdOf, presetsFor, pressGate, projectOfPath, projectPickerFilters, pruneFilterToFields, queryPlan, reachedEnd, referencedPaths, refsForIds, relativeFrom, relativeLuminance, relativeOperator, relativeValue, relativeWindow, removeAt, renderKindFor, replaceAt, requestAppSession, requestGate, resolveColumns, resolveFieldPathOptions, resolveRowFields, resolveTreeFields, rgbToCss, rowCode, rowFields, rowIdOf, rowIsDisabled, rowKey, rowSecondary, rowSubLabel, rowThumbnail, sameCollapse, sameFilters, sameIds, sameRefs, sameSort, scopeToProject, scrollHighlightedIntoView, searchFieldOptions, searchFieldPathOptions, searchKeyIntent, searchTypeMap, searchView, searchWords, secondaryType, selectableRefs, selectionState, serializeSort, setFacet, setFacetPreset, settleStep, shouldLoadNext, sortableAnnouncements, sortableDropIndex, sortableFields, sortableScrollStep, sortableStride, sourceModeFor, spriteStyle, stateLine, statusFieldFor, statusFieldNameFor, statusGlyph, statusLabel, statusPaint, stepNumber, stockIconSource, storedNumber, subLabelType, summariseSelection, supportsEmpty, supportsOperator, thumbnailField, timeUnitField, timeUnitLabel, timeZoneName, toApi3Hash, toApiDate, toApiDateTime, toApiFloat, toColumn, toFilterArray, toRef, toSearchHit, toSortKeys, toSortSpecs, toSortString, toWireGroup, toggleCollapsed, toggleFieldPath, toggleId, toggleRef, traversalTargets, undeclaredField, unformatNumberInput, urlLink, usableStatuses, userPickerFilters, userPickerSearchFields, userPickerSubLabel, userPickerTypes, userSearchFields, validateCondition, valueArity, valueEditorFor, walk, watchHighlight, watchOverflow, withAddedListValue, withListValue, withRelativeWindow, withSelectedPinned, withoutListValue, withoutPaths };
|
|
7990
|
+
export { AppSessionError, COLOR_SENTINEL, DATA_TYPES, DEFAULT_FIELD_ICON, DISPLAY_NAME_FIELDS, ELLIPSIS_CHIPS, ERROR_LABEL, EVENT_LOG_FIELDS, FIELD_ICON_NAMES, FIELD_SCHEMA_OVERRIDES, FLOAT_PRECISION, HIERARCHY_LEAF_LIMIT, INT32_MAX, INT32_MIN, LOADING_LABEL, NAME_HUES, NATIVE_STATUSES, NEGATING_OPERATORS, NOTHING_CHOSEN_LABEL, NO_MATCH_LABEL, NO_ROWS_LABEL, OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OVERFLOW_END_VAR, OVERFLOW_START_VAR, PATH_SEPARATOR, PRESS_WINDOW_MS, PROJECT_PICKER_FIELDS, PROXY_METHODS, ProxyClient, RestClient, SCROLL_THRESHOLD, SEARCHING_LABEL, SEARCH_DEBOUNCE_MS, SEARCH_PAGE_SIZE, SORTABLE_HANDLE_ATTRIBUTE, SORTABLE_ID_ATTRIBUTE, STOCK_ICON_CELLS, STOCK_ICON_DATA_URLS, STOCK_ICON_KEYS, STOCK_SPRITE_PATH, SgApiError, THUMBNAIL_PENDING_PATH, TIME_UNITS, TIME_UNIT_LABELS, TREE_STATUS_FIELDS, UNRESOLVED_PATH_LABEL, USER_PICKER_FIELDS, VALUE_SHAPE, appendAt, applyPreset, asCollapseState, asFilterGroup, base64ToBytes, batchResults, breadcrumb, bytesToBase64, canLoadNext, cellValue, clearableForField, collapseAll, collapseStateFrom, collapsedKeys, collectionBottom, collectionView, colorToHex, condition, conditionArity, conditionList, conditionParts, conditionValues, contextFromClient, countActiveConditions, countConditions, countLine, createEntitySearch, createEntitySource, createProxyHandler, createQueryCache, createSchemaService, createSessionTokenAuth, createSgContext, createSortable, createSortableController, createStatusService, createTree, currentPlatform, currentType, defaultCondition, defaultValueFor, deriveFieldOptions, describeCondition, describeEntityCard, describePaging, displayNameOf, editorKindFor, editorNeedsContext, editorPlacementFor, emptyFilter, emptyValueFor, entityCardFields, entityCardSlot, entityDetailUrl, entityKey, entityTypeOptions, errorText, eventLogFilters, expandAll, facetCounts, facetLists, facetPresets, facetScopes, facetShape, facetValues, facetValuesFromGroups, fieldOperators, fieldPathOf, fieldSchemaOverride, fieldText, fileHref, fileNameFromUrl, filterEntityTypes, filterableFields, findCondition, findFacet, firstEnabledIndex, fitChips, flattenRow, focusChip, foregroundFor, formatCurrency, formatDate, formatDateTime, formatDuration, formatFloat, formatNumberInput, formatPercent, formatTimecode, friendlyFieldPath, fromApiDateTime, fromSortString, fromWire, group, groupKeyText, groupRows, groupRowsKeyed, hasFailedPage, hasMorePage, hierarchyEntity, hierarchyLoader, hierarchySearcher, hydrate, iconNameFor, idsForRefs, imageState, initialsOf, intersectStatuses, isBareRef, isBlankCondition, isCollapsed, isDataType, isEditableType, isEmptyFilter, isEmptyValue, isFilterable, isGroupingRefusal, isHiddenPath, isLinkType, isNativeStatus, isNumericType, isOperator, isParseError, isPinned, isProxyMethod, isSortable, isTemporalType, isValidListValue, isoDay, isoDayParts, listStatus, loadEntityCard, loadsOnArrowDown, markOverflow, matchRuns, matchesEveryWord, measureSortable, mergeFilters, moveAt, moveFieldPath, nameColorIndex, nameHue, nameSearchFilter, nativeStatus, nextEnabledIndex, nodeAt, normalizeEventLogEntry, normalizeField, normalizeFields, normalizeHierarchyNode, normalizeSiteUrl, numberDigits, numberDraft, numberSteps, numberWire, operatorLabel, operatorMenu, operatorsFor, overflowEdges, parseBgColor, parseColorInput, parseDurationInput, parseFloatInput, parseInteger, parseNumberInput, parseTextInput, parseTimecodeInput, parseUrlInput, pathLabel, pathOf, pathRefs, pathTypes, pickerKeyIntent, placeholderName, playSortableFlip, pollAppSession, preferencesOf, prependRecent, presetById, presetIdOf, presetsFor, pressGate, projectOfPath, projectPickerFilters, pruneFilterToFields, queryPlan, reachedEnd, referencedPaths, refsForIds, relativeFrom, relativeLuminance, relativeOperator, relativeValue, relativeWindow, removeAt, renderKindFor, replaceAt, requestAppSession, requestGate, resolveColumns, resolveFieldPathOptions, resolveRowFields, resolveTreeFields, rgbToCss, rowCode, rowFields, rowIdOf, rowIsDisabled, rowKey, rowSecondary, rowSubLabel, rowThumbnail, sameCollapse, sameFilters, sameIds, sameRefs, sameSort, scopeToProject, scrollHighlightedIntoView, searchFieldOptions, searchFieldPathOptions, searchKeyIntent, searchTypeMap, searchView, searchWords, secondaryType, selectableRefs, selectionState, serializeSort, setFacet, setFacetPreset, settleStep, shouldLoadNext, sortableAnnouncements, sortableDropIndex, sortableFields, sortableScrollStep, sortableStride, sourceModeFor, spriteStyle, stateLine, statusFieldFor, statusFieldNameFor, statusGlyph, statusLabel, statusPaint, stepNumber, stockIconSource, storedNumber, subLabelType, summariseSelection, supportsEmpty, supportsOperator, thumbnailField, timeUnitField, timeUnitLabel, timeZoneName, toApi3Hash, toApiDate, toApiDateTime, toApiFloat, toColumn, toFilterArray, toRef, toSearchHit, toSortKeys, toSortSpecs, toSortString, toWireGroup, toggleCollapsed, toggleFieldPath, toggleId, toggleRef, traversalTargets, undeclaredField, unformatNumberInput, urlLink, usableStatuses, userPickerFilters, userPickerSearchFields, userPickerSubLabel, userPickerTypes, userSearchFields, validateCondition, valueArity, valueEditorFor, walk, watchHighlight, watchOverflow, withAddedListValue, withListValue, withRelativeWindow, withSelectedPinned, withoutListValue, withoutPaths };
|
package/dist/mock.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as UploadFile, At as TextSearchFilter, D as TextSearchRow, H as StatusRecord, S as SummarizeResult, _ as SearchOptions, a as EntityTypeInfo, b as SgClient, c as EventLogResult, d as HierarchyPath, ft as FieldSchema, i as EntityRow, j as UploadResult, k as ThreadRow, l as FollowingOptions, n as BatchResult, s as EventLogOptions, t as BatchRequest, u as HierarchyNode, v as SearchResult, wt as EntityRef, x as SummarizeOptions } from "./client-B2PCySg9.mjs";
|
|
2
2
|
//#region src/mock.d.ts
|
|
3
3
|
/** What the next call should throw instead of answering. */
|
|
4
4
|
export interface MockFailure {
|
|
@@ -34,6 +34,11 @@ export declare class MockClient implements SgClient {
|
|
|
34
34
|
private readonly latencyMs;
|
|
35
35
|
private readonly clock;
|
|
36
36
|
private pendingFailure;
|
|
37
|
+
/** Rows a delete retired, by `Type:id`. Reads skip them and a revive puts them back. */
|
|
38
|
+
private readonly retired;
|
|
39
|
+
/** Rows a batch created with no `project`: no read reaches them, a delete does (report 001). */
|
|
40
|
+
private readonly unreadable;
|
|
41
|
+
private deletes;
|
|
37
42
|
constructor(options?: MockClientOptions);
|
|
38
43
|
/**
|
|
39
44
|
* Make the next call reject with an `SgApiError`, for demoing an error state.
|
|
@@ -53,6 +58,7 @@ export declare class MockClient implements SgClient {
|
|
|
53
58
|
number?: number;
|
|
54
59
|
}): Promise<TextSearchRow[]>;
|
|
55
60
|
update(entityType: string, id: number, patch: Record<string, unknown>): Promise<EntityRow>;
|
|
61
|
+
private updateRow;
|
|
56
62
|
/**
|
|
57
63
|
* Counts without paging rows.
|
|
58
64
|
*
|
|
@@ -104,6 +110,29 @@ export declare class MockClient implements SgClient {
|
|
|
104
110
|
* entity_types/Note). Nothing is unique, so two identical creates make two rows.
|
|
105
111
|
*/
|
|
106
112
|
create(entityType: string, body: Record<string, unknown>): Promise<EntityRow>;
|
|
113
|
+
/**
|
|
114
|
+
* A create, alone or inside a batch. The batch skips the `project` check and stores
|
|
115
|
+
* the row where no read reaches it (report 001), and it spells an unknown field its
|
|
116
|
+
* own way (recipes/002).
|
|
117
|
+
*/
|
|
118
|
+
private createRow;
|
|
119
|
+
/**
|
|
120
|
+
* Retire one row: reads skip it and a second delete is 404 (delete_entity_type_id).
|
|
121
|
+
* The mock retires only the row; what a delete does to rows that link to it
|
|
122
|
+
* (probe 060, 089_task_delete_side_effects) is not modelled.
|
|
123
|
+
*/
|
|
124
|
+
delete(entityType: string, id: number): Promise<void>;
|
|
125
|
+
private deleteRow;
|
|
126
|
+
/** Bring a retired row back with its values; `false` for a row that is already live (post_entity_type_id). */
|
|
127
|
+
revive(entityType: string, id: number): Promise<boolean>;
|
|
128
|
+
/**
|
|
129
|
+
* Apply the requests in order, and undo all of them when one fails (recipes/002).
|
|
130
|
+
* A create or update row carries the record under `data`; a delete row is flat.
|
|
131
|
+
*/
|
|
132
|
+
batch(requests: BatchRequest[]): Promise<BatchResult[]>;
|
|
133
|
+
private batchOne;
|
|
134
|
+
/** Everything a batch can change, and a function that puts it back. */
|
|
135
|
+
private snapshot;
|
|
107
136
|
/**
|
|
108
137
|
* Put a file on a row, as the three-call handshake leaves the site.
|
|
109
138
|
*
|
package/dist/mock.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as NEGATING_OPERATORS, D as toFilterArray, I as isFilterable, L as isLinkType, N as TIME_UNITS, R as isNumericType, V as operatorsFor, a as eventLogFilters, d as displayNameOf, f as fieldSchemaOverride, r as SgApiError, s as normalizeEventLogEntry, t as EVENT_LOG_FIELDS, v as pluralPath } from "./client-BdePDloQ.mjs";
|
|
2
2
|
//#region src/mock.ts
|
|
3
3
|
/**
|
|
4
4
|
* Status vocabularies. `valid_values` is the site's whole vocabulary and is
|
|
@@ -2007,6 +2007,11 @@ var MockClient = class {
|
|
|
2007
2007
|
latencyMs;
|
|
2008
2008
|
clock;
|
|
2009
2009
|
pendingFailure;
|
|
2010
|
+
/** Rows a delete retired, by `Type:id`. Reads skip them and a revive puts them back. */
|
|
2011
|
+
retired = /* @__PURE__ */ new Map();
|
|
2012
|
+
/** Rows a batch created with no `project`: no read reaches them, a delete does (report 001). */
|
|
2013
|
+
unreadable = /* @__PURE__ */ new Map();
|
|
2014
|
+
deletes = 0;
|
|
2010
2015
|
constructor(options = {}) {
|
|
2011
2016
|
this.fixtures = buildFixtures(options.seed ?? 1, options.counts ?? {});
|
|
2012
2017
|
this.latencyMs = options.latencyMs ?? 0;
|
|
@@ -2128,6 +2133,9 @@ var MockClient = class {
|
|
|
2128
2133
|
}
|
|
2129
2134
|
async update(entityType, id, patch) {
|
|
2130
2135
|
await this.gate();
|
|
2136
|
+
return this.updateRow(entityType, id, patch);
|
|
2137
|
+
}
|
|
2138
|
+
updateRow(entityType, id, patch) {
|
|
2131
2139
|
const spec = this.schemaOf(entityType);
|
|
2132
2140
|
const row = this.fixtures.index.get(`${entityType}:${id}`);
|
|
2133
2141
|
if (!row) throw new SgApiError(404, null, `Entity of type [${entityType}] with id=${id} does not exist.`);
|
|
@@ -2476,11 +2484,21 @@ var MockClient = class {
|
|
|
2476
2484
|
*/
|
|
2477
2485
|
async create(entityType, body) {
|
|
2478
2486
|
await this.gate();
|
|
2487
|
+
return this.createRow(entityType, body, false);
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* A create, alone or inside a batch. The batch skips the `project` check and stores
|
|
2491
|
+
* the row where no read reaches it (report 001), and it spells an unknown field its
|
|
2492
|
+
* own way (recipes/002).
|
|
2493
|
+
*/
|
|
2494
|
+
createRow(entityType, body, inBatch) {
|
|
2479
2495
|
const spec = this.schemaOf(entityType);
|
|
2480
|
-
|
|
2496
|
+
const orphan = spec["project"] !== void 0 && body["project"] === void 0;
|
|
2497
|
+
if (orphan && !inBatch) throw new SgApiError(400, null, `API create() missing 'project' attribute: ${JSON.stringify(body)}`);
|
|
2481
2498
|
const identity = IDENTITY_FIELD[entityType];
|
|
2482
2499
|
for (const [name, value] of Object.entries(body)) {
|
|
2483
2500
|
const field = spec[name];
|
|
2501
|
+
if (!field && inBatch) throw new SgApiError(400, null, `Invalid field value, update failed [2 - Invalid field name: field [${entityType}.${name}] does not exist or user does not have access permission.]`);
|
|
2484
2502
|
if (!field) throw new SgApiError(400, null, `API create() ${entityType}.${name} doesn't exist.`);
|
|
2485
2503
|
if (field.editable === false && !field.createOnly) throw new SgApiError(400, null, `API create() ${entityType}.${name} is read only.`);
|
|
2486
2504
|
this.checkLink("create", entityType, name, field, value);
|
|
@@ -2509,6 +2527,10 @@ var MockClient = class {
|
|
|
2509
2527
|
id,
|
|
2510
2528
|
values
|
|
2511
2529
|
};
|
|
2530
|
+
if (orphan) {
|
|
2531
|
+
this.unreadable.set(`${entityType}:${id}`, row);
|
|
2532
|
+
return this.project(row, spec);
|
|
2533
|
+
}
|
|
2512
2534
|
const rows = this.fixtures.rows.get(entityType);
|
|
2513
2535
|
if (rows) rows.push(row);
|
|
2514
2536
|
else this.fixtures.rows.set(entityType, [row]);
|
|
@@ -2517,6 +2539,113 @@ var MockClient = class {
|
|
|
2517
2539
|
return this.project(row, spec);
|
|
2518
2540
|
}
|
|
2519
2541
|
/**
|
|
2542
|
+
* Retire one row: reads skip it and a second delete is 404 (delete_entity_type_id).
|
|
2543
|
+
* The mock retires only the row; what a delete does to rows that link to it
|
|
2544
|
+
* (probe 060, 089_task_delete_side_effects) is not modelled.
|
|
2545
|
+
*/
|
|
2546
|
+
async delete(entityType, id) {
|
|
2547
|
+
await this.gate();
|
|
2548
|
+
this.deleteRow(entityType, id);
|
|
2549
|
+
}
|
|
2550
|
+
deleteRow(entityType, id) {
|
|
2551
|
+
this.schemaOf(entityType);
|
|
2552
|
+
const key = `${entityType}:${id}`;
|
|
2553
|
+
const row = this.fixtures.index.get(key) ?? this.unreadable.get(key);
|
|
2554
|
+
if (!row) throw new SgApiError(404, null, `Entity of type [${entityType}] with id=${id} does not exist.`);
|
|
2555
|
+
this.unreadable.delete(key);
|
|
2556
|
+
this.fixtures.index.delete(key);
|
|
2557
|
+
const rows = this.fixtures.rows.get(entityType) ?? [];
|
|
2558
|
+
const at = rows.indexOf(row);
|
|
2559
|
+
if (at >= 0) rows.splice(at, 1);
|
|
2560
|
+
this.retired.set(key, row);
|
|
2561
|
+
}
|
|
2562
|
+
/** Bring a retired row back with its values; `false` for a row that is already live (post_entity_type_id). */
|
|
2563
|
+
async revive(entityType, id) {
|
|
2564
|
+
await this.gate();
|
|
2565
|
+
this.schemaOf(entityType);
|
|
2566
|
+
const key = `${entityType}:${id}`;
|
|
2567
|
+
if (this.fixtures.index.has(key)) return false;
|
|
2568
|
+
const row = this.retired.get(key);
|
|
2569
|
+
if (!row) throw new SgApiError(404, null, `Entity of type [${entityType}] with id=${id} does not exist.`);
|
|
2570
|
+
this.retired.delete(key);
|
|
2571
|
+
const rows = this.fixtures.rows.get(entityType) ?? [];
|
|
2572
|
+
const at = rows.findIndex((r) => r.id > id);
|
|
2573
|
+
rows.splice(at < 0 ? rows.length : at, 0, row);
|
|
2574
|
+
this.fixtures.rows.set(entityType, rows);
|
|
2575
|
+
this.fixtures.index.set(key, row);
|
|
2576
|
+
return true;
|
|
2577
|
+
}
|
|
2578
|
+
/**
|
|
2579
|
+
* Apply the requests in order, and undo all of them when one fails (recipes/002).
|
|
2580
|
+
* A create or update row carries the record under `data`; a delete row is flat.
|
|
2581
|
+
*/
|
|
2582
|
+
async batch(requests) {
|
|
2583
|
+
await this.gate();
|
|
2584
|
+
const restore = this.snapshot();
|
|
2585
|
+
try {
|
|
2586
|
+
return requests.map((request, i) => this.batchOne(request, i));
|
|
2587
|
+
} catch (error) {
|
|
2588
|
+
restore();
|
|
2589
|
+
throw error;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
batchOne(request, i) {
|
|
2593
|
+
const invalid = (source) => new SgApiError(400, { errors: [{
|
|
2594
|
+
status: 400,
|
|
2595
|
+
code: 103,
|
|
2596
|
+
title: "Request Parameters invalid.",
|
|
2597
|
+
source
|
|
2598
|
+
}] }, "Request Parameters invalid.");
|
|
2599
|
+
const kind = request.request_type;
|
|
2600
|
+
if (kind !== "create" && kind !== "update" && kind !== "delete") throw invalid({ requests: { [i]: { request_type: ["request_type must be one of: create, update, delete"] } } });
|
|
2601
|
+
if (!request.entity) throw invalid({ requests: { [i]: { entity: ["entity is missing"] } } });
|
|
2602
|
+
if (!SPECS[request.entity]) throw new SgApiError(400, null, "Invalid entity type: entity type [] does not exist.");
|
|
2603
|
+
const id = "record_id" in request ? request.record_id ?? 0 : 0;
|
|
2604
|
+
if (request.request_type === "delete") {
|
|
2605
|
+
this.deleteRow(request.entity, id);
|
|
2606
|
+
this.deletes += 1;
|
|
2607
|
+
const uuid = `00000000-0000-4000-8000-${this.deletes.toString(16).padStart(12, "0")}`;
|
|
2608
|
+
return {
|
|
2609
|
+
request_type: "delete",
|
|
2610
|
+
type: request.entity,
|
|
2611
|
+
id,
|
|
2612
|
+
uuid,
|
|
2613
|
+
did_delete: true
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
const data = request.data;
|
|
2617
|
+
if (data === null || typeof data !== "object") throw invalid({ data: ["data hash containing field/value pairs is required for the given request"] });
|
|
2618
|
+
if (request.request_type === "create") return {
|
|
2619
|
+
request_type: "create",
|
|
2620
|
+
data: this.createRow(request.entity, data, true)
|
|
2621
|
+
};
|
|
2622
|
+
return {
|
|
2623
|
+
request_type: "update",
|
|
2624
|
+
data: this.updateRow(request.entity, id, data)
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
/** Everything a batch can change, and a function that puts it back. */
|
|
2628
|
+
snapshot() {
|
|
2629
|
+
const rows = new Map([...this.fixtures.rows].map(([type, list]) => [type, [...list]]));
|
|
2630
|
+
const index = new Map(this.fixtures.index);
|
|
2631
|
+
const values = new Map([...index.values()].map((row) => [row, structuredClone(row.values)]));
|
|
2632
|
+
const retired = new Map(this.retired);
|
|
2633
|
+
const unreadable = new Map(this.unreadable);
|
|
2634
|
+
const deletes = this.deletes;
|
|
2635
|
+
const refill = (target, from) => {
|
|
2636
|
+
target.clear();
|
|
2637
|
+
for (const [k, v] of from) target.set(k, v);
|
|
2638
|
+
};
|
|
2639
|
+
return () => {
|
|
2640
|
+
refill(this.fixtures.rows, rows);
|
|
2641
|
+
refill(this.fixtures.index, index);
|
|
2642
|
+
for (const [row, saved] of values) row.values = saved;
|
|
2643
|
+
refill(this.retired, retired);
|
|
2644
|
+
refill(this.unreadable, unreadable);
|
|
2645
|
+
this.deletes = deletes;
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
/**
|
|
2520
2649
|
* Put a file on a row, as the three-call handshake leaves the site.
|
|
2521
2650
|
*
|
|
2522
2651
|
* The field in the path picks the kind: `image` a Thumbnail, another field an
|
|
@@ -2603,7 +2732,9 @@ var MockClient = class {
|
|
|
2603
2732
|
}
|
|
2604
2733
|
/** The next free id of a type, which is what a create takes. */
|
|
2605
2734
|
nextId(entityType) {
|
|
2606
|
-
|
|
2735
|
+
let taken = (this.fixtures.rows.get(entityType) ?? []).reduce((max, row) => Math.max(max, row.id), 0);
|
|
2736
|
+
for (const row of [...this.retired.values(), ...this.unreadable.values()]) if (row.type === entityType) taken = Math.max(taken, row.id);
|
|
2737
|
+
return taken + 1;
|
|
2607
2738
|
}
|
|
2608
2739
|
/** The reverse view of a link the server fills in: a Reply lands in `Note.replies`. */
|
|
2609
2740
|
linkBack(row) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sg-widgets-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Headless, framework-agnostic model of Flow Production Tracking (ShotGrid) fields, filters, statuses and a client adapter, for building widgets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shotgrid",
|