@aglyn/aglyn 1.0.0-beta.285 → 1.0.0-beta.288
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/package.json +11 -11
- package/src/lib/app-utils/account-acquisition.d.ts +14 -0
- package/src/lib/app-utils/account-acquisition.js +19 -0
- package/src/lib/app-utils/account-acquisition.js.map +1 -1
- package/src/lib/app-utils/api-plugins.d.ts +25 -0
- package/src/lib/app-utils/api-plugins.js +13 -0
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/business-profile-values.d.ts +15 -3
- package/src/lib/app-utils/business-profile-values.js +19 -3
- package/src/lib/app-utils/business-profile-values.js.map +1 -1
- package/src/lib/app-utils/business-profile.d.ts +5 -3
- package/src/lib/app-utils/business-profile.js +2 -1
- package/src/lib/app-utils/business-profile.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +11 -0
- package/src/lib/app-utils/contacts.js +18 -0
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/docs-deflection.d.ts +1 -1
- package/src/lib/app-utils/docs-deflection.js +17 -0
- package/src/lib/app-utils/docs-deflection.js.map +1 -1
- package/src/lib/app-utils/docs-help-sections.generated.js +5 -2
- package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +9 -9
- package/src/lib/app-utils/docs-help.generated.js +20 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +168 -63
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/docs-retrieval.d.ts +17 -0
- package/src/lib/app-utils/docs-retrieval.js +28 -0
- package/src/lib/app-utils/docs-retrieval.js.map +1 -1
- package/src/lib/app-utils/host-naming.d.ts +2 -1
- package/src/lib/app-utils/host-naming.js +65 -2
- package/src/lib/app-utils/host-naming.js.map +1 -1
- package/src/lib/app-utils/host-permissions.d.ts +159 -3
- package/src/lib/app-utils/host-permissions.js +384 -12
- package/src/lib/app-utils/host-permissions.js.map +1 -1
- package/src/lib/app-utils/org-permission-editor.d.ts +128 -1
- package/src/lib/app-utils/org-permission-editor.js +176 -1
- package/src/lib/app-utils/org-permission-editor.js.map +1 -1
- package/src/lib/app-utils/org-permissions.d.ts +62 -1
- package/src/lib/app-utils/org-permissions.js +55 -5
- package/src/lib/app-utils/org-permissions.js.map +1 -1
- package/src/lib/app-utils/org-role-grants.d.ts +28 -0
- package/src/lib/app-utils/org-role-grants.js +180 -2
- package/src/lib/app-utils/org-role-grants.js.map +1 -1
- package/src/lib/app-utils/org-roles.js +11 -2
- package/src/lib/app-utils/org-roles.js.map +1 -1
- package/src/lib/app-utils/redirect-query.d.ts +39 -0
- package/src/lib/app-utils/redirect-query.js +57 -0
- package/src/lib/app-utils/redirect-query.js.map +1 -0
- package/src/lib/app-utils/release-flags.js +2 -2
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/site-starter-links.d.ts +42 -0
- package/src/lib/app-utils/site-starter-links.js +79 -0
- package/src/lib/app-utils/site-starter-links.js.map +1 -0
- package/src/lib/app-utils/site-starter-nodes.d.ts +91 -0
- package/src/lib/app-utils/site-starter-nodes.js +210 -0
- package/src/lib/app-utils/site-starter-nodes.js.map +1 -0
- package/src/lib/app-utils/site-starter-theme.d.ts +90 -0
- package/src/lib/app-utils/site-starter-theme.js +241 -0
- package/src/lib/app-utils/site-starter-theme.js.map +1 -0
- package/src/lib/app-utils/webhook-delivery.js +6 -1
- package/src/lib/app-utils/webhook-delivery.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +12 -2
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.js +39 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/plugin-closure-notices.d.ts +88 -0
- package/src/lib/plugin-manager/plugin-closure-notices.js +123 -0
- package/src/lib/plugin-manager/plugin-closure-notices.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +15 -0
- package/src/lib/plugin-manager/plugin-contact-capture.js +24 -1
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-customer-display-verifier.d.ts +77 -0
- package/src/lib/plugin-manager/plugin-customer-display-verifier.js +74 -0
- package/src/lib/plugin-manager/plugin-customer-display-verifier.js.map +1 -0
- package/src/lib/plugin-manager/plugin-customer-display.d.ts +135 -0
- package/src/lib/plugin-manager/plugin-customer-display.js +189 -0
- package/src/lib/plugin-manager/plugin-customer-display.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entitlements.d.ts +59 -0
- package/src/lib/plugin-manager/plugin-entitlements.js +32 -3
- package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
- package/src/lib/plugin-manager/plugin-events.d.ts +45 -0
- package/src/lib/plugin-manager/plugin-events.js.map +1 -1
- package/src/lib/plugin-manager/plugin-permissions.d.ts +74 -0
- package/src/lib/plugin-manager/plugin-permissions.js +91 -1
- package/src/lib/plugin-manager/plugin-permissions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-starters.d.ts +7 -0
- package/src/lib/plugin-manager/plugin-site-starters.js.map +1 -1
- package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +87 -4
- package/src/lib/plugin-manager/plugin-tax-return-sources.js +155 -35
- package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -1
|
@@ -36,6 +36,27 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
36
36
|
* figures, its tables and figures for the screen, its blocks for the export,
|
|
37
37
|
* and its own summary and rows carried whole for the audit.
|
|
38
38
|
*
|
|
39
|
+
* A plugin that records two KINDS of sale apart — sales it facilitated for
|
|
40
|
+
* merchants and sales the operator made itself, say — answers one section
|
|
41
|
+
* per kind, as a list. Each is its own card, with its own truncation, its own
|
|
42
|
+
* undated rows and its own findings, because one card over two collections
|
|
43
|
+
* could only say "these rows exceeded the cap" without saying which. The
|
|
44
|
+
* list is all or nothing: an empty list or one malformed section refuses the
|
|
45
|
+
* plugin, so a half-answered plugin never reads as a complete one.
|
|
46
|
+
*
|
|
47
|
+
* ## THE OPERATOR'S OWN SALES FOLD INTO THE FILING FIGURES (AGL-4038)
|
|
48
|
+
*
|
|
49
|
+
* The filing figures sum the operator's own invoices. A plugin may also hold
|
|
50
|
+
* sales the operator made AS THE SELLER — goods sold from the operator's own
|
|
51
|
+
* store, hardware sold to workspaces — and those are as much the operator's
|
|
52
|
+
* receipts as an invoice is. A source states them as
|
|
53
|
+
* {@link TaxReturnOperatorSalesPart}s, by jurisdiction and under a label for
|
|
54
|
+
* each kind, and the platform ADDS them to the filing figures and prints a
|
|
55
|
+
* breakdown beside them by part and jurisdiction, so the sum can be checked.
|
|
56
|
+
* A facilitated sale — somebody else's money — never goes there: it stays on
|
|
57
|
+
* the source's own card. A source counts each sale under ONE part only, and
|
|
58
|
+
* a part id is unique on the return, so nothing is folded in twice.
|
|
59
|
+
*
|
|
39
60
|
* ## ⛔ AN UNREAD SOURCE REFUSES, IT NEVER READS AS ZERO
|
|
40
61
|
*
|
|
41
62
|
* Decided before anything else, because this is a legal filing. A source
|
|
@@ -70,7 +91,27 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
70
91
|
*/ import { PLUGIN_TAX_RETURN_SOURCES } from "./first-party-plugins.generated.js";
|
|
71
92
|
import { definePluginServiceContract, registerPluginService, resolvePluginServices } from "./plugin-services.js";
|
|
72
93
|
export { PLUGIN_TAX_RETURN_SOURCES };
|
|
73
|
-
/**
|
|
94
|
+
/** The figure fields of {@link TaxReturnOperatorFigures}, in print order. */ export const TAX_RETURN_OPERATOR_FIGURE_FIELDS = [
|
|
95
|
+
'transactionCount',
|
|
96
|
+
'totalSalesCents',
|
|
97
|
+
'taxableSalesCents',
|
|
98
|
+
'taxCollectedCents',
|
|
99
|
+
'refundCount',
|
|
100
|
+
'refundedSalesCents',
|
|
101
|
+
'refundedTaxCents'
|
|
102
|
+
];
|
|
103
|
+
/** A jurisdiction with nothing in it. */ export function emptyTaxReturnOperatorFigures() {
|
|
104
|
+
return {
|
|
105
|
+
transactionCount: 0,
|
|
106
|
+
totalSalesCents: 0,
|
|
107
|
+
taxableSalesCents: 0,
|
|
108
|
+
taxCollectedCents: 0,
|
|
109
|
+
refundCount: 0,
|
|
110
|
+
refundedSalesCents: 0,
|
|
111
|
+
refundedTaxCents: 0
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** Every source answers; one per plugin, with one section or several. */ export const TAX_RETURN_SOURCES = definePluginServiceContract('core.tax-return-sources', {
|
|
74
115
|
multiple: true
|
|
75
116
|
});
|
|
76
117
|
/**
|
|
@@ -115,8 +156,59 @@ const isCount = (value)=>typeof value === 'number' && Number.isFinite(value) &&
|
|
|
115
156
|
}
|
|
116
157
|
const badFinding = answer.findings.find((finding)=>!isText(finding == null ? void 0 : finding.id) || finding.severity !== 'blocking' && finding.severity !== 'review' || !isCount(finding.count));
|
|
117
158
|
if (badFinding) return 'a finding with no id, severity or count';
|
|
159
|
+
if (answer.operatorSales !== undefined) {
|
|
160
|
+
if (!Array.isArray(answer.operatorSales)) return 'no list of its own sales';
|
|
161
|
+
for (const part of answer.operatorSales){
|
|
162
|
+
if (!isText(part == null ? void 0 : part.id) || !isText(part == null ? void 0 : part.label)) return 'own sales with no id or label';
|
|
163
|
+
if (!part.byJurisdiction || typeof part.byJurisdiction !== 'object' || Array.isArray(part.byJurisdiction)) {
|
|
164
|
+
return 'own sales with no jurisdictions';
|
|
165
|
+
}
|
|
166
|
+
for (const figures of Object.values(part.byJurisdiction)){
|
|
167
|
+
// Whole cents and counts only: a fraction or a NaN folded into a
|
|
168
|
+
// form item is a figure nobody can file.
|
|
169
|
+
const bad = TAX_RETURN_OPERATOR_FIGURE_FIELDS.some((field)=>!isCount(figures == null ? void 0 : figures[field]) || !Number.isInteger(figures[field]));
|
|
170
|
+
if (bad) return 'own sales with a figure that is not a whole number';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
118
174
|
return null;
|
|
119
175
|
}
|
|
176
|
+
export function taxReturnOperatorSalesRows(sections) {
|
|
177
|
+
const rows = [];
|
|
178
|
+
for (const section of sections != null ? sections : []){
|
|
179
|
+
var _section_operatorSales;
|
|
180
|
+
if ((section == null ? void 0 : section.outcome) !== 'answered') continue;
|
|
181
|
+
for (const part of (_section_operatorSales = section.operatorSales) != null ? _section_operatorSales : []){
|
|
182
|
+
var _part_byJurisdiction;
|
|
183
|
+
for (const [jurisdiction, figures] of Object.entries((_part_byJurisdiction = part.byJurisdiction) != null ? _part_byJurisdiction : {})){
|
|
184
|
+
rows.push(_extends({
|
|
185
|
+
pluginId: section.pluginId,
|
|
186
|
+
partId: part.id,
|
|
187
|
+
label: part.label,
|
|
188
|
+
jurisdiction
|
|
189
|
+
}, emptyTaxReturnOperatorFigures(), Object.fromEntries(TAX_RETURN_OPERATOR_FIGURE_FIELDS.map((field)=>{
|
|
190
|
+
var _ref;
|
|
191
|
+
return [
|
|
192
|
+
field,
|
|
193
|
+
Number((_ref = figures == null ? void 0 : figures[field]) != null ? _ref : 0) || 0
|
|
194
|
+
];
|
|
195
|
+
}))));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return rows;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The operator's own sales in ONE jurisdiction, summed over every part —
|
|
203
|
+
* what the platform adds to its own figures for that jurisdiction.
|
|
204
|
+
*/ export function taxReturnOperatorSalesIn(sections, jurisdiction) {
|
|
205
|
+
const total = emptyTaxReturnOperatorFigures();
|
|
206
|
+
for (const row of taxReturnOperatorSalesRows(sections)){
|
|
207
|
+
if (row.jurisdiction !== jurisdiction) continue;
|
|
208
|
+
for (const field of TAX_RETURN_OPERATOR_FIGURE_FIELDS)total[field] += row[field];
|
|
209
|
+
}
|
|
210
|
+
return total;
|
|
211
|
+
}
|
|
120
212
|
/**
|
|
121
213
|
* Every source's answer for one period — declared sources first, in the
|
|
122
214
|
* compiled order, then any other registered source in registration order.
|
|
@@ -132,59 +224,87 @@ const isCount = (value)=>typeof value === 'number' && Number.isFinite(value) &&
|
|
|
132
224
|
...declared,
|
|
133
225
|
...registered.map((entry)=>entry.pluginId).filter((pluginId)=>!declared.includes(pluginId))
|
|
134
226
|
].filter((pluginId, index, all)=>all.indexOf(pluginId) === index);
|
|
135
|
-
const
|
|
227
|
+
const perPlugin = await Promise.all(order.map(async (pluginId)=>{
|
|
136
228
|
var _registered_find;
|
|
137
229
|
const source = (_registered_find = registered.find((entry)=>entry.pluginId === pluginId)) == null ? void 0 : _registered_find.impl;
|
|
138
230
|
if (!source) {
|
|
139
231
|
console.error(`[tax-return] "${pluginId}" declares a tax return source and none is ` + 'registered in this process; its sales cannot be read.');
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
pluginId,
|
|
143
|
-
id: pluginId,
|
|
144
|
-
reason: `The “${pluginId}” plugin sells through the platform and registered ` + 'nothing to read its sales with.'
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
try {
|
|
148
|
-
const answer = await source.read(request);
|
|
149
|
-
const problem = malformed(answer);
|
|
150
|
-
if (problem) {
|
|
151
|
-
return {
|
|
232
|
+
return [
|
|
233
|
+
{
|
|
152
234
|
outcome: 'refused',
|
|
153
235
|
pluginId,
|
|
154
236
|
id: pluginId,
|
|
155
|
-
reason: `The “${pluginId}” plugin
|
|
156
|
-
}
|
|
237
|
+
reason: `The “${pluginId}” plugin sells through the platform and registered ` + 'nothing to read its sales with.'
|
|
238
|
+
}
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
const answered = await source.read(request);
|
|
243
|
+
const sections = Array.isArray(answered) ? answered : [
|
|
244
|
+
answered
|
|
245
|
+
];
|
|
246
|
+
// All or nothing: a plugin that answered no section, or one section
|
|
247
|
+
// the return cannot print, is refused whole, so a half-answered plugin
|
|
248
|
+
// never reads as a complete one.
|
|
249
|
+
const problem = sections.length ? sections.map(malformed).find((found)=>found !== null) : 'no section';
|
|
250
|
+
if (problem) {
|
|
251
|
+
return [
|
|
252
|
+
{
|
|
253
|
+
outcome: 'refused',
|
|
254
|
+
pluginId,
|
|
255
|
+
id: pluginId,
|
|
256
|
+
reason: `The “${pluginId}” plugin answered ${problem}.`
|
|
257
|
+
}
|
|
258
|
+
];
|
|
157
259
|
}
|
|
158
|
-
return _extends({},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
260
|
+
return sections.map((section)=>_extends({}, section, {
|
|
261
|
+
outcome: 'answered',
|
|
262
|
+
pluginId
|
|
263
|
+
}));
|
|
162
264
|
} catch (error) {
|
|
163
265
|
console.error(`[tax-return] "${pluginId}" failed to read its sales`, error);
|
|
164
|
-
return
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
266
|
+
return [
|
|
267
|
+
{
|
|
268
|
+
outcome: 'refused',
|
|
269
|
+
pluginId,
|
|
270
|
+
id: pluginId,
|
|
271
|
+
reason: `The “${pluginId}” plugin could not read its sales for this period.`
|
|
272
|
+
}
|
|
273
|
+
];
|
|
170
274
|
}
|
|
171
275
|
}));
|
|
276
|
+
const answers = perPlugin.flat();
|
|
172
277
|
// Two sources under one id would print two cards and one set of findings
|
|
173
278
|
// under the same key, and a finding that names the wrong source's rows is
|
|
174
279
|
// worse than none. The later one is refused, visibly.
|
|
175
280
|
const seen = new Set();
|
|
281
|
+
// The same for the operator's own sales: a part id answered twice would be
|
|
282
|
+
// folded into the filing figures twice.
|
|
283
|
+
const seenParts = new Set();
|
|
176
284
|
return answers.map((section)=>{
|
|
285
|
+
var _section_operatorSales;
|
|
177
286
|
if (section.outcome !== 'answered') return section;
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
287
|
+
if (seen.has(section.id)) {
|
|
288
|
+
return {
|
|
289
|
+
outcome: 'refused',
|
|
290
|
+
pluginId: section.pluginId,
|
|
291
|
+
id: section.pluginId,
|
|
292
|
+
reason: `The “${section.pluginId}” plugin answered as “${section.id}”, which ` + 'another source already is.'
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const partIds = ((_section_operatorSales = section.operatorSales) != null ? _section_operatorSales : []).map((part)=>part.id);
|
|
296
|
+
const repeated = partIds.find((partId, index)=>seenParts.has(partId) || partIds.indexOf(partId) !== index);
|
|
297
|
+
if (repeated) {
|
|
298
|
+
return {
|
|
299
|
+
outcome: 'refused',
|
|
300
|
+
pluginId: section.pluginId,
|
|
301
|
+
id: section.pluginId,
|
|
302
|
+
reason: `The “${section.pluginId}” plugin stated its own sales as “${repeated}”, ` + 'which is already on the return.'
|
|
303
|
+
};
|
|
181
304
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
id: section.pluginId,
|
|
186
|
-
reason: `The “${section.pluginId}” plugin answered as “${section.id}”, which ` + 'another source already is.'
|
|
187
|
-
};
|
|
305
|
+
seen.add(section.id);
|
|
306
|
+
for (const partId of partIds)seenParts.add(partId);
|
|
307
|
+
return section;
|
|
188
308
|
});
|
|
189
309
|
}
|
|
190
310
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-tax-return-sources.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * THE SALES A PLUGIN MADE THROUGH THE PLATFORM, ON THE OPERATOR'S RETURN\n * (AGL-3080).\n *\n * The operator — whoever runs this deployment — files a sales tax return for\n * the sales it FACILITATED, not only for its own. Its own subscription\n * invoices are platform billing and the return sums them itself. A plugin\n * that sells through the platform's account — a storefront checkout whose tax\n * Stripe computes against the operator's registrations, a marketplace charge\n * whose tax stays platform-side — holds records the return cannot read\n * without knowing that plugin's storage, and a classification of them the\n * return has no business restating.\n *\n * So the division is: the FILING is the platform's — the period, the\n * jurisdiction and registration, the verdict, the working-papers export and\n * the Texas Webfile lines. What a plugin sold, how each of its rows\n * classifies and who is liable for it, and the words a preparer reads about\n * it, are the plugin's. A source answers one period with a\n * {@link TaxReturnSourceAnswer}: its findings, its lines for the filing\n * figures, its tables and figures for the screen, its blocks for the export,\n * and its own summary and rows carried whole for the audit.\n *\n * ## ⛔ AN UNREAD SOURCE REFUSES, IT NEVER READS AS ZERO\n *\n * Decided before anything else, because this is a legal filing. A source\n * that answered nothing is indistinguishable, on a total, from a source that\n * sold nothing — and a return signed on that total understates what the\n * operator collected and holds. So:\n *\n * - **Declared and not registered** — every plugin whose sales belong on the\n * return says so with `\"taxReturnSource\": true` in `plugins.config.json`,\n * compiled into {@link PLUGIN_TAX_RETURN_SOURCES}. A declared plugin that\n * registered no source in this process answers `outcome: 'refused'`. A\n * runtime registry alone could not say this: an empty registry looks\n * exactly like a deployment where nothing sells.\n * - **Threw, or answered a malformed section** — `outcome: 'refused'`, with\n * the sentence the return prints.\n * - **Truncated, or holding rows no period can reach** — answered, and the\n * platform raises each as a BLOCKING finding itself; a source cannot word\n * its way out of either.\n *\n * The return turns every refusal into a blocking \"do not file from this\"\n * finding. {@link readTaxReturnSources} never throws and never drops a\n * declared source.\n *\n * The reader is the staff tax-return route, which awaits `ensureAll` on the\n * `consoleApi` surface before it asks, so a runtime registry is filled before\n * the question; the compiled declaration is what makes a MISSING\n * registration a refusal rather than an absence.\n *\n * ⚑ The discriminant is a string: this repo compiles with\n * `strictNullChecks: false`, under which a boolean-literal union does not\n * narrow (see `plugin-artifact-inventory.ts`).\n */\n\nimport { PLUGIN_TAX_RETURN_SOURCES } from './first-party-plugins.generated'\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\nexport { PLUGIN_TAX_RETURN_SOURCES }\n\n/** Which exporter the filing jurisdiction gets. */\nexport type TaxReturnFilingForm = 'tx-webfile' | 'breakdown'\n\n/**\n * The jurisdiction the operator files in, as the platform resolved it from\n * its own configuration. A source words its lines and findings for THIS\n * jurisdiction and never assumes one.\n */\nexport interface TaxReturnFiling {\n /** The bucket key: `US-TX`, `US-CA`, `GB`. */\n code: string\n /** How a sentence names it: `Texas`, or the code itself. */\n label: string\n /** Which exporter the filing lines are for. */\n form: TaxReturnFilingForm\n /** How a sentence names the filing figures: `Items 1–3`, `the breakdown`. */\n figuresName: string\n}\n\n/** What the return asks every source, once per period. */\nexport interface TaxReturnSourceRequest {\n /** `2026-Q3` or `2026-09`, echoed for the record. */\n period: string\n /** Half-open UTC bounds of the period. */\n start: Date\n end: Date\n filing: TaxReturnFiling\n /**\n * The most documents the operator will read for one source. Past it the\n * answer is `truncated`, and a truncated source blocks the return: the\n * ceiling is the operator's policy, so a source is TOLD it.\n */\n rowCap: number\n}\n\nexport type TaxReturnFindingSeverity = 'blocking' | 'review'\n\n/**\n * One finding, in the words a preparer reads. `blocking` means the return\n * must not be filed until it is resolved; `review` means a figure is\n * qualified. A zero count is not raised.\n */\nexport interface TaxReturnFinding {\n /** Stable, and unique on the return. */\n id: string\n severity: TaxReturnFindingSeverity\n /** Rows, or cents where the label says so. */\n count: number\n label: string\n /** What it means for the return, and what to do — not a restatement. */\n detail: string\n}\n\n/** A line printed beneath the platform's own filing figures. */\nexport interface TaxReturnFilingLine {\n /** The form's item number where the figure maps to one, else `—`. */\n item: string\n label: string\n /** Dollars, or null when the figure is not computed. */\n dollars: string | null\n note: string\n}\n\n/** One cell of a source's table on the screen. */\nexport interface TaxReturnSectionCell {\n text: string\n /** A second, quieter line under the text. */\n caption?: string\n /**\n * A short tag beside the text. `attention` marks the figure that needs a\n * decision; `neutral` qualifies one.\n */\n tag?: { label: string; tone: 'attention' | 'neutral' }\n /** The figure a reader must not miss. */\n strong?: boolean\n}\n\nexport interface TaxReturnSectionColumn {\n label: string\n /** Right-aligned. */\n numeric?: boolean\n /** Money: set in a fixed-width face so columns of cents line up. */\n money?: boolean\n}\n\n/** A table on the source's card. */\nexport interface TaxReturnSectionTable {\n /** A subheading above the table; the first table sits under the card's own. */\n heading?: string\n /** A sentence between the heading and the table. */\n description?: string\n columns: TaxReturnSectionColumn[]\n rows: Array<{ key: string; cells: TaxReturnSectionCell[] }>\n /** What the table says when it has no rows. */\n empty: string\n /** A caption under the table. */\n footnote?: string\n}\n\n/** One label/value line of a source's figures. */\nexport interface TaxReturnSectionFigure {\n label: string\n value: string\n note: string\n}\n\n/**\n * One block of the working-papers export, as the CSV's own rows.\n *\n * `jurisdictions` places it beside the operator's own sales by jurisdiction,\n * before the working papers; `sections` places it after them, where each\n * source's figures sit. The platform separates blocks with a blank row.\n */\nexport interface TaxReturnExportBlock {\n placement: 'jurisdictions' | 'sections'\n rows: string[][]\n}\n\n/** What a source answers for one period. */\nexport interface TaxReturnSourceAnswer {\n /** Stable key for the source's findings and its card, unique on the return. */\n id: string\n /** The noun for its rows: `Storefront`, `Marketplace`. */\n name: string\n /** The card's heading. */\n title: string\n /** The card's help, as a documentation excerpt. */\n help: string\n /** The paragraph under the heading. */\n intro: string\n /** Documents past the request's `rowCap` were not read. */\n truncated: boolean\n /** Rows no period query can reach — in this return and every other. */\n undatedRows: number\n /** The source's own findings. Truncation and undated rows are raised by the platform. */\n findings: TaxReturnFinding[]\n /** Lines beneath the filing figures, for the request's `filing.form`. */\n filingLines: TaxReturnFilingLine[]\n tables: TaxReturnSectionTable[]\n figures: TaxReturnSectionFigure[]\n exports: TaxReturnExportBlock[]\n /** The source's own figures, carried whole for the audit. */\n summary: unknown\n /** The rows behind them, as the source projects them for the working papers. */\n rows: unknown[]\n}\n\n/** One source on the return: its answer, or why there is none. */\nexport type TaxReturnSection =\n | ({ outcome: 'answered'; pluginId: string } & TaxReturnSourceAnswer)\n | {\n outcome: 'refused'\n pluginId: string\n /** The plugin id: a refused source never said what it calls itself. */\n id: string\n /** Why nothing from this source is on the return, as the return prints it. */\n reason: string\n }\n\nexport interface TaxReturnSource {\n /**\n * This plugin's sales for one period. May throw: the return refuses the\n * source rather than read a throw as nothing sold.\n */\n read(request: TaxReturnSourceRequest): Promise<TaxReturnSourceAnswer>\n}\n\n/** Every source answers; one per plugin. */\nexport const TAX_RETURN_SOURCES = definePluginServiceContract<TaxReturnSource>(\n 'core.tax-return-sources',\n { multiple: true },\n)\n\n/**\n * Installs a plugin's source. Owner = the loader's marker inside a register\n * fn, else `options.pluginId`. Registering again replaces the plugin's\n * earlier source, so a module evaluated twice does not answer twice.\n */\nexport function registerTaxReturnSource(\n source: TaxReturnSource,\n options?: { pluginId?: string },\n): void {\n if (typeof source?.read !== 'function') {\n throw new Error('a tax return source needs a read function')\n }\n registerPluginService(TAX_RETURN_SOURCES, source, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\n/** The plugins with a registered source, in the order they answer. */\nexport function listTaxReturnSources(): string[] {\n return resolvePluginServices(TAX_RETURN_SOURCES).map((entry) => entry.pluginId)\n}\n\nconst isText = (value: unknown): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\nconst isCount = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/**\n * What is wrong with an answer, or null when it can be printed.\n *\n * Checked because the answer crosses a package boundary into a legal\n * document: a finding with a NaN count sums to NaN and the verdict reads\n * clean, and a missing array is a section that silently shows nothing.\n */\nfunction malformed(answer: TaxReturnSourceAnswer): string | null {\n if (!answer || typeof answer !== 'object') return 'no section'\n if (!isText(answer.id) || !isText(answer.name) || !isText(answer.title)) {\n return 'a section with no id, name or title'\n }\n if (typeof answer.truncated !== 'boolean') return 'no truncation flag'\n if (!isCount(answer.undatedRows)) return 'no count of undated rows'\n for (const key of ['findings', 'filingLines', 'tables', 'figures', 'exports', 'rows'] as const) {\n if (!Array.isArray(answer[key])) return `no ${key}`\n }\n const badFinding = answer.findings.find(\n (finding) =>\n !isText(finding?.id) ||\n (finding.severity !== 'blocking' && finding.severity !== 'review') ||\n !isCount(finding.count),\n )\n if (badFinding) return 'a finding with no id, severity or count'\n return null\n}\n\n/**\n * Every source's answer for one period — declared sources first, in the\n * compiled order, then any other registered source in registration order.\n *\n * NEVER THROWS and never drops a declared source: a declared plugin with no\n * registration, a source that threw, and a malformed or duplicate answer\n * each come back as `outcome: 'refused'` with the sentence the return prints.\n * `declared` is the compiled {@link PLUGIN_TAX_RETURN_SOURCES} unless a spec\n * passes its own.\n */\nexport async function readTaxReturnSources(\n request: TaxReturnSourceRequest,\n declared: readonly string[] = PLUGIN_TAX_RETURN_SOURCES,\n): Promise<TaxReturnSection[]> {\n const registered = resolvePluginServices(TAX_RETURN_SOURCES)\n const order = [\n ...declared,\n ...registered\n .map((entry) => entry.pluginId)\n .filter((pluginId) => !declared.includes(pluginId)),\n ].filter((pluginId, index, all) => all.indexOf(pluginId) === index)\n\n const answers = await Promise.all(\n order.map(async (pluginId): Promise<TaxReturnSection> => {\n const source = registered.find((entry) => entry.pluginId === pluginId)?.impl\n if (!source) {\n console.error(\n `[tax-return] \"${pluginId}\" declares a tax return source and none is ` +\n 'registered in this process; its sales cannot be read.',\n )\n return {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason:\n `The “${pluginId}” plugin sells through the platform and registered ` +\n 'nothing to read its sales with.',\n }\n }\n try {\n const answer = await source.read(request)\n const problem = malformed(answer)\n if (problem) {\n return {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason: `The “${pluginId}” plugin answered ${problem}.`,\n }\n }\n return { ...answer, outcome: 'answered', pluginId }\n } catch (error) {\n console.error(`[tax-return] \"${pluginId}\" failed to read its sales`, error)\n return {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason: `The “${pluginId}” plugin could not read its sales for this period.`,\n }\n }\n }),\n )\n\n // Two sources under one id would print two cards and one set of findings\n // under the same key, and a finding that names the wrong source's rows is\n // worse than none. The later one is refused, visibly.\n const seen = new Set<string>()\n return answers.map((section) => {\n if (section.outcome !== 'answered') return section\n if (!seen.has(section.id)) {\n seen.add(section.id)\n return section\n }\n return {\n outcome: 'refused',\n pluginId: section.pluginId,\n id: section.pluginId,\n reason:\n `The “${section.pluginId}” plugin answered as “${section.id}”, which ` +\n 'another source already is.',\n }\n })\n}\n"],"names":["PLUGIN_TAX_RETURN_SOURCES","definePluginServiceContract","registerPluginService","resolvePluginServices","TAX_RETURN_SOURCES","multiple","registerTaxReturnSource","source","options","read","Error","pluginId","listTaxReturnSources","map","entry","isText","value","trim","length","isCount","Number","isFinite","malformed","answer","id","name","title","truncated","undatedRows","key","Array","isArray","badFinding","findings","find","finding","severity","count","readTaxReturnSources","request","declared","registered","order","filter","includes","index","all","indexOf","answers","Promise","impl","console","error","outcome","reason","problem","seen","Set","section","has","add"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-tax-return-sources.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * THE SALES A PLUGIN MADE THROUGH THE PLATFORM, ON THE OPERATOR'S RETURN\n * (AGL-3080).\n *\n * The operator — whoever runs this deployment — files a sales tax return for\n * the sales it FACILITATED, not only for its own. Its own subscription\n * invoices are platform billing and the return sums them itself. A plugin\n * that sells through the platform's account — a storefront checkout whose tax\n * Stripe computes against the operator's registrations, a marketplace charge\n * whose tax stays platform-side — holds records the return cannot read\n * without knowing that plugin's storage, and a classification of them the\n * return has no business restating.\n *\n * So the division is: the FILING is the platform's — the period, the\n * jurisdiction and registration, the verdict, the working-papers export and\n * the Texas Webfile lines. What a plugin sold, how each of its rows\n * classifies and who is liable for it, and the words a preparer reads about\n * it, are the plugin's. A source answers one period with a\n * {@link TaxReturnSourceAnswer}: its findings, its lines for the filing\n * figures, its tables and figures for the screen, its blocks for the export,\n * and its own summary and rows carried whole for the audit.\n *\n * A plugin that records two KINDS of sale apart — sales it facilitated for\n * merchants and sales the operator made itself, say — answers one section\n * per kind, as a list. Each is its own card, with its own truncation, its own\n * undated rows and its own findings, because one card over two collections\n * could only say \"these rows exceeded the cap\" without saying which. The\n * list is all or nothing: an empty list or one malformed section refuses the\n * plugin, so a half-answered plugin never reads as a complete one.\n *\n * ## THE OPERATOR'S OWN SALES FOLD INTO THE FILING FIGURES (AGL-4038)\n *\n * The filing figures sum the operator's own invoices. A plugin may also hold\n * sales the operator made AS THE SELLER — goods sold from the operator's own\n * store, hardware sold to workspaces — and those are as much the operator's\n * receipts as an invoice is. A source states them as\n * {@link TaxReturnOperatorSalesPart}s, by jurisdiction and under a label for\n * each kind, and the platform ADDS them to the filing figures and prints a\n * breakdown beside them by part and jurisdiction, so the sum can be checked.\n * A facilitated sale — somebody else's money — never goes there: it stays on\n * the source's own card. A source counts each sale under ONE part only, and\n * a part id is unique on the return, so nothing is folded in twice.\n *\n * ## ⛔ AN UNREAD SOURCE REFUSES, IT NEVER READS AS ZERO\n *\n * Decided before anything else, because this is a legal filing. A source\n * that answered nothing is indistinguishable, on a total, from a source that\n * sold nothing — and a return signed on that total understates what the\n * operator collected and holds. So:\n *\n * - **Declared and not registered** — every plugin whose sales belong on the\n * return says so with `\"taxReturnSource\": true` in `plugins.config.json`,\n * compiled into {@link PLUGIN_TAX_RETURN_SOURCES}. A declared plugin that\n * registered no source in this process answers `outcome: 'refused'`. A\n * runtime registry alone could not say this: an empty registry looks\n * exactly like a deployment where nothing sells.\n * - **Threw, or answered a malformed section** — `outcome: 'refused'`, with\n * the sentence the return prints.\n * - **Truncated, or holding rows no period can reach** — answered, and the\n * platform raises each as a BLOCKING finding itself; a source cannot word\n * its way out of either.\n *\n * The return turns every refusal into a blocking \"do not file from this\"\n * finding. {@link readTaxReturnSources} never throws and never drops a\n * declared source.\n *\n * The reader is the staff tax-return route, which awaits `ensureAll` on the\n * `consoleApi` surface before it asks, so a runtime registry is filled before\n * the question; the compiled declaration is what makes a MISSING\n * registration a refusal rather than an absence.\n *\n * ⚑ The discriminant is a string: this repo compiles with\n * `strictNullChecks: false`, under which a boolean-literal union does not\n * narrow (see `plugin-artifact-inventory.ts`).\n */\n\nimport { PLUGIN_TAX_RETURN_SOURCES } from './first-party-plugins.generated'\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\nexport { PLUGIN_TAX_RETURN_SOURCES }\n\n/** Which exporter the filing jurisdiction gets. */\nexport type TaxReturnFilingForm = 'tx-webfile' | 'breakdown'\n\n/**\n * The jurisdiction the operator files in, as the platform resolved it from\n * its own configuration. A source words its lines and findings for THIS\n * jurisdiction and never assumes one.\n */\nexport interface TaxReturnFiling {\n /** The bucket key: `US-TX`, `US-CA`, `GB`. */\n code: string\n /** How a sentence names it: `Texas`, or the code itself. */\n label: string\n /** Which exporter the filing lines are for. */\n form: TaxReturnFilingForm\n /** How a sentence names the filing figures: `Items 1–3`, `the breakdown`. */\n figuresName: string\n}\n\n/** What the return asks every source, once per period. */\nexport interface TaxReturnSourceRequest {\n /** `2026-Q3` or `2026-09`, echoed for the record. */\n period: string\n /** Half-open UTC bounds of the period. */\n start: Date\n end: Date\n filing: TaxReturnFiling\n /**\n * The most documents the operator will read for one source. Past it the\n * answer is `truncated`, and a truncated source blocks the return: the\n * ceiling is the operator's policy, so a source is TOLD it.\n */\n rowCap: number\n}\n\nexport type TaxReturnFindingSeverity = 'blocking' | 'review'\n\n/**\n * One finding, in the words a preparer reads. `blocking` means the return\n * must not be filed until it is resolved; `review` means a figure is\n * qualified. A zero count is not raised.\n */\nexport interface TaxReturnFinding {\n /** Stable, and unique on the return. */\n id: string\n severity: TaxReturnFindingSeverity\n /** Rows, or cents where the label says so. */\n count: number\n label: string\n /** What it means for the return, and what to do — not a restatement. */\n detail: string\n}\n\n/** A line printed beneath the platform's own filing figures. */\nexport interface TaxReturnFilingLine {\n /** The form's item number where the figure maps to one, else `—`. */\n item: string\n label: string\n /** Dollars, or null when the figure is not computed. */\n dollars: string | null\n note: string\n}\n\n/** One cell of a source's table on the screen. */\nexport interface TaxReturnSectionCell {\n text: string\n /** A second, quieter line under the text. */\n caption?: string\n /**\n * A short tag beside the text. `attention` marks the figure that needs a\n * decision; `neutral` qualifies one.\n */\n tag?: { label: string; tone: 'attention' | 'neutral' }\n /** The figure a reader must not miss. */\n strong?: boolean\n}\n\nexport interface TaxReturnSectionColumn {\n label: string\n /** Right-aligned. */\n numeric?: boolean\n /** Money: set in a fixed-width face so columns of cents line up. */\n money?: boolean\n}\n\n/** A table on the source's card. */\nexport interface TaxReturnSectionTable {\n /** A subheading above the table; the first table sits under the card's own. */\n heading?: string\n /** A sentence between the heading and the table. */\n description?: string\n columns: TaxReturnSectionColumn[]\n rows: Array<{ key: string; cells: TaxReturnSectionCell[] }>\n /** What the table says when it has no rows. */\n empty: string\n /** A caption under the table. */\n footnote?: string\n}\n\n/** One label/value line of a source's figures. */\nexport interface TaxReturnSectionFigure {\n label: string\n value: string\n note: string\n}\n\n/**\n * One block of the working-papers export, as the CSV's own rows.\n *\n * `jurisdictions` places it beside the operator's own sales by jurisdiction,\n * before the working papers; `sections` places it after them, where each\n * source's figures sit. The platform separates blocks with a blank row.\n */\nexport interface TaxReturnExportBlock {\n placement: 'jurisdictions' | 'sections'\n rows: string[][]\n}\n\n/**\n * The operator's own sales of one kind in one jurisdiction, for one period.\n * Integer cents. Sales are placed in the period they were paid; refunds in\n * the period they were made, stated beside the sales and never netted.\n */\nexport interface TaxReturnOperatorFigures {\n /** Sales paid in the period. */\n transactionCount: number\n /** Receipts excluding the tax itself. */\n totalSalesCents: number\n /** The base the tax was charged on. */\n taxableSalesCents: number\n taxCollectedCents: number\n /** Refunds made in the period, whenever the sale was paid. */\n refundCount: number\n /** Refunded receipts excluding the tax. */\n refundedSalesCents: number\n refundedTaxCents: number\n}\n\n/**\n * One kind of the operator's own sales a source holds, which the platform\n * folds into the filing figures (see the module note).\n */\nexport interface TaxReturnOperatorSalesPart {\n /** Stable, and unique on the return. */\n id: string\n /** How the breakdown beside the filing figures names it. */\n label: string\n /**\n * By the jurisdiction keys the platform's own figures use (`US-TX`, `GB`,\n * `unknown` for a sale with no region). Every jurisdiction is listed in the\n * breakdown; only the filing jurisdiction's figures are added to the form.\n */\n byJurisdiction: Record<string, TaxReturnOperatorFigures>\n}\n\n/** The figure fields of {@link TaxReturnOperatorFigures}, in print order. */\nexport const TAX_RETURN_OPERATOR_FIGURE_FIELDS = [\n 'transactionCount',\n 'totalSalesCents',\n 'taxableSalesCents',\n 'taxCollectedCents',\n 'refundCount',\n 'refundedSalesCents',\n 'refundedTaxCents',\n] as const satisfies ReadonlyArray<keyof TaxReturnOperatorFigures>\n\n/** A jurisdiction with nothing in it. */\nexport function emptyTaxReturnOperatorFigures(): TaxReturnOperatorFigures {\n return {\n transactionCount: 0,\n totalSalesCents: 0,\n taxableSalesCents: 0,\n taxCollectedCents: 0,\n refundCount: 0,\n refundedSalesCents: 0,\n refundedTaxCents: 0,\n }\n}\n\n/** What a source answers for one period. */\nexport interface TaxReturnSourceAnswer {\n /** Stable key for the source's findings and its card, unique on the return. */\n id: string\n /** The noun for its rows: `Storefront`, `Marketplace`. */\n name: string\n /** The card's heading. */\n title: string\n /** The card's help, as a documentation excerpt. */\n help: string\n /** The paragraph under the heading. */\n intro: string\n /** Documents past the request's `rowCap` were not read. */\n truncated: boolean\n /** Rows no period query can reach — in this return and every other. */\n undatedRows: number\n /** The source's own findings. Truncation and undated rows are raised by the platform. */\n findings: TaxReturnFinding[]\n /** Lines beneath the filing figures, for the request's `filing.form`. */\n filingLines: TaxReturnFilingLine[]\n /**\n * The operator's OWN sales this section holds, which the platform adds to\n * the filing figures (see the module note). Absent or empty for a section\n * of facilitated sales only.\n */\n operatorSales?: TaxReturnOperatorSalesPart[]\n tables: TaxReturnSectionTable[]\n figures: TaxReturnSectionFigure[]\n exports: TaxReturnExportBlock[]\n /** The source's own figures, carried whole for the audit. */\n summary: unknown\n /** The rows behind them, as the source projects them for the working papers. */\n rows: unknown[]\n}\n\n/** One source on the return: its answer, or why there is none. */\nexport type TaxReturnSection =\n | ({ outcome: 'answered'; pluginId: string } & TaxReturnSourceAnswer)\n | {\n outcome: 'refused'\n pluginId: string\n /** The plugin id: a refused source never said what it calls itself. */\n id: string\n /** Why nothing from this source is on the return, as the return prints it. */\n reason: string\n }\n\nexport interface TaxReturnSource {\n /**\n * This plugin's sales for one period: one section, or one per kind of sale\n * it records apart (see the module note). May throw: the return refuses\n * the source rather than read a throw as nothing sold.\n */\n read(\n request: TaxReturnSourceRequest,\n ): Promise<TaxReturnSourceAnswer | readonly TaxReturnSourceAnswer[]>\n}\n\n/** Every source answers; one per plugin, with one section or several. */\nexport const TAX_RETURN_SOURCES = definePluginServiceContract<TaxReturnSource>(\n 'core.tax-return-sources',\n { multiple: true },\n)\n\n/**\n * Installs a plugin's source. Owner = the loader's marker inside a register\n * fn, else `options.pluginId`. Registering again replaces the plugin's\n * earlier source, so a module evaluated twice does not answer twice.\n */\nexport function registerTaxReturnSource(\n source: TaxReturnSource,\n options?: { pluginId?: string },\n): void {\n if (typeof source?.read !== 'function') {\n throw new Error('a tax return source needs a read function')\n }\n registerPluginService(TAX_RETURN_SOURCES, source, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\n/** The plugins with a registered source, in the order they answer. */\nexport function listTaxReturnSources(): string[] {\n return resolvePluginServices(TAX_RETURN_SOURCES).map((entry) => entry.pluginId)\n}\n\nconst isText = (value: unknown): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\nconst isCount = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/**\n * What is wrong with an answer, or null when it can be printed.\n *\n * Checked because the answer crosses a package boundary into a legal\n * document: a finding with a NaN count sums to NaN and the verdict reads\n * clean, and a missing array is a section that silently shows nothing.\n */\nfunction malformed(answer: TaxReturnSourceAnswer): string | null {\n if (!answer || typeof answer !== 'object') return 'no section'\n if (!isText(answer.id) || !isText(answer.name) || !isText(answer.title)) {\n return 'a section with no id, name or title'\n }\n if (typeof answer.truncated !== 'boolean') return 'no truncation flag'\n if (!isCount(answer.undatedRows)) return 'no count of undated rows'\n for (const key of ['findings', 'filingLines', 'tables', 'figures', 'exports', 'rows'] as const) {\n if (!Array.isArray(answer[key])) return `no ${key}`\n }\n const badFinding = answer.findings.find(\n (finding) =>\n !isText(finding?.id) ||\n (finding.severity !== 'blocking' && finding.severity !== 'review') ||\n !isCount(finding.count),\n )\n if (badFinding) return 'a finding with no id, severity or count'\n if (answer.operatorSales !== undefined) {\n if (!Array.isArray(answer.operatorSales)) return 'no list of its own sales'\n for (const part of answer.operatorSales) {\n if (!isText(part?.id) || !isText(part?.label)) return 'own sales with no id or label'\n if (!part.byJurisdiction || typeof part.byJurisdiction !== 'object' || Array.isArray(part.byJurisdiction)) {\n return 'own sales with no jurisdictions'\n }\n for (const figures of Object.values(part.byJurisdiction)) {\n // Whole cents and counts only: a fraction or a NaN folded into a\n // form item is a figure nobody can file.\n const bad = TAX_RETURN_OPERATOR_FIGURE_FIELDS.some(\n (field) => !isCount(figures?.[field]) || !Number.isInteger(figures[field]),\n )\n if (bad) return 'own sales with a figure that is not a whole number'\n }\n }\n }\n return null\n}\n\n/**\n * The operator's own sales every answered section states, as the platform\n * folds them: one row per part and jurisdiction, in the sections' order.\n */\nexport interface TaxReturnOperatorSalesRow extends TaxReturnOperatorFigures {\n pluginId: string\n partId: string\n label: string\n jurisdiction: string\n}\n\nexport function taxReturnOperatorSalesRows(\n sections: readonly TaxReturnSection[] | null | undefined,\n): TaxReturnOperatorSalesRow[] {\n const rows: TaxReturnOperatorSalesRow[] = []\n for (const section of sections ?? []) {\n if (section?.outcome !== 'answered') continue\n for (const part of section.operatorSales ?? []) {\n for (const [jurisdiction, figures] of Object.entries(part.byJurisdiction ?? {})) {\n rows.push({\n pluginId: section.pluginId,\n partId: part.id,\n label: part.label,\n jurisdiction,\n ...emptyTaxReturnOperatorFigures(),\n ...Object.fromEntries(\n TAX_RETURN_OPERATOR_FIGURE_FIELDS.map((field) => [field, Number(figures?.[field] ?? 0) || 0]),\n ),\n })\n }\n }\n }\n return rows\n}\n\n/**\n * The operator's own sales in ONE jurisdiction, summed over every part —\n * what the platform adds to its own figures for that jurisdiction.\n */\nexport function taxReturnOperatorSalesIn(\n sections: readonly TaxReturnSection[] | null | undefined,\n jurisdiction: string,\n): TaxReturnOperatorFigures {\n const total = emptyTaxReturnOperatorFigures()\n for (const row of taxReturnOperatorSalesRows(sections)) {\n if (row.jurisdiction !== jurisdiction) continue\n for (const field of TAX_RETURN_OPERATOR_FIGURE_FIELDS) total[field] += row[field]\n }\n return total\n}\n\n/**\n * Every source's answer for one period — declared sources first, in the\n * compiled order, then any other registered source in registration order.\n *\n * NEVER THROWS and never drops a declared source: a declared plugin with no\n * registration, a source that threw, and a malformed or duplicate answer\n * each come back as `outcome: 'refused'` with the sentence the return prints.\n * `declared` is the compiled {@link PLUGIN_TAX_RETURN_SOURCES} unless a spec\n * passes its own.\n */\nexport async function readTaxReturnSources(\n request: TaxReturnSourceRequest,\n declared: readonly string[] = PLUGIN_TAX_RETURN_SOURCES,\n): Promise<TaxReturnSection[]> {\n const registered = resolvePluginServices(TAX_RETURN_SOURCES)\n const order = [\n ...declared,\n ...registered\n .map((entry) => entry.pluginId)\n .filter((pluginId) => !declared.includes(pluginId)),\n ].filter((pluginId, index, all) => all.indexOf(pluginId) === index)\n\n const perPlugin = await Promise.all(\n order.map(async (pluginId): Promise<TaxReturnSection[]> => {\n const source = registered.find((entry) => entry.pluginId === pluginId)?.impl\n if (!source) {\n console.error(\n `[tax-return] \"${pluginId}\" declares a tax return source and none is ` +\n 'registered in this process; its sales cannot be read.',\n )\n return [\n {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason:\n `The “${pluginId}” plugin sells through the platform and registered ` +\n 'nothing to read its sales with.',\n },\n ]\n }\n try {\n const answered = await source.read(request)\n const sections: readonly TaxReturnSourceAnswer[] = Array.isArray(answered)\n ? answered\n : [answered as TaxReturnSourceAnswer]\n // All or nothing: a plugin that answered no section, or one section\n // the return cannot print, is refused whole, so a half-answered plugin\n // never reads as a complete one.\n const problem = sections.length\n ? sections.map(malformed).find((found) => found !== null)\n : 'no section'\n if (problem) {\n return [\n {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason: `The “${pluginId}” plugin answered ${problem}.`,\n },\n ]\n }\n return sections.map(\n (section): TaxReturnSection => ({ ...section, outcome: 'answered', pluginId }),\n )\n } catch (error) {\n console.error(`[tax-return] \"${pluginId}\" failed to read its sales`, error)\n return [\n {\n outcome: 'refused',\n pluginId,\n id: pluginId,\n reason: `The “${pluginId}” plugin could not read its sales for this period.`,\n },\n ]\n }\n }),\n )\n const answers = perPlugin.flat()\n\n // Two sources under one id would print two cards and one set of findings\n // under the same key, and a finding that names the wrong source's rows is\n // worse than none. The later one is refused, visibly.\n const seen = new Set<string>()\n // The same for the operator's own sales: a part id answered twice would be\n // folded into the filing figures twice.\n const seenParts = new Set<string>()\n return answers.map((section) => {\n if (section.outcome !== 'answered') return section\n if (seen.has(section.id)) {\n return {\n outcome: 'refused',\n pluginId: section.pluginId,\n id: section.pluginId,\n reason:\n `The “${section.pluginId}” plugin answered as “${section.id}”, which ` +\n 'another source already is.',\n }\n }\n const partIds = (section.operatorSales ?? []).map((part) => part.id)\n const repeated = partIds.find(\n (partId, index) => seenParts.has(partId) || partIds.indexOf(partId) !== index,\n )\n if (repeated) {\n return {\n outcome: 'refused',\n pluginId: section.pluginId,\n id: section.pluginId,\n reason:\n `The “${section.pluginId}” plugin stated its own sales as “${repeated}”, ` +\n 'which is already on the return.',\n }\n }\n seen.add(section.id)\n for (const partId of partIds) seenParts.add(partId)\n return section\n })\n}\n"],"names":["PLUGIN_TAX_RETURN_SOURCES","definePluginServiceContract","registerPluginService","resolvePluginServices","TAX_RETURN_OPERATOR_FIGURE_FIELDS","emptyTaxReturnOperatorFigures","transactionCount","totalSalesCents","taxableSalesCents","taxCollectedCents","refundCount","refundedSalesCents","refundedTaxCents","TAX_RETURN_SOURCES","multiple","registerTaxReturnSource","source","options","read","Error","pluginId","listTaxReturnSources","map","entry","isText","value","trim","length","isCount","Number","isFinite","malformed","answer","id","name","title","truncated","undatedRows","key","Array","isArray","badFinding","findings","find","finding","severity","count","operatorSales","undefined","part","label","byJurisdiction","figures","Object","values","bad","some","field","isInteger","taxReturnOperatorSalesRows","sections","rows","section","outcome","jurisdiction","entries","push","partId","fromEntries","taxReturnOperatorSalesIn","total","row","readTaxReturnSources","request","declared","registered","order","filter","includes","index","all","indexOf","perPlugin","Promise","impl","console","error","reason","answered","problem","found","answers","flat","seen","Set","seenParts","has","partIds","repeated","add"],"mappings":"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"}
|