platform-types 1.10.725 → 1.10.727
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/appointment.js +2 -1
- package/dist/cjs/appointment.js +2 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/socket.js +13 -0
- package/dist/cjs/store.js +4 -1
- package/dist/cjs/workItem.js +43 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/socket.d.ts +1 -1
- package/dist/socket.js +13 -0
- package/dist/store.d.ts +78 -3
- package/dist/store.js +4 -1
- package/dist/workItem.d.ts +188 -0
- package/dist/workItem.js +40 -0
- package/package.json +1 -1
package/dist/appointment.js
CHANGED
|
@@ -141,7 +141,8 @@ export const APPOINTMENT_ERROR_CODES = [
|
|
|
141
141
|
'ROLE_FORBIDDEN',
|
|
142
142
|
'APPOINTMENT_FEED_SECRET_NOT_CONFIGURED',
|
|
143
143
|
'APPOINTMENT_FEED_IDENTITY_INVALID',
|
|
144
|
-
// The storefront's self-booking surface, while the store has `modules.appointments` off
|
|
144
|
+
// The storefront's self-booking surface, while the store has `modules.appointments` off;
|
|
145
|
+
// its `data` is `StoreModuleDisabledData` (`StoreModuleRefusalBody` types the whole body).
|
|
145
146
|
'STORE_MODULE_DISABLED',
|
|
146
147
|
];
|
|
147
148
|
/**
|
package/dist/cjs/appointment.js
CHANGED
|
@@ -144,7 +144,8 @@ exports.APPOINTMENT_ERROR_CODES = [
|
|
|
144
144
|
'ROLE_FORBIDDEN',
|
|
145
145
|
'APPOINTMENT_FEED_SECRET_NOT_CONFIGURED',
|
|
146
146
|
'APPOINTMENT_FEED_IDENTITY_INVALID',
|
|
147
|
-
// The storefront's self-booking surface, while the store has `modules.appointments` off
|
|
147
|
+
// The storefront's self-booking surface, while the store has `modules.appointments` off;
|
|
148
|
+
// its `data` is `StoreModuleDisabledData` (`StoreModuleRefusalBody` types the whole body).
|
|
148
149
|
'STORE_MODULE_DISABLED',
|
|
149
150
|
];
|
|
150
151
|
/**
|
package/dist/cjs/index.js
CHANGED
|
@@ -121,5 +121,6 @@ __exportStar(require("./valuation.js"), exports);
|
|
|
121
121
|
__exportStar(require("./webhook.js"), exports);
|
|
122
122
|
__exportStar(require("./wire.js"), exports);
|
|
123
123
|
__exportStar(require("./whatsapp.js"), exports);
|
|
124
|
+
__exportStar(require("./workItem.js"), exports);
|
|
124
125
|
__exportStar(require("./zone.js"), exports);
|
|
125
126
|
__exportStar(require("./provinces.js"), exports);
|
package/dist/cjs/socket.js
CHANGED
|
@@ -654,6 +654,19 @@ exports.SOCKET_ACTIONS = [
|
|
|
654
654
|
* `POST /transfers` request log should expect both actions.
|
|
655
655
|
*/
|
|
656
656
|
'stockTransfers',
|
|
657
|
+
/**
|
|
658
|
+
* BE → the store's OPERATOR sockets on every work-item write: report (a new
|
|
659
|
+
* item, never a replay), handover, accept, resolve and correct. Carries
|
|
660
|
+
* `WorkItemFrameData` — `{ itemId, status, responsibleUserId }` and nothing
|
|
661
|
+
* else — so a receiving device REFETCHES `GET /work-items` rather than
|
|
662
|
+
* patching from the frame.
|
|
663
|
+
*
|
|
664
|
+
* ⚠️ Operator-only — `wsPostStore(..., { audience: 'operator' })`. The row
|
|
665
|
+
* carries the tenant's free-text `summary`, which is why the frame does not:
|
|
666
|
+
* an id-only refetch signal reaches every operator socket, and the read is
|
|
667
|
+
* where the role and scope gates sit.
|
|
668
|
+
*/
|
|
669
|
+
'workItems',
|
|
657
670
|
];
|
|
658
671
|
/** Runtime guard — narrows an untrusted string to a known action. */
|
|
659
672
|
const isSocketAction = (value) => typeof value === 'string' && exports.SOCKET_ACTIONS.includes(value);
|
package/dist/cjs/store.js
CHANGED
|
@@ -60,7 +60,10 @@ exports.isStoreModuleOn = isStoreModuleOn;
|
|
|
60
60
|
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
61
61
|
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
62
62
|
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
63
|
-
* than one depósito is active
|
|
63
|
+
* than one depósito is active, or the depósito read stopped before it could
|
|
64
|
+
* count them all; `data.activeWarehouses` carries the count, and
|
|
65
|
+
* `data.truncated: true` marks it as a floor (see
|
|
66
|
+
* {@link StoreModuleWarehousesActiveData}).
|
|
64
67
|
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
65
68
|
* transfer is in transit or partially received; `data.transferId` names one.
|
|
66
69
|
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Work items — a minimal, durable record of an UNRESOLVED transaction outcome
|
|
4
|
+
* that someone in the store is accountable for, over the existing domain
|
|
5
|
+
* records. Not a workflow engine and not a second ledger: a work-item write
|
|
6
|
+
* never mutates the business row it points at.
|
|
7
|
+
*
|
|
8
|
+
* Phase 1 is REPORT-ONLY: the phone reports device-originated uncertainty
|
|
9
|
+
* (`POST /work-items { mode: 'report' }`) — an order create whose reply was
|
|
10
|
+
* lost, cash taken but unconfirmed, a delivery outcome it cannot see. The
|
|
11
|
+
* server does not yet open items from its own handlers.
|
|
12
|
+
*
|
|
13
|
+
* Lifecycle: `open` → `resolved` (only on an AUTHORITATIVE verdict the server
|
|
14
|
+
* re-reads from the family's own source) or `corrected` (ADMIN-tier, with a
|
|
15
|
+
* recorded note). A responsibility transfer is two acts — `handover` names the
|
|
16
|
+
* receiver, and only the receiver's `accept` moves `responsibleUserId` — each
|
|
17
|
+
* under a compare-and-swap on `version`. Accountability never moves: whoever
|
|
18
|
+
* holds an item, the store's ADMIN-tier sees every open item through
|
|
19
|
+
* `GET /work-items?scope=store`.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ `summary` is the tenant's own free text. It is stored on the row and
|
|
22
|
+
* returned to the store's operators, and is never logged.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.WORK_ITEM_TEXT_MAX = exports.WORK_ITEM_PAGE_MAX = exports.WORK_ITEM_HISTORY_KINDS = exports.WORK_ITEM_SOURCE_VERDICTS = exports.WORK_ITEM_AVAILABILITIES = exports.WORK_ITEM_STATUSES = exports.WORK_ITEM_FAMILIES = void 0;
|
|
26
|
+
exports.WORK_ITEM_FAMILIES = [
|
|
27
|
+
'order-create',
|
|
28
|
+
'collection',
|
|
29
|
+
'delivery',
|
|
30
|
+
'invoice',
|
|
31
|
+
'receipt',
|
|
32
|
+
'service-draft',
|
|
33
|
+
'count-draft',
|
|
34
|
+
];
|
|
35
|
+
exports.WORK_ITEM_STATUSES = ['open', 'resolved', 'corrected'];
|
|
36
|
+
exports.WORK_ITEM_AVAILABILITIES = ['supported', 'unavailable'];
|
|
37
|
+
/** `committed` / `not-written` are authoritative and resolve; `pending` / `unknown` never do. */
|
|
38
|
+
exports.WORK_ITEM_SOURCE_VERDICTS = ['committed', 'not-written', 'pending', 'unknown'];
|
|
39
|
+
exports.WORK_ITEM_HISTORY_KINDS = ['reported', 'handover-requested', 'accepted', 'resolved', 'corrected'];
|
|
40
|
+
/** The `GET /work-items` page-size ceiling. */
|
|
41
|
+
exports.WORK_ITEM_PAGE_MAX = 100;
|
|
42
|
+
/** Upper bound on `summary` and on a `correct` note, in characters. */
|
|
43
|
+
exports.WORK_ITEM_TEXT_MAX = 500;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/socket.d.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* A client must ignore actions it does not own rather than assume it
|
|
27
27
|
* receives all of them.
|
|
28
28
|
*/
|
|
29
|
-
export declare const SOCKET_ACTIONS: readonly ["account", "appointments", "appointmentWaitlist", "attendance", "attributes", "automation-rules", "baskets", "cart", "brands", "cash", "catalogOperation", "categories", "campaigns", "customers", "customerNote", "customerAddress", "customerContact", "deliveries", "globals", "inventory", "invoices", "literals", "loyalty", "orders", "presupuestos", "products", "promotions", "segments", "returns", "rma", "templates", "services", "service-templates", "shifts", "stores", "suppliers", "supplier-invoice", "support", "surveys", "users", "warehouses", "zones", "favorites", "webhooks", "account-delete", "baskets-delete", "cart-delete", "log-delete", "notifications", "support-message", "whatsapp-order-draft", "whatsapp-order-confirmation", "payment_received", "mp_payment_status_changed", "payment_linked", "payment_unlinked", "mercadopago", "mercadopago_dynamic_qr_created", "mercadopago_static_qr_created", "mp_hook_log_appended", "mp_ipn_log_appended", "stripe", "subscription", "caea", "print", "print-order", "print-invoice", "print-product", "print-tag", "print_job_failed", "request_printers", "printers_changed", "agent_status_changed", "print_rules_changed", "printers_active", "agent_command", "maintenance", "currency_auto_updated", "drain_progress", "integration_event_appended", "userActivityRecorded", "mercadolibre_settlement_period", "customDomain", "purchaseOrders", "cycleCounts", "stockTransfers"];
|
|
29
|
+
export declare const SOCKET_ACTIONS: readonly ["account", "appointments", "appointmentWaitlist", "attendance", "attributes", "automation-rules", "baskets", "cart", "brands", "cash", "catalogOperation", "categories", "campaigns", "customers", "customerNote", "customerAddress", "customerContact", "deliveries", "globals", "inventory", "invoices", "literals", "loyalty", "orders", "presupuestos", "products", "promotions", "segments", "returns", "rma", "templates", "services", "service-templates", "shifts", "stores", "suppliers", "supplier-invoice", "support", "surveys", "users", "warehouses", "zones", "favorites", "webhooks", "account-delete", "baskets-delete", "cart-delete", "log-delete", "notifications", "support-message", "whatsapp-order-draft", "whatsapp-order-confirmation", "payment_received", "mp_payment_status_changed", "payment_linked", "payment_unlinked", "mercadopago", "mercadopago_dynamic_qr_created", "mercadopago_static_qr_created", "mp_hook_log_appended", "mp_ipn_log_appended", "stripe", "subscription", "caea", "print", "print-order", "print-invoice", "print-product", "print-tag", "print_job_failed", "request_printers", "printers_changed", "agent_status_changed", "print_rules_changed", "printers_active", "agent_command", "maintenance", "currency_auto_updated", "drain_progress", "integration_event_appended", "userActivityRecorded", "mercadolibre_settlement_period", "customDomain", "purchaseOrders", "cycleCounts", "stockTransfers", "workItems"];
|
|
30
30
|
/** Union of every server→client data-frame action. */
|
|
31
31
|
export type SocketAction = (typeof SOCKET_ACTIONS)[number];
|
|
32
32
|
/**
|
package/dist/socket.js
CHANGED
|
@@ -651,6 +651,19 @@ export const SOCKET_ACTIONS = [
|
|
|
651
651
|
* `POST /transfers` request log should expect both actions.
|
|
652
652
|
*/
|
|
653
653
|
'stockTransfers',
|
|
654
|
+
/**
|
|
655
|
+
* BE → the store's OPERATOR sockets on every work-item write: report (a new
|
|
656
|
+
* item, never a replay), handover, accept, resolve and correct. Carries
|
|
657
|
+
* `WorkItemFrameData` — `{ itemId, status, responsibleUserId }` and nothing
|
|
658
|
+
* else — so a receiving device REFETCHES `GET /work-items` rather than
|
|
659
|
+
* patching from the frame.
|
|
660
|
+
*
|
|
661
|
+
* ⚠️ Operator-only — `wsPostStore(..., { audience: 'operator' })`. The row
|
|
662
|
+
* carries the tenant's free-text `summary`, which is why the frame does not:
|
|
663
|
+
* an id-only refetch signal reaches every operator socket, and the read is
|
|
664
|
+
* where the role and scope gates sit.
|
|
665
|
+
*/
|
|
666
|
+
'workItems',
|
|
654
667
|
];
|
|
655
668
|
/** Runtime guard — narrows an untrusted string to a known action. */
|
|
656
669
|
export const isSocketAction = (value) => typeof value === 'string' && SOCKET_ACTIONS.includes(value);
|
package/dist/store.d.ts
CHANGED
|
@@ -907,8 +907,10 @@ declare global {
|
|
|
907
907
|
* `400 STORE_MODULE_NOT_BOOLEAN`.
|
|
908
908
|
*
|
|
909
909
|
* Turning a module OFF is refused while it still carries state:
|
|
910
|
-
* `multiWarehouse` while more than one depósito is active
|
|
911
|
-
*
|
|
910
|
+
* `multiWarehouse` while more than one depósito is active, or the
|
|
911
|
+
* depósito read could not finish counting
|
|
912
|
+
* (`409 STORE_MODULE_WAREHOUSES_ACTIVE`, `data.truncated: true` on the
|
|
913
|
+
* latter — `StoreModuleWarehousesActiveData`) or a transfer is in transit or
|
|
912
914
|
* partially received (`409 STORE_MODULE_TRANSFER_IN_FLIGHT`);
|
|
913
915
|
* `customerAccounts` while any customer carries a non-zero balance
|
|
914
916
|
* (`409 STORE_MODULE_CUSTOMER_BALANCES`, or
|
|
@@ -2025,7 +2027,10 @@ export declare const isStoreModuleOn: (modules: StoreModules | null | undefined,
|
|
|
2025
2027
|
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
2026
2028
|
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
2027
2029
|
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
2028
|
-
* than one depósito is active
|
|
2030
|
+
* than one depósito is active, or the depósito read stopped before it could
|
|
2031
|
+
* count them all; `data.activeWarehouses` carries the count, and
|
|
2032
|
+
* `data.truncated: true` marks it as a floor (see
|
|
2033
|
+
* {@link StoreModuleWarehousesActiveData}).
|
|
2029
2034
|
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
2030
2035
|
* transfer is in transit or partially received; `data.transferId` names one.
|
|
2031
2036
|
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
@@ -2038,3 +2043,73 @@ export declare const isStoreModuleOn: (modules: StoreModules | null | undefined,
|
|
|
2038
2043
|
*/
|
|
2039
2044
|
export declare const STORE_MODULE_ERROR_CODES: readonly ["STORE_MODULE_UNKNOWN", "STORE_MODULE_NOT_BOOLEAN", "STORE_MODULE_WAREHOUSES_ACTIVE", "STORE_MODULE_TRANSFER_IN_FLIGHT", "STORE_MODULE_CUSTOMER_BALANCES", "STORE_MODULE_BALANCE_CHECK_INCOMPLETE", "STORE_MODULE_DISABLED"];
|
|
2040
2045
|
export type StoreModuleErrorCode = (typeof STORE_MODULE_ERROR_CODES)[number];
|
|
2046
|
+
/** `data` of `400 STORE_MODULE_UNKNOWN` — the unknown key, cut to its first 64 UTF-16 code units. */
|
|
2047
|
+
export interface StoreModuleUnknownData {
|
|
2048
|
+
module: string;
|
|
2049
|
+
}
|
|
2050
|
+
/** `data` of `400 STORE_MODULE_NOT_BOOLEAN` — the module whose value was not a boolean. */
|
|
2051
|
+
export interface StoreModuleNotBooleanData {
|
|
2052
|
+
module: StoreModuleKey;
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* `data` of `409 STORE_MODULE_WAREHOUSES_ACTIVE`.
|
|
2056
|
+
*
|
|
2057
|
+
* `activeWarehouses` is the number of active depósitos the read SAW.
|
|
2058
|
+
* `truncated: true` marks the read as stopped early, so that number is a FLOOR:
|
|
2059
|
+
* at `2` or more the store still has extra depósitos to deactivate (the true
|
|
2060
|
+
* count is at least that); at `0` or `1` the refusal means only "could not
|
|
2061
|
+
* finish counting", and deactivating depósitos is not the remedy. `truncated`
|
|
2062
|
+
* is present only on a stopped read; its absence means the count is exact (and
|
|
2063
|
+
* therefore above one).
|
|
2064
|
+
*/
|
|
2065
|
+
export interface StoreModuleWarehousesActiveData {
|
|
2066
|
+
module: 'multiWarehouse';
|
|
2067
|
+
activeWarehouses: number;
|
|
2068
|
+
truncated?: true;
|
|
2069
|
+
}
|
|
2070
|
+
/** `data` of `409 STORE_MODULE_TRANSFER_IN_FLIGHT` — one in-flight transfer, the bare `TRF…` id. */
|
|
2071
|
+
export interface StoreModuleTransferInFlightData {
|
|
2072
|
+
module: 'multiWarehouse';
|
|
2073
|
+
transferId: string;
|
|
2074
|
+
}
|
|
2075
|
+
/** `data` of `409 STORE_MODULE_CUSTOMER_BALANCES` — one customer with a balance, the bare `CUST…` id. */
|
|
2076
|
+
export interface StoreModuleCustomerBalancesData {
|
|
2077
|
+
module: 'customerAccounts';
|
|
2078
|
+
customerId: string;
|
|
2079
|
+
}
|
|
2080
|
+
/** `data` of `409 STORE_MODULE_BALANCE_CHECK_INCOMPLETE`. */
|
|
2081
|
+
export interface StoreModuleBalanceCheckIncompleteData {
|
|
2082
|
+
module: 'customerAccounts';
|
|
2083
|
+
}
|
|
2084
|
+
/** `data` of `403 STORE_MODULE_DISABLED` — the switched-off module the request needed. */
|
|
2085
|
+
export interface StoreModuleDisabledData {
|
|
2086
|
+
module: StoreModuleKey;
|
|
2087
|
+
}
|
|
2088
|
+
/**
|
|
2089
|
+
* Each `STORE_MODULE_*` code and the `data` it carries — the union below is
|
|
2090
|
+
* derived from it. Keyed by exactly `StoreModuleErrorCode`, both ways: a code
|
|
2091
|
+
* missing here fails the union's index, and a key no code names fails
|
|
2092
|
+
* `tests/unit/storeModules.test.ts`'s type-level check.
|
|
2093
|
+
*/
|
|
2094
|
+
export interface StoreModuleRefusalDataByCode {
|
|
2095
|
+
STORE_MODULE_UNKNOWN: StoreModuleUnknownData;
|
|
2096
|
+
STORE_MODULE_NOT_BOOLEAN: StoreModuleNotBooleanData;
|
|
2097
|
+
STORE_MODULE_WAREHOUSES_ACTIVE: StoreModuleWarehousesActiveData;
|
|
2098
|
+
STORE_MODULE_TRANSFER_IN_FLIGHT: StoreModuleTransferInFlightData;
|
|
2099
|
+
STORE_MODULE_CUSTOMER_BALANCES: StoreModuleCustomerBalancesData;
|
|
2100
|
+
STORE_MODULE_BALANCE_CHECK_INCOMPLETE: StoreModuleBalanceCheckIncompleteData;
|
|
2101
|
+
STORE_MODULE_DISABLED: StoreModuleDisabledData;
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* The wire body of any store-module refusal, discriminated on `error` —
|
|
2105
|
+
* narrowing on the code types `data`. Every emitter checks its whole body
|
|
2106
|
+
* against it with `satisfies`, so a code cannot travel with another code's
|
|
2107
|
+
* `data`.
|
|
2108
|
+
*/
|
|
2109
|
+
export type StoreModuleRefusalBody = {
|
|
2110
|
+
[Code in StoreModuleErrorCode]: {
|
|
2111
|
+
error: Code;
|
|
2112
|
+
message: string;
|
|
2113
|
+
data: StoreModuleRefusalDataByCode[Code];
|
|
2114
|
+
};
|
|
2115
|
+
}[StoreModuleErrorCode];
|
package/dist/store.js
CHANGED
|
@@ -55,7 +55,10 @@ export const isStoreModuleOn = (modules, module) => modules?.[module] !== false;
|
|
|
55
55
|
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
56
56
|
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
57
57
|
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
58
|
-
* than one depósito is active
|
|
58
|
+
* than one depósito is active, or the depósito read stopped before it could
|
|
59
|
+
* count them all; `data.activeWarehouses` carries the count, and
|
|
60
|
+
* `data.truncated: true` marks it as a floor (see
|
|
61
|
+
* {@link StoreModuleWarehousesActiveData}).
|
|
59
62
|
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
60
63
|
* transfer is in transit or partially received; `data.transferId` names one.
|
|
61
64
|
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work items — a minimal, durable record of an UNRESOLVED transaction outcome
|
|
3
|
+
* that someone in the store is accountable for, over the existing domain
|
|
4
|
+
* records. Not a workflow engine and not a second ledger: a work-item write
|
|
5
|
+
* never mutates the business row it points at.
|
|
6
|
+
*
|
|
7
|
+
* Phase 1 is REPORT-ONLY: the phone reports device-originated uncertainty
|
|
8
|
+
* (`POST /work-items { mode: 'report' }`) — an order create whose reply was
|
|
9
|
+
* lost, cash taken but unconfirmed, a delivery outcome it cannot see. The
|
|
10
|
+
* server does not yet open items from its own handlers.
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle: `open` → `resolved` (only on an AUTHORITATIVE verdict the server
|
|
13
|
+
* re-reads from the family's own source) or `corrected` (ADMIN-tier, with a
|
|
14
|
+
* recorded note). A responsibility transfer is two acts — `handover` names the
|
|
15
|
+
* receiver, and only the receiver's `accept` moves `responsibleUserId` — each
|
|
16
|
+
* under a compare-and-swap on `version`. Accountability never moves: whoever
|
|
17
|
+
* holds an item, the store's ADMIN-tier sees every open item through
|
|
18
|
+
* `GET /work-items?scope=store`.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ `summary` is the tenant's own free text. It is stored on the row and
|
|
21
|
+
* returned to the store's operators, and is never logged.
|
|
22
|
+
*/
|
|
23
|
+
declare global {
|
|
24
|
+
/** One of {@link WORK_ITEM_FAMILIES} — which domain source decides the item. */
|
|
25
|
+
type WorkItemFamily = (typeof WORK_ITEM_FAMILIES)[number];
|
|
26
|
+
/** One of {@link WORK_ITEM_STATUSES}. */
|
|
27
|
+
type WorkItemStatus = (typeof WORK_ITEM_STATUSES)[number];
|
|
28
|
+
/** One of {@link WORK_ITEM_AVAILABILITIES}. */
|
|
29
|
+
type WorkItemAvailability = (typeof WORK_ITEM_AVAILABILITIES)[number];
|
|
30
|
+
/** One of {@link WORK_ITEM_SOURCE_VERDICTS}. */
|
|
31
|
+
type WorkItemSourceVerdictKind = (typeof WORK_ITEM_SOURCE_VERDICTS)[number];
|
|
32
|
+
/** One of {@link WORK_ITEM_HISTORY_KINDS}. */
|
|
33
|
+
type WorkItemHistoryKind = (typeof WORK_ITEM_HISTORY_KINDS)[number];
|
|
34
|
+
/**
|
|
35
|
+
* The exact domain ids the item points at, plus the client's attempt key.
|
|
36
|
+
*
|
|
37
|
+
* `attemptKey` is REQUIRED on every report: the order-create `attemptKey`
|
|
38
|
+
* for `order-create`, the write's `Idempotency-Key` for every other family —
|
|
39
|
+
* so a remote item matches the phone's local attempt one-to-one, and
|
|
40
|
+
* `(storeId, family, attemptKey)` is the report's idempotency key.
|
|
41
|
+
*
|
|
42
|
+
* Which ids the server reads per family when resolving:
|
|
43
|
+
* - `order-create` — `attemptKey` (the create-attempt row). Run
|
|
44
|
+
* `POST /orders { mode: 'create-attempt' }` first: only its tombstone
|
|
45
|
+
* makes `not-written` provable.
|
|
46
|
+
* - `collection` — `operation`, `orderId`, `attemptKey` (the write's
|
|
47
|
+
* idempotency marker, as `POST /orders { mode: 'collection-attempt' }`).
|
|
48
|
+
* - `delivery` — `deliveryId` + `attemptKey` (the event's attempt row; run
|
|
49
|
+
* the delivery attempt lookup first, for the same reason).
|
|
50
|
+
* - `invoice` — `invoiceId` (that invoice's own fiscal status).
|
|
51
|
+
* - `receipt`, `service-draft`, `count-draft` — `unavailable`: no write in
|
|
52
|
+
* these families leaves evidence bound to the attempt key, so an item of
|
|
53
|
+
* theirs closes only through an ADMIN-tier `correct`. `receiptId`,
|
|
54
|
+
* `serviceOrderId` and `cycleCountId` are kept for the operator's context.
|
|
55
|
+
*/
|
|
56
|
+
interface WorkItemSourceRef {
|
|
57
|
+
attemptKey: string;
|
|
58
|
+
orderId?: string;
|
|
59
|
+
operation?: OrderCollectionAttemptOperation;
|
|
60
|
+
deliveryId?: string;
|
|
61
|
+
invoiceId?: string;
|
|
62
|
+
receiptId?: string;
|
|
63
|
+
serviceOrderId?: string;
|
|
64
|
+
cycleCountId?: string;
|
|
65
|
+
}
|
|
66
|
+
/** A pending responsibility transfer — set by `handover`, consumed by `accept`. */
|
|
67
|
+
interface WorkItemPendingHandover {
|
|
68
|
+
fromUserId: string;
|
|
69
|
+
toUserId: string;
|
|
70
|
+
requestedBy: string;
|
|
71
|
+
requestedAt: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* What the server read at the source when it resolved the item. Only
|
|
75
|
+
* `committed` and `not-written` resolve; `pending` and `unknown` are refused
|
|
76
|
+
* `409 WORK_ITEM_UNRESOLVED_AT_SOURCE` with this verdict as `data.verdict`.
|
|
77
|
+
* `reason` is a machine code naming what decided it (or why nothing did).
|
|
78
|
+
*/
|
|
79
|
+
interface WorkItemSourceVerdict {
|
|
80
|
+
verdict: WorkItemSourceVerdictKind;
|
|
81
|
+
reason: string;
|
|
82
|
+
}
|
|
83
|
+
/** One append-only history entry. The original actor stays on the item itself. */
|
|
84
|
+
interface WorkItemHistoryEntry {
|
|
85
|
+
kind: WorkItemHistoryKind;
|
|
86
|
+
at: number;
|
|
87
|
+
byUserId: string;
|
|
88
|
+
fromUserId?: string;
|
|
89
|
+
toUserId?: string;
|
|
90
|
+
verdict?: WorkItemSourceVerdict;
|
|
91
|
+
note?: string;
|
|
92
|
+
}
|
|
93
|
+
/** One work item as the API answers it. */
|
|
94
|
+
interface WorkItem {
|
|
95
|
+
itemId: string;
|
|
96
|
+
storeId: string;
|
|
97
|
+
family: WorkItemFamily;
|
|
98
|
+
sourceRef: WorkItemSourceRef;
|
|
99
|
+
/** Tenant free text. Never logged. */
|
|
100
|
+
summary: string;
|
|
101
|
+
/** Who reported it. Never changes — a handover moves responsibility, not provenance. */
|
|
102
|
+
originalActorId: string;
|
|
103
|
+
/** Device clock (epoch ms) when the phone captured the uncertainty. Informational. */
|
|
104
|
+
capturedAt: number;
|
|
105
|
+
/** Server clock (epoch ms) when the report landed. */
|
|
106
|
+
reportedAt: number;
|
|
107
|
+
status: WorkItemStatus;
|
|
108
|
+
responsibleUserId: string;
|
|
109
|
+
pendingHandover?: WorkItemPendingHandover;
|
|
110
|
+
history: WorkItemHistoryEntry[];
|
|
111
|
+
/** Compare-and-swap token: every transition is conditioned on it and bumps it (`handover`, `accept` and `correct` also take it as `expectedVersion`). */
|
|
112
|
+
version: number;
|
|
113
|
+
resolution?: WorkItemSourceVerdict;
|
|
114
|
+
createdAt: number;
|
|
115
|
+
updatedAt: number;
|
|
116
|
+
}
|
|
117
|
+
/** `POST /work-items { mode: 'report' }` — staffToken. */
|
|
118
|
+
interface WorkItemReportRequest {
|
|
119
|
+
mode: 'report';
|
|
120
|
+
family: WorkItemFamily;
|
|
121
|
+
sourceRef: WorkItemSourceRef;
|
|
122
|
+
summary: string;
|
|
123
|
+
capturedAt: number;
|
|
124
|
+
}
|
|
125
|
+
/** `POST /work-items { mode: 'handover' }` — the responsible user or ADMIN-tier. */
|
|
126
|
+
interface WorkItemHandoverRequest {
|
|
127
|
+
mode: 'handover';
|
|
128
|
+
itemId: string;
|
|
129
|
+
toUserId: string;
|
|
130
|
+
expectedVersion: number;
|
|
131
|
+
}
|
|
132
|
+
/** `POST /work-items { mode: 'accept' }` — only the pending handover's `toUserId`. */
|
|
133
|
+
interface WorkItemAcceptRequest {
|
|
134
|
+
mode: 'accept';
|
|
135
|
+
itemId: string;
|
|
136
|
+
expectedVersion: number;
|
|
137
|
+
}
|
|
138
|
+
/** `POST /work-items { mode: 'resolve' }` — the responsible user or ADMIN-tier. */
|
|
139
|
+
interface WorkItemResolveRequest {
|
|
140
|
+
mode: 'resolve';
|
|
141
|
+
itemId: string;
|
|
142
|
+
}
|
|
143
|
+
/** `POST /work-items { mode: 'correct' }` — ADMIN-tier only; `note` is recorded. */
|
|
144
|
+
interface WorkItemCorrectRequest {
|
|
145
|
+
mode: 'correct';
|
|
146
|
+
itemId: string;
|
|
147
|
+
note: string;
|
|
148
|
+
expectedVersion: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* `data` of a `200` from `GET /work-items?scope=mine|store|offered`.
|
|
152
|
+
*
|
|
153
|
+
* - `items` — OPEN items only, newest first. `mine`: responsible to the
|
|
154
|
+
* caller. `offered`: a pending handover names the caller. `store`
|
|
155
|
+
* (ADMIN-tier): every open item.
|
|
156
|
+
* - `openCount` — from a per-store counter row (`mine`/`offered`: the
|
|
157
|
+
* caller's own responsible count), so a badge needs no page walk. Never
|
|
158
|
+
* negative.
|
|
159
|
+
* - `availability` — EVERY family, `supported` when the server can read its
|
|
160
|
+
* source verdict. An `unavailable` family means its items cannot be
|
|
161
|
+
* resolved from evidence yet — never read its absence from `items` as an
|
|
162
|
+
* all-clear.
|
|
163
|
+
*
|
|
164
|
+
* Paging sits beside `data`: `truncated` and, when a next page exists,
|
|
165
|
+
* an opaque `LastEvaluatedKey` to send back as `?startKey=`.
|
|
166
|
+
*/
|
|
167
|
+
interface WorkItemListData {
|
|
168
|
+
items: WorkItem[];
|
|
169
|
+
openCount: number;
|
|
170
|
+
availability: Record<WorkItemFamily, WorkItemAvailability>;
|
|
171
|
+
}
|
|
172
|
+
/** The `workItems` socket frame's `data` — refetch, never patch from it. */
|
|
173
|
+
interface WorkItemFrameData {
|
|
174
|
+
itemId: string;
|
|
175
|
+
status: WorkItemStatus;
|
|
176
|
+
responsibleUserId: string;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export declare const WORK_ITEM_FAMILIES: readonly ["order-create", "collection", "delivery", "invoice", "receipt", "service-draft", "count-draft"];
|
|
180
|
+
export declare const WORK_ITEM_STATUSES: readonly ["open", "resolved", "corrected"];
|
|
181
|
+
export declare const WORK_ITEM_AVAILABILITIES: readonly ["supported", "unavailable"];
|
|
182
|
+
/** `committed` / `not-written` are authoritative and resolve; `pending` / `unknown` never do. */
|
|
183
|
+
export declare const WORK_ITEM_SOURCE_VERDICTS: readonly ["committed", "not-written", "pending", "unknown"];
|
|
184
|
+
export declare const WORK_ITEM_HISTORY_KINDS: readonly ["reported", "handover-requested", "accepted", "resolved", "corrected"];
|
|
185
|
+
/** The `GET /work-items` page-size ceiling. */
|
|
186
|
+
export declare const WORK_ITEM_PAGE_MAX = 100;
|
|
187
|
+
/** Upper bound on `summary` and on a `correct` note, in characters. */
|
|
188
|
+
export declare const WORK_ITEM_TEXT_MAX = 500;
|
package/dist/workItem.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work items — a minimal, durable record of an UNRESOLVED transaction outcome
|
|
3
|
+
* that someone in the store is accountable for, over the existing domain
|
|
4
|
+
* records. Not a workflow engine and not a second ledger: a work-item write
|
|
5
|
+
* never mutates the business row it points at.
|
|
6
|
+
*
|
|
7
|
+
* Phase 1 is REPORT-ONLY: the phone reports device-originated uncertainty
|
|
8
|
+
* (`POST /work-items { mode: 'report' }`) — an order create whose reply was
|
|
9
|
+
* lost, cash taken but unconfirmed, a delivery outcome it cannot see. The
|
|
10
|
+
* server does not yet open items from its own handlers.
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle: `open` → `resolved` (only on an AUTHORITATIVE verdict the server
|
|
13
|
+
* re-reads from the family's own source) or `corrected` (ADMIN-tier, with a
|
|
14
|
+
* recorded note). A responsibility transfer is two acts — `handover` names the
|
|
15
|
+
* receiver, and only the receiver's `accept` moves `responsibleUserId` — each
|
|
16
|
+
* under a compare-and-swap on `version`. Accountability never moves: whoever
|
|
17
|
+
* holds an item, the store's ADMIN-tier sees every open item through
|
|
18
|
+
* `GET /work-items?scope=store`.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ `summary` is the tenant's own free text. It is stored on the row and
|
|
21
|
+
* returned to the store's operators, and is never logged.
|
|
22
|
+
*/
|
|
23
|
+
export const WORK_ITEM_FAMILIES = [
|
|
24
|
+
'order-create',
|
|
25
|
+
'collection',
|
|
26
|
+
'delivery',
|
|
27
|
+
'invoice',
|
|
28
|
+
'receipt',
|
|
29
|
+
'service-draft',
|
|
30
|
+
'count-draft',
|
|
31
|
+
];
|
|
32
|
+
export const WORK_ITEM_STATUSES = ['open', 'resolved', 'corrected'];
|
|
33
|
+
export const WORK_ITEM_AVAILABILITIES = ['supported', 'unavailable'];
|
|
34
|
+
/** `committed` / `not-written` are authoritative and resolve; `pending` / `unknown` never do. */
|
|
35
|
+
export const WORK_ITEM_SOURCE_VERDICTS = ['committed', 'not-written', 'pending', 'unknown'];
|
|
36
|
+
export const WORK_ITEM_HISTORY_KINDS = ['reported', 'handover-requested', 'accepted', 'resolved', 'corrected'];
|
|
37
|
+
/** The `GET /work-items` page-size ceiling. */
|
|
38
|
+
export const WORK_ITEM_PAGE_MAX = 100;
|
|
39
|
+
/** Upper bound on `summary` and on a `correct` note, in characters. */
|
|
40
|
+
export const WORK_ITEM_TEXT_MAX = 500;
|