@kottera/tera-web 0.1.0-rc.3 → 0.1.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/dist/client.d.ts +59 -5
- package/dist/client.js +203 -16
- package/dist/feed/connection.d.ts +2 -0
- package/dist/feed/connection.js +2 -2
- package/dist/generated/kit.d.ts +67 -7
- package/dist/generated/kit.js +28 -5
- package/dist/generated/shares.d.ts +196 -0
- package/dist/generated/shares.js +17 -0
- package/dist/generated/workorder.d.ts +82 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -2
- package/dist/phone.d.ts +11 -0
- package/dist/phone.js +24 -0
- package/dist/routes.d.ts +22 -0
- package/dist/routes.js +37 -0
- package/dist/stepup.d.ts +87 -0
- package/dist/stepup.js +66 -0
- package/package.json +1 -1
package/dist/generated/kit.js
CHANGED
|
@@ -10,16 +10,20 @@ export const KIT_SCHEMAS = {
|
|
|
10
10
|
KitFeedEventReauthenticate: "sdk/plugin/webui/schema/v1/feed.event.reauthenticate.json",
|
|
11
11
|
KitInvokeResponse: "sdk/plugin/webui/schema/v1/invoke.response.json",
|
|
12
12
|
KitMeResponse: "sdk/plugin/webui/schema/v1/me.response.json",
|
|
13
|
+
KitStepUpResponse: "sdk/plugin/webui/schema/v1/step-up.response.json",
|
|
13
14
|
KitUploadResponse: "sdk/plugin/webui/schema/v1/upload.response.json",
|
|
14
15
|
};
|
|
15
|
-
/** The prefix every kit route is served under (ADR-162 D3). */
|
|
16
|
+
/** The prefix every kit route is served under (ADR-162 D3), below the app's base. */
|
|
16
17
|
export const KIT_ROUTE_PREFIX = "/tera/v1/";
|
|
17
|
-
/** tera's own sign-out path, which `GET /tera/v1/me` answers as signout_path. */
|
|
18
|
-
export const KIT_SIGNOUT_PATH = "
|
|
18
|
+
/** tera's own sign-out path, which `GET /tera/v1/me` answers as signout_path: relative, resolved against the app's base. */
|
|
19
|
+
export const KIT_SIGNOUT_PATH = "_tera/signout";
|
|
20
|
+
/** tera's proxy's phone path, which `GET /tera/v1/me` answers as phone_path: relative, resolved against the app's base. */
|
|
21
|
+
export const KIT_PHONE_PATH = "_tera/phone";
|
|
19
22
|
/** The kit's route table (ADR-162 D3), as sdk/plugin/webui declares it. */
|
|
20
23
|
export const KIT_ROUTE_TABLE = {
|
|
21
24
|
prefix: "/tera/v1/",
|
|
22
|
-
signout_path: "
|
|
25
|
+
signout_path: "_tera/signout",
|
|
26
|
+
phone_path: "_tera/phone",
|
|
23
27
|
same_origin: "A route marked same_origin refuses a request unless it is same-origin: when the request carries Sec-Fetch-Site, that header must be same-origin; when it does not, its Origin must equal the request's own (scheme http or https, and the Host the request was sent to). The refusal is 403 cross_origin.",
|
|
24
28
|
public: "None. Every route under the prefix refuses a request with no verified caller, 401 unauthenticated, before anything else is decided. Only the app's assets, outside the prefix, are served to an anonymous request.",
|
|
25
29
|
error: {
|
|
@@ -32,7 +36,7 @@ export const KIT_ROUTE_TABLE = {
|
|
|
32
36
|
name: "me",
|
|
33
37
|
method: "GET",
|
|
34
38
|
path: "/tera/v1/me",
|
|
35
|
-
summary: "Who is signed in, and where to send them to
|
|
39
|
+
summary: "Who is signed in, where to send them to sign out, and where to send them to open a page on their phone.",
|
|
36
40
|
same_origin: false,
|
|
37
41
|
response: {
|
|
38
42
|
media_type: "application/json",
|
|
@@ -144,5 +148,24 @@ export const KIT_ROUTE_TABLE = {
|
|
|
144
148
|
description: "The staged artifact.",
|
|
145
149
|
},
|
|
146
150
|
},
|
|
151
|
+
{
|
|
152
|
+
name: "step_up",
|
|
153
|
+
method: "GET",
|
|
154
|
+
path: "/tera/v1/step-ups/{id}",
|
|
155
|
+
summary: "Read one of the person's own step-ups as the person (ADR-173 D11): what a page polls, after opening the step-up's url, until it is satisfied, declined or expired. A step-up that is not the person's is tera's 404, the same as an id no step-up carries.",
|
|
156
|
+
same_origin: false,
|
|
157
|
+
path_params: [
|
|
158
|
+
{
|
|
159
|
+
name: "id",
|
|
160
|
+
description: "The step-up's id, as a step_up_required refusal's step_up names it.",
|
|
161
|
+
required: true,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
response: {
|
|
165
|
+
media_type: "application/json",
|
|
166
|
+
schema: "https://kottera.dev/schemas/plugin/webui/step-up.response/v1",
|
|
167
|
+
description: "The step-up's state.",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
147
170
|
],
|
|
148
171
|
};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An ended share.
|
|
3
|
+
*
|
|
4
|
+
* The result of api.v1.shares.delete and api.v1.shares.leave: what the act ended. An ended share decides nothing and is not listed.
|
|
5
|
+
*
|
|
6
|
+
* Schema: sdk/shares/schema/v1/ended.json
|
|
7
|
+
*/
|
|
8
|
+
export type SharesEnded = {
|
|
9
|
+
/** The ended share's id. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** The installation whose resource was shared, <vault>/plugins/<installation>. */
|
|
12
|
+
installation: string;
|
|
13
|
+
/** The resource that was shared. */
|
|
14
|
+
resource: string;
|
|
15
|
+
/** The grantee person's id. */
|
|
16
|
+
grantee: string;
|
|
17
|
+
/** The sharer person's id. */
|
|
18
|
+
sharer: string;
|
|
19
|
+
/** How the share ended, as its record holds it: revoked or left. */
|
|
20
|
+
ended: "revoked" | "left";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Extend a share.
|
|
24
|
+
*
|
|
25
|
+
* The params of api.v1.shares.patch, PATCH /api/v1/shares/{id} (ADR-174 D11).
|
|
26
|
+
*
|
|
27
|
+
* Schema: sdk/shares/schema/v1/extend.request.json
|
|
28
|
+
*/
|
|
29
|
+
export type SharesExtendRequest = {
|
|
30
|
+
/** The share's id, a UUIDv7. */
|
|
31
|
+
id: string;
|
|
32
|
+
/** The new expiry: later than the share's, at most the installation's max_expiry from now. Absent takes the kind's default_expiry from now, clamped to max_expiry. */
|
|
33
|
+
expires_at?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Name one share.
|
|
37
|
+
*
|
|
38
|
+
* The params of api.v1.shares.get, api.v1.shares.delete and api.v1.shares.leave: the {id} of /api/v1/shares/{id}.
|
|
39
|
+
*
|
|
40
|
+
* Schema: sdk/shares/schema/v1/id.request.json
|
|
41
|
+
*/
|
|
42
|
+
export type SharesIdRequest = {
|
|
43
|
+
/** The share's id, a UUIDv7. */
|
|
44
|
+
id: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* A list of shares.
|
|
48
|
+
*
|
|
49
|
+
* The result of api.v1.shares.list.
|
|
50
|
+
*
|
|
51
|
+
* Schema: sdk/shares/schema/v1/list.json
|
|
52
|
+
*/
|
|
53
|
+
export type SharesList = {
|
|
54
|
+
/** The shares, each with whether it decides now. */
|
|
55
|
+
shares: {
|
|
56
|
+
/** The share's id, a UUIDv7. */
|
|
57
|
+
id: string;
|
|
58
|
+
/** The installation whose resource is shared, <vault>/plugins/<installation>. */
|
|
59
|
+
installation: string;
|
|
60
|
+
/** The resource shared, plugins/<vault>/<installation>/<kind>/<id>. */
|
|
61
|
+
resource: string;
|
|
62
|
+
/** The shared verbs. */
|
|
63
|
+
verbs: string[] | null;
|
|
64
|
+
/** What the grantee is: person. */
|
|
65
|
+
grantee_kind: string;
|
|
66
|
+
/** The grantee person's id. */
|
|
67
|
+
grantee: string;
|
|
68
|
+
/** The id of the person who made the share. */
|
|
69
|
+
sharer: string;
|
|
70
|
+
/** The plugin principal that made the share for its sharer; absent when the sharer made it directly. */
|
|
71
|
+
created_via?: string;
|
|
72
|
+
/** When the share was made. */
|
|
73
|
+
created_at: string;
|
|
74
|
+
/** When the share stops deciding. */
|
|
75
|
+
expires_at: string;
|
|
76
|
+
/** When the share was last extended; absent if never. */
|
|
77
|
+
extended_at?: string;
|
|
78
|
+
/** Whether the share decides at least one of its verbs on the grantee's next request, computed from what decides now. */
|
|
79
|
+
deciding: boolean;
|
|
80
|
+
/** When deciding is false, the one reason why. Absent while the share decides. */
|
|
81
|
+
not_deciding?: "sharer_lost_access" | "sharing_disabled" | "installation_not_standing" | "verb_no_longer_shareable" | "pending_invitation";
|
|
82
|
+
}[] | null;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* List shares.
|
|
86
|
+
*
|
|
87
|
+
* The params of api.v1.shares.list, the query of GET /api/v1/shares. At most one member is named; with none, the caller's own live shares as grantee and as sharer.
|
|
88
|
+
*
|
|
89
|
+
* Schema: sdk/shares/schema/v1/list.request.json
|
|
90
|
+
*/
|
|
91
|
+
export type SharesListRequest = {
|
|
92
|
+
/** An installation, <vault>/plugins/<name>: every share on it. Needs the shares admin grant (api/v1/shares/admin). */
|
|
93
|
+
installation?: string;
|
|
94
|
+
/** One resource, plugins/<vault>/<installation>/<kind>/<id>: every share on it when the caller's own grants include its share-conferring verb, else the caller's own shares on it. */
|
|
95
|
+
resource?: string;
|
|
96
|
+
/** A grantee's person id; someone else's needs the shares admin grant. */
|
|
97
|
+
grantee?: string;
|
|
98
|
+
/** A sharer's person id; someone else's needs the shares admin grant. */
|
|
99
|
+
sharer?: string;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Make a share.
|
|
103
|
+
*
|
|
104
|
+
* The params of api.v1.shares.create, the body of POST /api/v1/shares (ADR-174 D6).
|
|
105
|
+
*
|
|
106
|
+
* Schema: sdk/shares/schema/v1/make.request.json
|
|
107
|
+
*/
|
|
108
|
+
export type SharesMakeRequest = {
|
|
109
|
+
/** The one resource shared, plugins/<vault>/<installation>/<kind>/<id>. */
|
|
110
|
+
resource: string;
|
|
111
|
+
/** The shared verbs: a non-empty subset of the kind's sharing { verbs }, never its share-conferring verb. */
|
|
112
|
+
verbs: string[];
|
|
113
|
+
/** The grantee person's id. Exactly one of grantee and grantee_address names the grantee. */
|
|
114
|
+
grantee?: string;
|
|
115
|
+
/** An email address the directory resolves to the grantee. An address no person holds is invited, and the share is pending until they sign in, on a kind whose effective grantee class is addresses; otherwise it is refused share_grantee_not_admitted. */
|
|
116
|
+
grantee_address?: string;
|
|
117
|
+
/** The share's expiry, at most the installation's max_expiry from now. Absent takes the kind's default_expiry, clamped to max_expiry. */
|
|
118
|
+
expires_at?: string;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The vocabulary of the share acts' refusal codes (sdk/shares.Codes).
|
|
122
|
+
*
|
|
123
|
+
* Every stable code a share act is refused with. A code is never renamed; a new refusal is a new code, so a reader keeps a code it does not know as it arrived. share_not_found answers a share the caller may not see exactly as an id no share has. share_grantee_not_admitted answers an address no person holds on a kind whose effective grantee class is not addresses; on one that is, the address is invited and the share is pending until the invitee signs in.
|
|
124
|
+
*
|
|
125
|
+
* Schema: sdk/shares/schema/v1/refusal-code.json
|
|
126
|
+
*/
|
|
127
|
+
export type SharesRefusalCode = "share_sharer_not_a_person" | "share_sharing_disabled" | "share_resource_not_shareable" | "share_resource_unknown" | "share_actor_other_installation" | "share_verb_not_shareable" | "share_verb_confers_sharing" | "share_verb_not_held" | "share_grantee_not_admitted" | "share_guest_cannot_invite" | "share_invitation_refused" | "share_grantee_is_sharer" | "share_expiry_beyond_max" | "share_cap_active" | "share_cap_pending_invitations" | "share_exists" | "share_caller_not_a_person" | "share_not_found" | "share_sharer_lost_access" | "share_expiry_not_later" | "share_admin_required" | "share_list_query" | "shares_unavailable";
|
|
128
|
+
/**
|
|
129
|
+
* A share act refused.
|
|
130
|
+
*
|
|
131
|
+
* A share act tera refused, as the shares client answers it: the route's stable code and its words, unchanged, and the detail the code declares.
|
|
132
|
+
*
|
|
133
|
+
* Schema: sdk/shares/schema/v1/refusal.json
|
|
134
|
+
*/
|
|
135
|
+
export type SharesRefusal = {
|
|
136
|
+
/** The route's stable code. A code a reader does not know is kept as it arrived. */
|
|
137
|
+
code: string;
|
|
138
|
+
/** The route's words for a person, unchanged. */
|
|
139
|
+
message: string;
|
|
140
|
+
/** On share_verb_not_held, share_verb_not_shareable and share_verb_confers_sharing, the verb refused. */
|
|
141
|
+
verb?: string;
|
|
142
|
+
/** On share_exists, the id of the share already there. */
|
|
143
|
+
existing?: string;
|
|
144
|
+
/** On share_invitation_refused, why the address was not invited (inviter_limited, email_unavailable, ...). */
|
|
145
|
+
invitation?: string;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* A share.
|
|
149
|
+
*
|
|
150
|
+
* One live share, with whether it decides now: the result of api.v1.shares.create, api.v1.shares.get and api.v1.shares.patch, and each member of a list (ADR-174 D14).
|
|
151
|
+
*
|
|
152
|
+
* Schema: sdk/shares/schema/v1/share.json
|
|
153
|
+
*/
|
|
154
|
+
export type SharesShare = {
|
|
155
|
+
/** The share's id, a UUIDv7. */
|
|
156
|
+
id: string;
|
|
157
|
+
/** The installation whose resource is shared, <vault>/plugins/<installation>. */
|
|
158
|
+
installation: string;
|
|
159
|
+
/** The resource shared, plugins/<vault>/<installation>/<kind>/<id>. */
|
|
160
|
+
resource: string;
|
|
161
|
+
/** The shared verbs. */
|
|
162
|
+
verbs: string[] | null;
|
|
163
|
+
/** What the grantee is: person. */
|
|
164
|
+
grantee_kind: string;
|
|
165
|
+
/** The grantee person's id. */
|
|
166
|
+
grantee: string;
|
|
167
|
+
/** The id of the person who made the share. */
|
|
168
|
+
sharer: string;
|
|
169
|
+
/** The plugin principal that made the share for its sharer; absent when the sharer made it directly. */
|
|
170
|
+
created_via?: string;
|
|
171
|
+
/** When the share was made. */
|
|
172
|
+
created_at: string;
|
|
173
|
+
/** When the share stops deciding. */
|
|
174
|
+
expires_at: string;
|
|
175
|
+
/** When the share was last extended; absent if never. */
|
|
176
|
+
extended_at?: string;
|
|
177
|
+
/** Whether the share decides at least one of its verbs on the grantee's next request, computed from what decides now. */
|
|
178
|
+
deciding: boolean;
|
|
179
|
+
/** When deciding is false, the one reason why. Absent while the share decides. */
|
|
180
|
+
not_deciding?: "sharer_lost_access" | "sharing_disabled" | "installation_not_standing" | "verb_no_longer_shareable" | "pending_invitation";
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Every type this module declares, mapped to the repository path of the schema
|
|
184
|
+
* it was generated from.
|
|
185
|
+
*/
|
|
186
|
+
export declare const SHARES_SCHEMAS: {
|
|
187
|
+
readonly SharesEnded: "sdk/shares/schema/v1/ended.json";
|
|
188
|
+
readonly SharesExtendRequest: "sdk/shares/schema/v1/extend.request.json";
|
|
189
|
+
readonly SharesIdRequest: "sdk/shares/schema/v1/id.request.json";
|
|
190
|
+
readonly SharesList: "sdk/shares/schema/v1/list.json";
|
|
191
|
+
readonly SharesListRequest: "sdk/shares/schema/v1/list.request.json";
|
|
192
|
+
readonly SharesMakeRequest: "sdk/shares/schema/v1/make.request.json";
|
|
193
|
+
readonly SharesRefusalCode: "sdk/shares/schema/v1/refusal-code.json";
|
|
194
|
+
readonly SharesRefusal: "sdk/shares/schema/v1/refusal.json";
|
|
195
|
+
readonly SharesShare: "sdk/shares/schema/v1/share.json";
|
|
196
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Code generated by cmd/internal/genwebtypes from sdk/shares/schema/v1/; DO NOT EDIT.
|
|
2
|
+
// Regenerate with `make web-types` (ADR-162 D4 item 1).
|
|
3
|
+
/**
|
|
4
|
+
* Every type this module declares, mapped to the repository path of the schema
|
|
5
|
+
* it was generated from.
|
|
6
|
+
*/
|
|
7
|
+
export const SHARES_SCHEMAS = {
|
|
8
|
+
SharesEnded: "sdk/shares/schema/v1/ended.json",
|
|
9
|
+
SharesExtendRequest: "sdk/shares/schema/v1/extend.request.json",
|
|
10
|
+
SharesIdRequest: "sdk/shares/schema/v1/id.request.json",
|
|
11
|
+
SharesList: "sdk/shares/schema/v1/list.json",
|
|
12
|
+
SharesListRequest: "sdk/shares/schema/v1/list.request.json",
|
|
13
|
+
SharesMakeRequest: "sdk/shares/schema/v1/make.request.json",
|
|
14
|
+
SharesRefusalCode: "sdk/shares/schema/v1/refusal-code.json",
|
|
15
|
+
SharesRefusal: "sdk/shares/schema/v1/refusal.json",
|
|
16
|
+
SharesShare: "sdk/shares/schema/v1/share.json",
|
|
17
|
+
};
|
|
@@ -48,6 +48,8 @@ export type WorkOrderAnswerParams = {
|
|
|
48
48
|
replace?: boolean;
|
|
49
49
|
/** Cross ONE refusal: a select site where this Work Order's live step binding is running a candidate the new pin no longer offers (ADR-130 D5, ratified crossable 2026-09-20). The binding row is RETAINED at the same chain generation and the resume RE-SELECTS from the new candidate set, running the candidate loop against live capacity exactly as a first admission would. It does NOT preserve the candidate the run is on — that candidate is gone, which is why the refusal exists. It lifts nothing else: a capability or operation switch at a fixed site has no candidate to re-select, and a withdrawn `yields_turn` offer is frozen for the life of a pinned conversation (ADR-129 D9). Over a site whose candidate IS still offered, or a fixed site, it is a no-op and says so in the manifest rather than refusing. Only meaningful with `repin`. Authorized against `api/v1/workorders/repin/reselect` IN ADDITION to `api/v1/workorders/repin`. Pass `dry_run` first: the manifest's `would_reselect` names the site, the candidate being given up and the set the resume will choose from. */
|
|
50
50
|
reselect?: boolean;
|
|
51
|
+
/** The id of the step-up a person confirmed this act with, when the Work Order's type requires one for it (ADR-173 D10): a review verdict, an answer, or an off-tera `complete` / `failed`. Call WITHOUT it first: the call is refused `step_up_required` and its error data names the step-up's `id` and the `url` the person opens to confirm it — show them that url; you cannot confirm it yourself. Then retry the IDENTICAL call with step_up = that id. `step_up_pending` means they have not confirmed yet: wait and retry the same call. A step-up confirms exactly one act with exactly this content, once. */
|
|
52
|
+
step_up?: string;
|
|
51
53
|
/** The operator's exact prose. Interactive answers become one durable ledger message; other answers are wrapped as {"answer": "<text>"}. Ignored when `payload` is supplied. */
|
|
52
54
|
text?: string;
|
|
53
55
|
};
|
|
@@ -965,6 +967,13 @@ export type WorkOrderGetResult = {
|
|
|
965
967
|
authorized_for?: string;
|
|
966
968
|
plugin?: string;
|
|
967
969
|
evidence_class?: string;
|
|
970
|
+
step_up?: {
|
|
971
|
+
id: string;
|
|
972
|
+
method: string;
|
|
973
|
+
anchor?: string;
|
|
974
|
+
at: string;
|
|
975
|
+
};
|
|
976
|
+
display_name?: string;
|
|
968
977
|
};
|
|
969
978
|
};
|
|
970
979
|
question?: {
|
|
@@ -1217,10 +1226,22 @@ export type WorkOrderGetResult = {
|
|
|
1217
1226
|
describe?: string;
|
|
1218
1227
|
caller_is_person?: boolean;
|
|
1219
1228
|
outcome_provenance?: string;
|
|
1229
|
+
step_up?: {
|
|
1230
|
+
id: string;
|
|
1231
|
+
method: string;
|
|
1232
|
+
anchor?: string;
|
|
1233
|
+
at: string;
|
|
1234
|
+
};
|
|
1220
1235
|
};
|
|
1221
1236
|
outcome?: {
|
|
1222
1237
|
outcome_provenance: string;
|
|
1223
1238
|
attested_by?: string;
|
|
1239
|
+
step_up?: {
|
|
1240
|
+
id: string;
|
|
1241
|
+
method: string;
|
|
1242
|
+
anchor?: string;
|
|
1243
|
+
at: string;
|
|
1244
|
+
};
|
|
1224
1245
|
};
|
|
1225
1246
|
relations: {
|
|
1226
1247
|
relation: string;
|
|
@@ -1383,6 +1404,9 @@ export type WorkOrderGetResult = {
|
|
|
1383
1404
|
} | null;
|
|
1384
1405
|
created_by?: string;
|
|
1385
1406
|
created_via?: string;
|
|
1407
|
+
arrival_evidence?: {
|
|
1408
|
+
[key: string]: string;
|
|
1409
|
+
};
|
|
1386
1410
|
created_at: string;
|
|
1387
1411
|
updated_at: string;
|
|
1388
1412
|
off_tera: boolean;
|
|
@@ -1785,6 +1809,12 @@ export type WorkOrderListResult = {
|
|
|
1785
1809
|
describe?: string;
|
|
1786
1810
|
caller_is_person?: boolean;
|
|
1787
1811
|
outcome_provenance?: string;
|
|
1812
|
+
step_up?: {
|
|
1813
|
+
id: string;
|
|
1814
|
+
method: string;
|
|
1815
|
+
anchor?: string;
|
|
1816
|
+
at: string;
|
|
1817
|
+
};
|
|
1788
1818
|
};
|
|
1789
1819
|
}[] | null;
|
|
1790
1820
|
};
|
|
@@ -1818,6 +1848,12 @@ export type WorkOrderListOffTeraResult = {
|
|
|
1818
1848
|
describe?: string;
|
|
1819
1849
|
caller_is_person?: boolean;
|
|
1820
1850
|
outcome_provenance?: string;
|
|
1851
|
+
step_up?: {
|
|
1852
|
+
id: string;
|
|
1853
|
+
method: string;
|
|
1854
|
+
anchor?: string;
|
|
1855
|
+
at: string;
|
|
1856
|
+
};
|
|
1821
1857
|
};
|
|
1822
1858
|
take_age_seconds?: number;
|
|
1823
1859
|
/** On a held entry: the JSON Schema this Work Order was pinned to at its first take, which submit_result grades the record against. Absent on posted and taken entries, and when the type declares none. */
|
|
@@ -1840,6 +1876,12 @@ export type WorkOrderListOffTeraResult = {
|
|
|
1840
1876
|
describe?: string;
|
|
1841
1877
|
caller_is_person?: boolean;
|
|
1842
1878
|
outcome_provenance?: string;
|
|
1879
|
+
step_up?: {
|
|
1880
|
+
id: string;
|
|
1881
|
+
method: string;
|
|
1882
|
+
anchor?: string;
|
|
1883
|
+
at: string;
|
|
1884
|
+
};
|
|
1843
1885
|
};
|
|
1844
1886
|
take_age_seconds?: number;
|
|
1845
1887
|
/** On a held entry: the JSON Schema this Work Order was pinned to at its first take, which submit_result grades the record against. Absent on posted and taken entries, and when the type declares none. */
|
|
@@ -1862,6 +1904,12 @@ export type WorkOrderListOffTeraResult = {
|
|
|
1862
1904
|
describe?: string;
|
|
1863
1905
|
caller_is_person?: boolean;
|
|
1864
1906
|
outcome_provenance?: string;
|
|
1907
|
+
step_up?: {
|
|
1908
|
+
id: string;
|
|
1909
|
+
method: string;
|
|
1910
|
+
anchor?: string;
|
|
1911
|
+
at: string;
|
|
1912
|
+
};
|
|
1865
1913
|
};
|
|
1866
1914
|
take_age_seconds?: number;
|
|
1867
1915
|
/** On a held entry: the JSON Schema this Work Order was pinned to at its first take, which submit_result grades the record against. Absent on posted and taken entries, and when the type declares none. */
|
|
@@ -1962,6 +2010,12 @@ export type WorkOrderProgressResult = {
|
|
|
1962
2010
|
describe?: string;
|
|
1963
2011
|
caller_is_person?: boolean;
|
|
1964
2012
|
outcome_provenance?: string;
|
|
2013
|
+
step_up?: {
|
|
2014
|
+
id: string;
|
|
2015
|
+
method: string;
|
|
2016
|
+
anchor?: string;
|
|
2017
|
+
at: string;
|
|
2018
|
+
};
|
|
1965
2019
|
} | null;
|
|
1966
2020
|
addressed_events: {
|
|
1967
2021
|
id: number;
|
|
@@ -2550,6 +2604,8 @@ export type WorkOrderSubmitResultParams = {
|
|
|
2550
2604
|
};
|
|
2551
2605
|
/** The id of the last event you have processed on this Work Order. The response carries the events addressed to you after it (a repost, a cancel, a wake, an answer, posted guidance), at most 32 with `more` set when there were more, plus `newest_event_id`. The server keeps no cursor: omit it, or pass 0, for everything addressed so far. */
|
|
2552
2606
|
seen_through?: number;
|
|
2607
|
+
/** The id of the step-up a person confirmed this act with, when the Work Order's type requires one for it (ADR-173 D10): a review verdict, an answer, or an off-tera `complete` / `failed`. Call WITHOUT it first: the call is refused `step_up_required` and its error data names the step-up's `id` and the `url` the person opens to confirm it — show them that url; you cannot confirm it yourself. Then retry the IDENTICAL call with step_up = that id. `step_up_pending` means they have not confirmed yet: wait and retry the same call. A step-up confirms exactly one act with exactly this content, once. */
|
|
2608
|
+
step_up?: string;
|
|
2553
2609
|
};
|
|
2554
2610
|
/**
|
|
2555
2611
|
* `work_order.submit_result` result (v1).
|
|
@@ -2565,6 +2621,12 @@ export type WorkOrderSubmitResultResult = {
|
|
|
2565
2621
|
outcome?: {
|
|
2566
2622
|
outcome_provenance: string;
|
|
2567
2623
|
attested_by?: string;
|
|
2624
|
+
step_up?: {
|
|
2625
|
+
id: string;
|
|
2626
|
+
method: string;
|
|
2627
|
+
anchor?: string;
|
|
2628
|
+
at: string;
|
|
2629
|
+
};
|
|
2568
2630
|
};
|
|
2569
2631
|
checks?: string;
|
|
2570
2632
|
addressed_events: {
|
|
@@ -2612,6 +2674,12 @@ export type WorkOrderTakeResult = {
|
|
|
2612
2674
|
describe?: string;
|
|
2613
2675
|
caller_is_person?: boolean;
|
|
2614
2676
|
outcome_provenance?: string;
|
|
2677
|
+
step_up?: {
|
|
2678
|
+
id: string;
|
|
2679
|
+
method: string;
|
|
2680
|
+
anchor?: string;
|
|
2681
|
+
at: string;
|
|
2682
|
+
};
|
|
2615
2683
|
} | null;
|
|
2616
2684
|
instructions: string;
|
|
2617
2685
|
requirements?: string;
|
|
@@ -2675,6 +2743,8 @@ export type WorkOrderTransitionParams = {
|
|
|
2675
2743
|
replace?: boolean;
|
|
2676
2744
|
/** Cross ONE refusal: a select site where this Work Order's live step binding is running a candidate the new pin no longer offers (ADR-130 D5, ratified crossable 2026-09-20). The binding row is RETAINED at the same chain generation and the resume RE-SELECTS from the new candidate set, running the candidate loop against live capacity exactly as a first admission would. It does NOT preserve the candidate the run is on — that candidate is gone, which is why the refusal exists. It lifts nothing else: a capability or operation switch at a fixed site has no candidate to re-select, and a withdrawn `yields_turn` offer is frozen for the life of a pinned conversation (ADR-129 D9). Over a site whose candidate IS still offered, or a fixed site, it is a no-op and says so in the manifest rather than refusing. Only meaningful with `repin`. Authorized against `api/v1/workorders/repin/reselect` IN ADDITION to `api/v1/workorders/repin`. Pass `dry_run` first: the manifest's `would_reselect` names the site, the candidate being given up and the set the resume will choose from. */
|
|
2677
2745
|
reselect?: boolean;
|
|
2746
|
+
/** The id of the step-up a person confirmed this act with, when the Work Order's type requires one for it (ADR-173 D10): a review verdict, an answer, or an off-tera `complete` / `failed`. Call WITHOUT it first: the call is refused `step_up_required` and its error data names the step-up's `id` and the `url` the person opens to confirm it — show them that url; you cannot confirm it yourself. Then retry the IDENTICAL call with step_up = that id. `step_up_pending` means they have not confirmed yet: wait and retry the same call. A step-up confirms exactly one act with exactly this content, once. */
|
|
2747
|
+
step_up?: string;
|
|
2678
2748
|
/** action=answer only: the operator's answer text. Read work_order.get(id).question first — that is what is being asked. */
|
|
2679
2749
|
text?: string;
|
|
2680
2750
|
};
|
|
@@ -3102,6 +3172,12 @@ export type WorkOrderTreeResult = {
|
|
|
3102
3172
|
outcome?: {
|
|
3103
3173
|
outcome_provenance: string;
|
|
3104
3174
|
attested_by?: string;
|
|
3175
|
+
step_up?: {
|
|
3176
|
+
id: string;
|
|
3177
|
+
method: string;
|
|
3178
|
+
anchor?: string;
|
|
3179
|
+
at: string;
|
|
3180
|
+
};
|
|
3105
3181
|
};
|
|
3106
3182
|
replaced?: {
|
|
3107
3183
|
relation: string;
|
|
@@ -3326,6 +3402,12 @@ export type WorkOrderTreeResult = {
|
|
|
3326
3402
|
outcome?: {
|
|
3327
3403
|
outcome_provenance: string;
|
|
3328
3404
|
attested_by?: string;
|
|
3405
|
+
step_up?: {
|
|
3406
|
+
id: string;
|
|
3407
|
+
method: string;
|
|
3408
|
+
anchor?: string;
|
|
3409
|
+
at: string;
|
|
3410
|
+
};
|
|
3329
3411
|
};
|
|
3330
3412
|
replaced?: {
|
|
3331
3413
|
relation: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
export { ROUTE_PREFIX, routePath } from "./routes.ts";
|
|
1
|
+
export { ROOT_BASE, ROUTE_PREFIX, appBase, routePath, underBase } from "./routes.ts";
|
|
2
|
+
export { phoneURL } from "./phone.ts";
|
|
2
3
|
export { TeraClient, KitRequestError, UNRECOGNIZED_RESPONSE, type FeedOptions, type InvokeVerdict, type KitErrorBody, type TeraClientOptions, type UploadOptions, type UploadProgress, type UploadRequest, type VerbRefusal, } from "./client.ts";
|
|
4
|
+
export { STEP_UP_HEADER, STEP_UP_POLL_MS, STEP_UP_REQUIRED, STEP_UP_RESUME_PARAM, StepUpError, resumedStepUp, stepUpChallengeOf, stepUpPageURL, type StepUpChallenge, type StepUpEnd, type StepUpOptions, type StepUpWindow, } from "./stepup.ts";
|
|
3
5
|
export { BASE_DELAY_MS, MAX_DELAY_MS, REPLAY_LIMIT, REPLAY_WINDOW_MS, HEARTBEAT_GRACE_MS, REAUTHENTICATE_EVENT, FeedConnection, browserSignals, defaultOrderKey, type Clock, type FeedConnectionOptions, type FeedConnectionPhase, type FeedConnectionState, type FeedFrame, type FeedLoss, type FeedSignal, type FeedSignals, } from "./feed/connection.ts";
|
|
4
6
|
export { FeedOpenError, SSEParser, fetchOpener, isRefusal, type FeedOpener, type SSEEvent } from "./feed/sse.ts";
|
|
5
7
|
export type * from "./generated/feed.ts";
|
|
6
8
|
export type * from "./generated/kit.ts";
|
|
9
|
+
export type * from "./generated/shares.ts";
|
|
7
10
|
export type * from "./generated/workorder.ts";
|
|
8
11
|
export type * from "./generated/workorder-events.ts";
|
|
9
12
|
export { FEED_SCHEMAS } from "./generated/feed.ts";
|
|
10
|
-
export { KIT_ROUTE_PREFIX, KIT_ROUTE_TABLE, KIT_SCHEMAS, KIT_SIGNOUT_PATH } from "./generated/kit.ts";
|
|
13
|
+
export { KIT_ROUTE_PREFIX, KIT_ROUTE_TABLE, KIT_PHONE_PATH, KIT_SCHEMAS, KIT_SIGNOUT_PATH } from "./generated/kit.ts";
|
|
14
|
+
export { SHARES_SCHEMAS } from "./generated/shares.ts";
|
|
11
15
|
export { WORK_ORDER_SCHEMAS } from "./generated/workorder.ts";
|
|
12
16
|
export { WORK_ORDER_EVENT_SCHEMAS } from "./generated/workorder-events.ts";
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Framework-free, with no runtime dependencies: it carries no UI component,
|
|
4
4
|
// because the framework is the author's.
|
|
5
|
-
export { ROUTE_PREFIX, routePath } from "./routes.js";
|
|
5
|
+
export { ROOT_BASE, ROUTE_PREFIX, appBase, routePath, underBase } from "./routes.js";
|
|
6
|
+
export { phoneURL } from "./phone.js";
|
|
6
7
|
export { TeraClient, KitRequestError, UNRECOGNIZED_RESPONSE, } from "./client.js";
|
|
8
|
+
export { STEP_UP_HEADER, STEP_UP_POLL_MS, STEP_UP_REQUIRED, STEP_UP_RESUME_PARAM, StepUpError, resumedStepUp, stepUpChallengeOf, stepUpPageURL, } from "./stepup.js";
|
|
7
9
|
export { BASE_DELAY_MS, MAX_DELAY_MS, REPLAY_LIMIT, REPLAY_WINDOW_MS, HEARTBEAT_GRACE_MS, REAUTHENTICATE_EVENT, FeedConnection, browserSignals, defaultOrderKey, } from "./feed/connection.js";
|
|
8
10
|
export { FeedOpenError, SSEParser, fetchOpener, isRefusal } from "./feed/sse.js";
|
|
9
11
|
export { FEED_SCHEMAS } from "./generated/feed.js";
|
|
10
|
-
export { KIT_ROUTE_PREFIX, KIT_ROUTE_TABLE, KIT_SCHEMAS, KIT_SIGNOUT_PATH } from "./generated/kit.js";
|
|
12
|
+
export { KIT_ROUTE_PREFIX, KIT_ROUTE_TABLE, KIT_PHONE_PATH, KIT_SCHEMAS, KIT_SIGNOUT_PATH } from "./generated/kit.js";
|
|
13
|
+
export { SHARES_SCHEMAS } from "./generated/shares.js";
|
|
11
14
|
export { WORK_ORDER_SCHEMAS } from "./generated/workorder.js";
|
|
12
15
|
export { WORK_ORDER_EVENT_SCHEMAS } from "./generated/workorder-events.js";
|
package/dist/phone.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { KitMeResponse } from "./generated/kit.ts";
|
|
2
|
+
/**
|
|
3
|
+
* phoneURL builds the "Open on your phone" link of the page at `location`:
|
|
4
|
+
* the `phone_path` `me` answers, resolved against the app's `base` (`/`, or
|
|
5
|
+
* `/plugins/<name>/` on a path-based installation, as
|
|
6
|
+
* `TeraClientOptions.base`), with `next` set to `location.href`, fragment
|
|
7
|
+
* included. It answers a root-absolute path on the page's own origin. A
|
|
8
|
+
* `phone_path` that is not a path relative to the base is refused rather
|
|
9
|
+
* than followed.
|
|
10
|
+
*/
|
|
11
|
+
export declare function phoneURL(me: Pick<KitMeResponse, "phone_path">, location: Pick<Location, "href">, base?: string): string;
|
package/dist/phone.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// "Open on your phone" (ADR-177 D4): a link to tera's phone page, which draws
|
|
2
|
+
// the page's URL as a QR code. A page builds it without knowing tera's URL:
|
|
3
|
+
// it links to its own proxy's phone path, under its app's base, and tera's
|
|
4
|
+
// proxy redirects to tera's phone page for a URL under this installation's
|
|
5
|
+
// own base and to the app's base for any other.
|
|
6
|
+
import { ROOT_BASE, isBaseRelative, underBase } from "./routes.js";
|
|
7
|
+
/** The query parameter naming the page the phone opens. */
|
|
8
|
+
const NEXT_PARAM = "next";
|
|
9
|
+
/**
|
|
10
|
+
* phoneURL builds the "Open on your phone" link of the page at `location`:
|
|
11
|
+
* the `phone_path` `me` answers, resolved against the app's `base` (`/`, or
|
|
12
|
+
* `/plugins/<name>/` on a path-based installation, as
|
|
13
|
+
* `TeraClientOptions.base`), with `next` set to `location.href`, fragment
|
|
14
|
+
* included. It answers a root-absolute path on the page's own origin. A
|
|
15
|
+
* `phone_path` that is not a path relative to the base is refused rather
|
|
16
|
+
* than followed.
|
|
17
|
+
*/
|
|
18
|
+
export function phoneURL(me, location, base = ROOT_BASE) {
|
|
19
|
+
const path = me.phone_path;
|
|
20
|
+
if (!isBaseRelative(path)) {
|
|
21
|
+
throw new TypeError(`phoneURL: phone_path is not a path relative to the app's base: ${JSON.stringify(path)}`);
|
|
22
|
+
}
|
|
23
|
+
return underBase(base, path) + "?" + new URLSearchParams({ [NEXT_PARAM]: location.href }).toString();
|
|
24
|
+
}
|
package/dist/routes.d.ts
CHANGED
|
@@ -8,3 +8,25 @@ export declare const ROUTE_PREFIX = "/tera/v1/";
|
|
|
8
8
|
* collapses the dot segments and encoding does not change them.
|
|
9
9
|
*/
|
|
10
10
|
export declare function routePath(...segments: string[]): string;
|
|
11
|
+
/** The base of an app served at the root of its origin. */
|
|
12
|
+
export declare const ROOT_BASE = "/";
|
|
13
|
+
/**
|
|
14
|
+
* appBase checks the path an app is served under on its origin and answers it
|
|
15
|
+
* ending in `/`: `/` on a plugin's own origin, `/plugins/<name>/` on a
|
|
16
|
+
* path-based installation. A base that is not a root-absolute path on the
|
|
17
|
+
* page's own origin is refused.
|
|
18
|
+
*/
|
|
19
|
+
export declare function appBase(base?: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* underBase places a path the kit names under an app's base: a kit path
|
|
22
|
+
* (`/tera/v1/me`, from {@link routePath}) or a path relative to the base
|
|
23
|
+
* (`_tera/signout`, the kit's `signout_path`) alike.
|
|
24
|
+
*/
|
|
25
|
+
export declare function underBase(base: string, path: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* isBaseRelative reports whether a path the kit answers (`signout_path`,
|
|
28
|
+
* `phone_path`) is relative to the app's base: not empty, not root-absolute,
|
|
29
|
+
* naming no scheme and holding no backslash, so that {@link underBase} keeps
|
|
30
|
+
* it on the page's own origin under its base.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isBaseRelative(path: unknown): path is string;
|
package/dist/routes.js
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
// The route table itself is declared once, in Go, under sdk/plugin/webui, and
|
|
6
6
|
// generated into ./generated/kit.ts. What is here is how a path is built from
|
|
7
7
|
// it.
|
|
8
|
+
//
|
|
9
|
+
// The table's paths are the kit's own: tera's proxy serves a plugin either at
|
|
10
|
+
// the root of its own origin or, on a path-based installation, under
|
|
11
|
+
// `/plugins/<name>/` on tera's origin, and strips that prefix before the kit
|
|
12
|
+
// sees a request. A page therefore reaches every route, and tera's sign-out,
|
|
13
|
+
// under its app's base (`/` or `/plugins/<name>/`), which only the page knows.
|
|
8
14
|
import { KIT_ROUTE_PREFIX } from "./generated/kit.js";
|
|
9
15
|
/** The prefix every kit route is served under. */
|
|
10
16
|
export const ROUTE_PREFIX = KIT_ROUTE_PREFIX;
|
|
@@ -30,3 +36,34 @@ export function routePath(...segments) {
|
|
|
30
36
|
});
|
|
31
37
|
return ROUTE_PREFIX + parts.join("/");
|
|
32
38
|
}
|
|
39
|
+
/** The base of an app served at the root of its origin. */
|
|
40
|
+
export const ROOT_BASE = "/";
|
|
41
|
+
/**
|
|
42
|
+
* appBase checks the path an app is served under on its origin and answers it
|
|
43
|
+
* ending in `/`: `/` on a plugin's own origin, `/plugins/<name>/` on a
|
|
44
|
+
* path-based installation. A base that is not a root-absolute path on the
|
|
45
|
+
* page's own origin is refused.
|
|
46
|
+
*/
|
|
47
|
+
export function appBase(base = ROOT_BASE) {
|
|
48
|
+
if (!base.startsWith("/") || base.startsWith("//") || /[?#\\]/.test(base)) {
|
|
49
|
+
throw new TypeError(`appBase: ${JSON.stringify(base)} is not a root-absolute path on this origin`);
|
|
50
|
+
}
|
|
51
|
+
return base.endsWith("/") ? base : base + "/";
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* underBase places a path the kit names under an app's base: a kit path
|
|
55
|
+
* (`/tera/v1/me`, from {@link routePath}) or a path relative to the base
|
|
56
|
+
* (`_tera/signout`, the kit's `signout_path`) alike.
|
|
57
|
+
*/
|
|
58
|
+
export function underBase(base, path) {
|
|
59
|
+
return appBase(base) + (path.startsWith("/") ? path.slice(1) : path);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* isBaseRelative reports whether a path the kit answers (`signout_path`,
|
|
63
|
+
* `phone_path`) is relative to the app's base: not empty, not root-absolute,
|
|
64
|
+
* naming no scheme and holding no backslash, so that {@link underBase} keeps
|
|
65
|
+
* it on the page's own origin under its base.
|
|
66
|
+
*/
|
|
67
|
+
export function isBaseRelative(path) {
|
|
68
|
+
return typeof path === "string" && path !== "" && !path.startsWith("/") && !/^[^/?#]*:/.test(path) && !path.includes("\\");
|
|
69
|
+
}
|