@phis/contracts 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -5
- package/dist/addon-index.d.ts +1 -0
- package/dist/addon-index.js +1 -0
- package/dist/addon.d.ts +50 -1
- package/dist/capabilities.d.ts +81 -13
- package/dist/cms.d.ts +23 -1
- package/dist/cms.js +32 -1
- package/dist/controls.d.ts +8 -0
- package/dist/controls.js +1 -0
- package/dist/core.d.ts +19 -1
- package/dist/core.js +19 -0
- package/dist/payments.d.ts +385 -0
- package/dist/payments.js +12 -0
- package/dist/references.d.ts +13 -4
- package/dist/references.js +33 -0
- package/dist/resource-links.d.ts +13 -7
- package/dist/schema.d.ts +9 -0
- package/dist/support.d.ts +184 -0
- package/dist/support.js +11 -0
- package/dist/threads.d.ts +29 -0
- package/dist/timeline.d.ts +39 -0
- package/dist/timeline.js +53 -0
- package/package.json +11 -1
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approved v1 Payment agreement. Core owns execution; consumers own prices and commerce.
|
|
3
|
+
*
|
|
4
|
+
* Execution belongs to Core; its implemented capability, service and event identities live in core.ts.
|
|
5
|
+
* These declarations contain no SDK, credentials, persistence or exchange-rate conversion. See phis-server's
|
|
6
|
+
* PAYMENTS.md and PAYMENTS_STRIPE.md for authority, durability and Provider mapping requirements.
|
|
7
|
+
*
|
|
8
|
+
* `amount` is always the consumer's base amount. Under a pricing policy other than `final`/`none` the
|
|
9
|
+
* Provider adds tax, shipping and discounts on top of it and reports the customer's total with its parts
|
|
10
|
+
* (PAYMENTS.md section 12); authorized, captured and refunded funds are measured against that total.
|
|
11
|
+
*/
|
|
12
|
+
export type PhisPaymentId = string;
|
|
13
|
+
export type PhisPaymentOperationId = string;
|
|
14
|
+
export type PhisPaymentRefundId = string;
|
|
15
|
+
export type PhisPaymentMoney = {
|
|
16
|
+
/** Uppercase ISO currency code; one agreed currency for the whole payment. */
|
|
17
|
+
currency: string;
|
|
18
|
+
/** Canonical non-negative integer string of minor units, never floating-point money. */
|
|
19
|
+
minor: string;
|
|
20
|
+
};
|
|
21
|
+
export type PhisPaymentCaptureMode = "automatic" | "manual";
|
|
22
|
+
export type PhisPaymentCheckoutKind = "redirect" | "provider-ui";
|
|
23
|
+
export type PhisPaymentFeatures = {
|
|
24
|
+
captureModes: readonly PhisPaymentCaptureMode[];
|
|
25
|
+
checkoutKinds: readonly PhisPaymentCheckoutKind[];
|
|
26
|
+
canPartialCapture: boolean;
|
|
27
|
+
canCancel: boolean;
|
|
28
|
+
canRefund: boolean;
|
|
29
|
+
canPartialRefund: boolean;
|
|
30
|
+
pricing: PhisPaymentPricingFeatures;
|
|
31
|
+
};
|
|
32
|
+
export type PhisPaymentMethod = {
|
|
33
|
+
profileKey: string;
|
|
34
|
+
methodKey: string | null;
|
|
35
|
+
title: string;
|
|
36
|
+
features: PhisPaymentFeatures;
|
|
37
|
+
};
|
|
38
|
+
export type PhisPaymentCheckoutPlan = {
|
|
39
|
+
kind: "redirect";
|
|
40
|
+
url: string;
|
|
41
|
+
expiresAt: string | null;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "provider-ui";
|
|
44
|
+
moduleId: string;
|
|
45
|
+
adapterKey: string;
|
|
46
|
+
parameters: Readonly<Record<string, string>>;
|
|
47
|
+
expiresAt: string | null;
|
|
48
|
+
};
|
|
49
|
+
export type PhisPaymentStatus = "created" | "awaiting_customer" | "processing" | "authorized" | "captured" | "canceled" | "expired" | "failed";
|
|
50
|
+
export type PhisPayment = {
|
|
51
|
+
id: PhisPaymentId;
|
|
52
|
+
reference: string;
|
|
53
|
+
profileKey: string;
|
|
54
|
+
mode: "test" | "live";
|
|
55
|
+
/** The consumer's base amount; the customer pays `totals.total` once the Provider reports it. */
|
|
56
|
+
amount: PhisPaymentMoney;
|
|
57
|
+
pricing: PhisPaymentPricing;
|
|
58
|
+
totals: PhisPaymentTotals | null;
|
|
59
|
+
captureMode: PhisPaymentCaptureMode;
|
|
60
|
+
status: PhisPaymentStatus;
|
|
61
|
+
authorizedMinor: string;
|
|
62
|
+
capturedMinor: string;
|
|
63
|
+
refundedMinor: string;
|
|
64
|
+
authorizationExpiresAt: string | null;
|
|
65
|
+
checkout: PhisPaymentCheckoutPlan | null;
|
|
66
|
+
reconciliationRequired: boolean;
|
|
67
|
+
version: number;
|
|
68
|
+
lastObservedAt: string | null;
|
|
69
|
+
};
|
|
70
|
+
export type PhisPaymentErrorCode = "invalid_input" | "not_found" | "forbidden" | "profile_unavailable" | "method_unavailable" | "unsupported_operation" | "invalid_state" | "active_attempt_exists" | "idempotency_conflict" | "payment_declined" | "provider_rejected" | "provider_unavailable" | "reconciliation_required";
|
|
71
|
+
export type PhisPaymentOperation = {
|
|
72
|
+
id: PhisPaymentOperationId;
|
|
73
|
+
paymentId: PhisPaymentId;
|
|
74
|
+
action: "create" | "complete" | "capture" | "cancel" | "refund";
|
|
75
|
+
state: "reserved" | "pending" | "succeeded" | "failed" | "indeterminate";
|
|
76
|
+
errorCode: PhisPaymentErrorCode | null;
|
|
77
|
+
};
|
|
78
|
+
export type PhisPaymentRefund = {
|
|
79
|
+
id: PhisPaymentRefundId;
|
|
80
|
+
paymentId: PhisPaymentId;
|
|
81
|
+
amount: PhisPaymentMoney;
|
|
82
|
+
/** The tax or discount share of this refund when the Provider reports one; informational. */
|
|
83
|
+
additions: readonly PhisPaymentAddition[] | null;
|
|
84
|
+
status: "pending" | "succeeded" | "failed" | "canceled";
|
|
85
|
+
};
|
|
86
|
+
export type PhisPaymentCommandResult = {
|
|
87
|
+
operation: PhisPaymentOperation;
|
|
88
|
+
payment: PhisPayment;
|
|
89
|
+
refund: PhisPaymentRefund | null;
|
|
90
|
+
};
|
|
91
|
+
export type PhisPaymentCreateInput = {
|
|
92
|
+
profileKey: string;
|
|
93
|
+
reference: string;
|
|
94
|
+
idempotencyKey: string;
|
|
95
|
+
amount: PhisPaymentMoney;
|
|
96
|
+
pricing: PhisPaymentPricing;
|
|
97
|
+
description: string;
|
|
98
|
+
captureMode: PhisPaymentCaptureMode;
|
|
99
|
+
methodKey: string | null;
|
|
100
|
+
checkoutKind: PhisPaymentCheckoutKind;
|
|
101
|
+
returnPath: string;
|
|
102
|
+
};
|
|
103
|
+
export type PhisPaymentCommandInput = {
|
|
104
|
+
paymentId: PhisPaymentId;
|
|
105
|
+
idempotencyKey: string;
|
|
106
|
+
};
|
|
107
|
+
export interface PhisPaymentsCapabilityV1 {
|
|
108
|
+
listMethods(input: {
|
|
109
|
+
profileKey: string;
|
|
110
|
+
amount: PhisPaymentMoney;
|
|
111
|
+
captureMode: PhisPaymentCaptureMode;
|
|
112
|
+
checkoutKind: PhisPaymentCheckoutKind;
|
|
113
|
+
pricing: PhisPaymentPricingSelector;
|
|
114
|
+
}): Promise<readonly PhisPaymentMethod[]>;
|
|
115
|
+
/** Core binds Site/consumer/profile; the consumer checks access to its business resource. */
|
|
116
|
+
create(input: PhisPaymentCreateInput): Promise<PhisPaymentCommandResult>;
|
|
117
|
+
get(paymentId: PhisPaymentId): Promise<PhisPayment | null>;
|
|
118
|
+
getOperation(operationId: PhisPaymentOperationId): Promise<PhisPaymentOperation | null>;
|
|
119
|
+
getRefund(refundId: PhisPaymentRefundId): Promise<PhisPaymentRefund | null>;
|
|
120
|
+
/** Customer continuation; never captures a manually authorized payment. */
|
|
121
|
+
complete(input: PhisPaymentCommandInput): Promise<PhisPaymentCommandResult>;
|
|
122
|
+
/** Explicit bounded reconciliation that may update state and enqueue a consumer event. */
|
|
123
|
+
refresh(paymentId: PhisPaymentId): Promise<PhisPayment | null>;
|
|
124
|
+
/** One final merchant-authorized capture; minor units inherit the stored currency. */
|
|
125
|
+
capture(input: PhisPaymentCommandInput & {
|
|
126
|
+
minor: string;
|
|
127
|
+
}): Promise<PhisPaymentCommandResult>;
|
|
128
|
+
cancel(input: PhisPaymentCommandInput): Promise<PhisPaymentCommandResult>;
|
|
129
|
+
/** Merchant-authorized refund; pending/unknown amounts reserve the captured balance. */
|
|
130
|
+
refund(input: PhisPaymentCommandInput & {
|
|
131
|
+
minor: string;
|
|
132
|
+
reason: string;
|
|
133
|
+
}): Promise<PhisPaymentCommandResult>;
|
|
134
|
+
}
|
|
135
|
+
export type PhisPaymentProviderConfigV1 = {
|
|
136
|
+
profileKey: string;
|
|
137
|
+
mode: "test" | "live";
|
|
138
|
+
merchantIdentity: string | null;
|
|
139
|
+
};
|
|
140
|
+
export type PhisPaymentProviderContextV1 = {
|
|
141
|
+
providerKey: string;
|
|
142
|
+
readCredentials(): Promise<Readonly<Record<string, string>> | null>;
|
|
143
|
+
};
|
|
144
|
+
export type PhisPaymentProviderBinding = {
|
|
145
|
+
reference: string;
|
|
146
|
+
data: Readonly<Record<string, string>>;
|
|
147
|
+
};
|
|
148
|
+
export type PhisPaymentProviderProbe = {
|
|
149
|
+
merchantIdentity: string;
|
|
150
|
+
mode: "test" | "live";
|
|
151
|
+
methods: readonly Omit<PhisPaymentMethod, "profileKey">[];
|
|
152
|
+
};
|
|
153
|
+
export type PhisPaymentProviderObservation = {
|
|
154
|
+
binding: PhisPaymentProviderBinding;
|
|
155
|
+
merchantIdentity: string;
|
|
156
|
+
mode: "test" | "live";
|
|
157
|
+
status: PhisPaymentStatus;
|
|
158
|
+
/** The base amount as created; a Provider never changes it. */
|
|
159
|
+
amount: PhisPaymentMoney;
|
|
160
|
+
/** Null only while the Provider cannot yet know the total; required from `authorized` on. */
|
|
161
|
+
totals: PhisPaymentObservedTotals | null;
|
|
162
|
+
authorizedMinor: string;
|
|
163
|
+
capturedMinor: string;
|
|
164
|
+
authorizationExpiresAt: string | null;
|
|
165
|
+
checkout: PhisPaymentCheckoutPlan | null;
|
|
166
|
+
/** Complete refund observations, including remote refunds created outside Core. */
|
|
167
|
+
refunds: readonly {
|
|
168
|
+
operationId: PhisPaymentOperationId | null;
|
|
169
|
+
binding: PhisPaymentProviderBinding;
|
|
170
|
+
minor: string;
|
|
171
|
+
status: PhisPaymentRefund["status"];
|
|
172
|
+
additions: readonly PhisPaymentAddition[] | null;
|
|
173
|
+
}[];
|
|
174
|
+
};
|
|
175
|
+
export type PhisPaymentProviderCommand = {
|
|
176
|
+
operationId: PhisPaymentOperationId;
|
|
177
|
+
paymentId: PhisPaymentId;
|
|
178
|
+
providerIdempotencyKey: string;
|
|
179
|
+
signal: AbortSignal;
|
|
180
|
+
} & ({
|
|
181
|
+
action: "create";
|
|
182
|
+
amount: PhisPaymentMoney;
|
|
183
|
+
pricing: PhisPaymentPricing;
|
|
184
|
+
description: string;
|
|
185
|
+
captureMode: PhisPaymentCaptureMode;
|
|
186
|
+
methodKey: string | null;
|
|
187
|
+
checkoutKind: PhisPaymentCheckoutKind;
|
|
188
|
+
returnUrl: string;
|
|
189
|
+
notificationUrl: string;
|
|
190
|
+
} | {
|
|
191
|
+
action: "complete" | "cancel";
|
|
192
|
+
binding: PhisPaymentProviderBinding;
|
|
193
|
+
} | {
|
|
194
|
+
action: "capture";
|
|
195
|
+
binding: PhisPaymentProviderBinding;
|
|
196
|
+
minor: string;
|
|
197
|
+
} | {
|
|
198
|
+
action: "refund";
|
|
199
|
+
binding: PhisPaymentProviderBinding;
|
|
200
|
+
minor: string;
|
|
201
|
+
reason: string;
|
|
202
|
+
});
|
|
203
|
+
export type PhisPaymentProviderExecution = {
|
|
204
|
+
outcome: "applied" | "pending";
|
|
205
|
+
observation: PhisPaymentProviderObservation;
|
|
206
|
+
} | {
|
|
207
|
+
outcome: "rejected";
|
|
208
|
+
code: PhisPaymentErrorCode;
|
|
209
|
+
} | {
|
|
210
|
+
outcome: "unknown";
|
|
211
|
+
};
|
|
212
|
+
export type PhisPaymentProviderNotification = {
|
|
213
|
+
outcome: "verified";
|
|
214
|
+
deliveryId: string;
|
|
215
|
+
reference: string;
|
|
216
|
+
} | {
|
|
217
|
+
outcome: "lookup-required";
|
|
218
|
+
reference: string;
|
|
219
|
+
} | {
|
|
220
|
+
outcome: "irrelevant";
|
|
221
|
+
} | {
|
|
222
|
+
outcome: "rejected";
|
|
223
|
+
} | {
|
|
224
|
+
outcome: "unavailable";
|
|
225
|
+
};
|
|
226
|
+
export interface PhisPaymentProviderV1 {
|
|
227
|
+
probe(input: {
|
|
228
|
+
amount: PhisPaymentMoney;
|
|
229
|
+
captureMode: PhisPaymentCaptureMode;
|
|
230
|
+
checkoutKind: PhisPaymentCheckoutKind;
|
|
231
|
+
pricing: PhisPaymentPricingSelector;
|
|
232
|
+
signal: AbortSignal;
|
|
233
|
+
}): Promise<PhisPaymentProviderProbe>;
|
|
234
|
+
execute(input: PhisPaymentProviderCommand): Promise<PhisPaymentProviderExecution>;
|
|
235
|
+
observe(input: {
|
|
236
|
+
binding: PhisPaymentProviderBinding;
|
|
237
|
+
signal: AbortSignal;
|
|
238
|
+
}): Promise<PhisPaymentProviderObservation>;
|
|
239
|
+
/** Recover the same command; never replace its key, merchant, mode or Provider. */
|
|
240
|
+
recover(input: {
|
|
241
|
+
command: PhisPaymentProviderCommand;
|
|
242
|
+
binding: PhisPaymentProviderBinding | null;
|
|
243
|
+
}): Promise<PhisPaymentProviderExecution>;
|
|
244
|
+
verifyNotification(input: {
|
|
245
|
+
method: string;
|
|
246
|
+
headers: Readonly<Record<string, string>>;
|
|
247
|
+
body: Uint8Array;
|
|
248
|
+
signal: AbortSignal;
|
|
249
|
+
}): Promise<PhisPaymentProviderNotification>;
|
|
250
|
+
}
|
|
251
|
+
export interface PhisPaymentNotificationsCapabilityV1 {
|
|
252
|
+
receive(input: {
|
|
253
|
+
profileKey: string;
|
|
254
|
+
}): Promise<{
|
|
255
|
+
outcome: "processed" | "duplicate" | "ignored";
|
|
256
|
+
}>;
|
|
257
|
+
}
|
|
258
|
+
export type PhisPaymentGrantedOperation = "read" | "create" | "complete" | "refresh" | "capture" | "cancel" | "refund";
|
|
259
|
+
export type PhisPaymentMerchantActionPolicy = {
|
|
260
|
+
roles: readonly string[];
|
|
261
|
+
jobs: readonly string[];
|
|
262
|
+
events: readonly string[];
|
|
263
|
+
};
|
|
264
|
+
export type PhisPaymentProfileGrant = {
|
|
265
|
+
consumerAddonId: string;
|
|
266
|
+
operations: readonly PhisPaymentGrantedOperation[];
|
|
267
|
+
merchantActions: {
|
|
268
|
+
capture: PhisPaymentMerchantActionPolicy;
|
|
269
|
+
cancel: PhisPaymentMerchantActionPolicy;
|
|
270
|
+
refund: PhisPaymentMerchantActionPolicy;
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
/** Operator-controlled references and grants; contains no credential values. */
|
|
274
|
+
export type PhisPaymentProfileDraft = {
|
|
275
|
+
key: string;
|
|
276
|
+
providerKey: string;
|
|
277
|
+
mode: "test" | "live";
|
|
278
|
+
credentialReferences: Readonly<Record<string, string>>;
|
|
279
|
+
grants: readonly PhisPaymentProfileGrant[];
|
|
280
|
+
};
|
|
281
|
+
/** A payment event reaches only the consuming Add-on stored on that payment. */
|
|
282
|
+
export type PhisPaymentChangedEventFacts = {
|
|
283
|
+
event: "payment.changed";
|
|
284
|
+
subject: {
|
|
285
|
+
kind: "payment";
|
|
286
|
+
paymentId: PhisPaymentId;
|
|
287
|
+
reference: string;
|
|
288
|
+
version: number;
|
|
289
|
+
operationId: PhisPaymentOperationId | null;
|
|
290
|
+
refundId: PhisPaymentRefundId | null;
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
export type PhisPaymentPricingBasis = "final" | "net";
|
|
294
|
+
export type PhisPaymentTaxHandling = "none" | "provider" | "merchant-of-record";
|
|
295
|
+
export type PhisPaymentPromotionCodes = "none" | "provider";
|
|
296
|
+
/** What is sold, never a rate; each Provider maps the closed vocabulary to its own codes. */
|
|
297
|
+
export type PhisPaymentTaxCategory = "general" | "reduced-goods" | "digital-goods" | "digital-service" | "service" | "shipping" | "exempt";
|
|
298
|
+
export type PhisPaymentLineItem = {
|
|
299
|
+
reference: string;
|
|
300
|
+
description: string;
|
|
301
|
+
quantity: number;
|
|
302
|
+
unitMinor: string;
|
|
303
|
+
taxCategory: PhisPaymentTaxCategory;
|
|
304
|
+
/** Provider-specific code overriding the category mapping, keyed by provider key. */
|
|
305
|
+
providerTaxCodes: Readonly<Record<string, string>> | null;
|
|
306
|
+
};
|
|
307
|
+
/** A reduction the consumer decided; the Provider shows it and taxes the reduced amount. */
|
|
308
|
+
export type PhisPaymentDiscount = {
|
|
309
|
+
reference: string;
|
|
310
|
+
label: string;
|
|
311
|
+
minor: string;
|
|
312
|
+
};
|
|
313
|
+
export type PhisPaymentCustomerDetails = {
|
|
314
|
+
country: string;
|
|
315
|
+
postalCode: string | null;
|
|
316
|
+
region: string | null;
|
|
317
|
+
addressSource: "billing" | "shipping";
|
|
318
|
+
taxIds: readonly {
|
|
319
|
+
type: string;
|
|
320
|
+
value: string;
|
|
321
|
+
}[];
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* `final`/`none` is v1: the base amount is what the customer pays and the Provider adds nothing. Every
|
|
325
|
+
* other policy carries line items; the base amount then equals their sum plus shipping minus discounts.
|
|
326
|
+
*/
|
|
327
|
+
export type PhisPaymentPricing = {
|
|
328
|
+
basis: "final";
|
|
329
|
+
tax: "none";
|
|
330
|
+
} | {
|
|
331
|
+
basis: PhisPaymentPricingBasis;
|
|
332
|
+
tax: PhisPaymentTaxHandling;
|
|
333
|
+
lineItems: readonly PhisPaymentLineItem[];
|
|
334
|
+
shipping: {
|
|
335
|
+
minor: string;
|
|
336
|
+
taxCategory: "shipping";
|
|
337
|
+
} | null;
|
|
338
|
+
discounts: readonly PhisPaymentDiscount[];
|
|
339
|
+
promotionCodes: PhisPaymentPromotionCodes;
|
|
340
|
+
customer: PhisPaymentCustomerDetails | null;
|
|
341
|
+
};
|
|
342
|
+
/** The facts of a policy a method must support; `discounts` is the number of stated discounts. */
|
|
343
|
+
export type PhisPaymentPricingSelector = {
|
|
344
|
+
basis: PhisPaymentPricingBasis;
|
|
345
|
+
tax: PhisPaymentTaxHandling;
|
|
346
|
+
discounts: number;
|
|
347
|
+
promotionCodes: PhisPaymentPromotionCodes;
|
|
348
|
+
};
|
|
349
|
+
export type PhisPaymentPricingFeatures = {
|
|
350
|
+
/** Always includes `final`. */
|
|
351
|
+
bases: readonly PhisPaymentPricingBasis[];
|
|
352
|
+
/** Always includes `none`. */
|
|
353
|
+
tax: readonly PhisPaymentTaxHandling[];
|
|
354
|
+
/** How many stated discounts one payment may carry; 0 when the Provider shows none. */
|
|
355
|
+
maxDiscounts: number;
|
|
356
|
+
/** Whether a customer may enter a code on the Provider's page, and whether next to stated discounts. */
|
|
357
|
+
promotionCodes: "none" | "alone" | "with-discounts";
|
|
358
|
+
collectsCustomerDetails: boolean;
|
|
359
|
+
collectsTaxIds: boolean;
|
|
360
|
+
};
|
|
361
|
+
export type PhisPaymentAdditionKind = "tax" | "shipping" | "discount";
|
|
362
|
+
export type PhisPaymentAddition = {
|
|
363
|
+
kind: PhisPaymentAdditionKind;
|
|
364
|
+
minor: string;
|
|
365
|
+
label: string;
|
|
366
|
+
/** Contained in the base amount rather than added to it; a `discount` is never inclusive. */
|
|
367
|
+
inclusive: boolean;
|
|
368
|
+
/** Display-only decimal string such as "8.1"; never enters Core arithmetic. */
|
|
369
|
+
rate: string | null;
|
|
370
|
+
/** ISO country code, optionally followed by "-" and a region. */
|
|
371
|
+
jurisdiction: string | null;
|
|
372
|
+
/** Who owes a tax addition to the authority: the merchant, or the Provider as Merchant of Record. */
|
|
373
|
+
collectedBy: "merchant" | "provider";
|
|
374
|
+
/** The promotion code or stated discount reference behind a `discount`; null for every other kind. */
|
|
375
|
+
code: string | null;
|
|
376
|
+
};
|
|
377
|
+
export type PhisPaymentObservedTotals = {
|
|
378
|
+
total: PhisPaymentMoney;
|
|
379
|
+
additions: readonly PhisPaymentAddition[];
|
|
380
|
+
customer: PhisPaymentCustomerDetails | null;
|
|
381
|
+
};
|
|
382
|
+
export type PhisPaymentTotals = PhisPaymentObservedTotals & {
|
|
383
|
+
/** Set by Core when the total became binding; a differing total afterwards is an inconsistency. */
|
|
384
|
+
frozenAt: string | null;
|
|
385
|
+
};
|
package/dist/payments.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approved v1 Payment agreement. Core owns execution; consumers own prices and commerce.
|
|
3
|
+
*
|
|
4
|
+
* Execution belongs to Core; its implemented capability, service and event identities live in core.ts.
|
|
5
|
+
* These declarations contain no SDK, credentials, persistence or exchange-rate conversion. See phis-server's
|
|
6
|
+
* PAYMENTS.md and PAYMENTS_STRIPE.md for authority, durability and Provider mapping requirements.
|
|
7
|
+
*
|
|
8
|
+
* `amount` is always the consumer's base amount. Under a pricing policy other than `final`/`none` the
|
|
9
|
+
* Provider adds tax, shipping and discounts on top of it and reports the customer's total with its parts
|
|
10
|
+
* (PAYMENTS.md section 12); authorized, captured and refunded funds are measured against that total.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
package/dist/references.d.ts
CHANGED
|
@@ -98,6 +98,15 @@ export type PhiLinkTarget = {
|
|
|
98
98
|
* goes. Whether the reader may follow it is still the target Area's own answer.
|
|
99
99
|
*/
|
|
100
100
|
area?: PhiCmsAreaKey;
|
|
101
|
+
/**
|
|
102
|
+
* The values of the Page's route parameters, where its route has any (`/news/:slug`).
|
|
103
|
+
*
|
|
104
|
+
* A reference names the route and not one address of it, so a link to one entry of a family of
|
|
105
|
+
* Pages states which: `{ slug: "launch" }`. The resolver answers the route's pattern, and the link
|
|
106
|
+
* fills it from here and from what its caller adds -- a list that links each of its entries states
|
|
107
|
+
* the route once and the value per entry. A parameter nobody fills leaves no link at all.
|
|
108
|
+
*/
|
|
109
|
+
params?: Readonly<Record<string, string>>;
|
|
101
110
|
fragment?: string | null;
|
|
102
111
|
newTab?: boolean;
|
|
103
112
|
} | {
|
|
@@ -121,10 +130,10 @@ export declare const PHI_LINK_TARGET_CONFIG_KEY = "linkTarget";
|
|
|
121
130
|
export declare function isPhiLinkTargetConfigKey(key: string): boolean;
|
|
122
131
|
export declare function isPhiStorableExternalHref(value: string): boolean;
|
|
123
132
|
/**
|
|
124
|
-
* A
|
|
133
|
+
* A route pattern with its parameters filled, or `null` while one is still open.
|
|
125
134
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* non-interactive text beats a link that goes somewhere nobody chose.
|
|
135
|
+
* Each value is one path segment, encoded as one: a slug with a slash in it cannot step into another
|
|
136
|
+
* route. A pattern without parameters comes back as it is.
|
|
129
137
|
*/
|
|
138
|
+
export declare function fillPhiRouteParams(pattern: string, params: Readonly<Record<string, string>> | null | undefined): string | null;
|
|
130
139
|
export declare function readPhiLinkTarget(value: unknown): PhiLinkTarget | null;
|
package/dist/references.js
CHANGED
|
@@ -174,6 +174,37 @@ export function isPhiStorableExternalHref(value) {
|
|
|
174
174
|
* link at all. That is the same answer the contract gives for a Page reference that no longer resolves:
|
|
175
175
|
* non-interactive text beats a link that goes somewhere nobody chose.
|
|
176
176
|
*/
|
|
177
|
+
const PHI_ROUTE_PARAM_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/u;
|
|
178
|
+
/** Route parameter values as a target stores them: names a route can declare, non-empty string values. */
|
|
179
|
+
function readPhiRouteParams(value) {
|
|
180
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const entries = Object.entries(value).flatMap(([name, entry]) => PHI_ROUTE_PARAM_NAME_PATTERN.test(name) && typeof entry === "string" && entry.trim()
|
|
184
|
+
? [[name, entry.trim()]]
|
|
185
|
+
: []);
|
|
186
|
+
return entries.length > 0 ? Object.fromEntries(entries) : null;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* A route pattern with its parameters filled, or `null` while one is still open.
|
|
190
|
+
*
|
|
191
|
+
* Each value is one path segment, encoded as one: a slug with a slash in it cannot step into another
|
|
192
|
+
* route. A pattern without parameters comes back as it is.
|
|
193
|
+
*/
|
|
194
|
+
export function fillPhiRouteParams(pattern, params) {
|
|
195
|
+
let open = false;
|
|
196
|
+
const filled = pattern.split("/").map((segment) => {
|
|
197
|
+
if (!segment.startsWith(":"))
|
|
198
|
+
return segment;
|
|
199
|
+
const value = params?.[segment.slice(1)];
|
|
200
|
+
if (!value) {
|
|
201
|
+
open = true;
|
|
202
|
+
return segment;
|
|
203
|
+
}
|
|
204
|
+
return encodeURIComponent(value);
|
|
205
|
+
}).join("/");
|
|
206
|
+
return open ? null : filled;
|
|
207
|
+
}
|
|
177
208
|
export function readPhiLinkTarget(value) {
|
|
178
209
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
179
210
|
return null;
|
|
@@ -192,10 +223,12 @@ export function readPhiLinkTarget(value) {
|
|
|
192
223
|
* the asking Area is the behaviour of every link that names none, which is the honest default.
|
|
193
224
|
*/
|
|
194
225
|
const area = isPhiCmsAreaKey(record.area) ? { area: record.area } : {};
|
|
226
|
+
const params = readPhiRouteParams(record.params);
|
|
195
227
|
return {
|
|
196
228
|
kind: "page",
|
|
197
229
|
reference: parsed.reference,
|
|
198
230
|
...area,
|
|
231
|
+
...(params ? { params } : {}),
|
|
199
232
|
...(fragment ? { fragment } : {}),
|
|
200
233
|
...newTab,
|
|
201
234
|
};
|
package/dist/resource-links.d.ts
CHANGED
|
@@ -59,8 +59,9 @@ export type PhisResourceLink = {
|
|
|
59
59
|
*
|
|
60
60
|
* Bounded twice: to this Add-on's own links, and to subjects the acting user may reach. Writing needs
|
|
61
61
|
* an actor -- a link is a person saying these two things belong together, and it is what later lets the
|
|
62
|
-
* Add-on act with no person there. A hook or a job may read the links it wrote and may
|
|
63
|
-
*
|
|
62
|
+
* Add-on act with no person there. A hook or a job may read the links it wrote and may make new ones only
|
|
63
|
+
* on what it opened itself: a thread it owns -- or a ticket or task whose thread it owns -- it reaches
|
|
64
|
+
* already, so a link there grants nothing that needed anybody's consent.
|
|
64
65
|
*/
|
|
65
66
|
export type PhisResourceLinksCapabilityV1 = {
|
|
66
67
|
/** This Add-on's links on one subject, or none where the subject is out of reach. */
|
|
@@ -68,8 +69,10 @@ export type PhisResourceLinksCapabilityV1 = {
|
|
|
68
69
|
/**
|
|
69
70
|
* Records a reference, or hands back the one that is already there.
|
|
70
71
|
*
|
|
71
|
-
* Asking twice is how an id is learned, the way a declared group is: `(type, externalId)` is
|
|
72
|
-
* within this Add-on and this Site, so a second call answers with the first
|
|
72
|
+
* Asking twice is how an id is learned, the way a declared group is: `(subject, type, externalId)` is
|
|
73
|
+
* unique within this Add-on and this Site, so a second call for the same subject answers with the first
|
|
74
|
+
* link instead of failing. One external record may be linked from several subjects -- one issue that
|
|
75
|
+
* several tickets wait on -- and each of those links is its own.
|
|
73
76
|
*/
|
|
74
77
|
link(input: {
|
|
75
78
|
subject: PhisResourceLinkSubject;
|
|
@@ -86,9 +89,12 @@ export type PhisResourceLinksCapabilityV1 = {
|
|
|
86
89
|
}): Promise<boolean>;
|
|
87
90
|
/** Removes a link, and with it whatever actorless reach it granted. */
|
|
88
91
|
unlink(linkId: number): Promise<boolean>;
|
|
89
|
-
/**
|
|
90
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Every link of this Add-on to one external record, oldest first: what an event about that record has
|
|
94
|
+
* to reach. Empty where none is recorded.
|
|
95
|
+
*/
|
|
96
|
+
listByExternalId(input: {
|
|
91
97
|
type: number;
|
|
92
98
|
externalId: string;
|
|
93
|
-
}): Promise<PhisResourceLink
|
|
99
|
+
}): Promise<PhisResourceLink[]>;
|
|
94
100
|
};
|
package/dist/schema.d.ts
CHANGED
|
@@ -235,6 +235,15 @@ export type PhisAddonAssetSlotDescriptor = {
|
|
|
235
235
|
* newest of several would be a fact nobody asked for.
|
|
236
236
|
*/
|
|
237
237
|
mirrorColumn?: string;
|
|
238
|
+
/**
|
|
239
|
+
* A role this Add-on declares, which the actor must hold to put a file in this slot, take one out,
|
|
240
|
+
* or list what it holds -- the same guard `requiresRole` is on a declared query, refused loudly.
|
|
241
|
+
*
|
|
242
|
+
* On an owner- or group-scoped table it narrows: the row's own authority still has to agree. On a
|
|
243
|
+
* table with neither, Core has no row to judge, so a slot there must state one, and the role is then
|
|
244
|
+
* the whole authority -- which is what lets a category icon or a shop logo carry a file at all.
|
|
245
|
+
*/
|
|
246
|
+
requiresRole?: string;
|
|
238
247
|
};
|
|
239
248
|
export type PhisAddonTableDescriptor = {
|
|
240
249
|
name: string;
|