@asturiu/v0-sdk 0.0.0-stage → 1.0.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.
Files changed (239) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.md +82 -2
  5. package/contract/assertion-vectors.json +90 -0
  6. package/contract/schemas/branding.schema.json +46 -0
  7. package/contract/schemas/definitions.schema.json +376 -0
  8. package/contract/schemas/portal.schema.json +56 -0
  9. package/contract/tenant-api-routes.json +165 -0
  10. package/dist/branding.d.ts +131 -0
  11. package/dist/branding.d.ts.map +1 -0
  12. package/dist/branding.js +206 -0
  13. package/dist/branding.js.map +1 -0
  14. package/dist/changesets.d.ts +58 -0
  15. package/dist/changesets.d.ts.map +1 -0
  16. package/dist/changesets.js +18 -0
  17. package/dist/changesets.js.map +1 -0
  18. package/dist/cli/bin.d.ts +3 -0
  19. package/dist/cli/bin.d.ts.map +1 -0
  20. package/dist/cli/bin.js +12 -0
  21. package/dist/cli/bin.js.map +1 -0
  22. package/dist/cli/changesets.d.ts +14 -0
  23. package/dist/cli/changesets.d.ts.map +1 -0
  24. package/dist/cli/changesets.js +252 -0
  25. package/dist/cli/changesets.js.map +1 -0
  26. package/dist/cli/cli.d.ts +37 -0
  27. package/dist/cli/cli.d.ts.map +1 -0
  28. package/dist/cli/cli.js +415 -0
  29. package/dist/cli/cli.js.map +1 -0
  30. package/dist/cli/context.d.ts +147 -0
  31. package/dist/cli/context.d.ts.map +1 -0
  32. package/dist/cli/context.js +258 -0
  33. package/dist/cli/context.js.map +1 -0
  34. package/dist/cli/engine.d.ts +59 -0
  35. package/dist/cli/engine.d.ts.map +1 -0
  36. package/dist/cli/engine.js +85 -0
  37. package/dist/cli/engine.js.map +1 -0
  38. package/dist/cli/feedback.d.ts +40 -0
  39. package/dist/cli/feedback.d.ts.map +1 -0
  40. package/dist/cli/feedback.js +420 -0
  41. package/dist/cli/feedback.js.map +1 -0
  42. package/dist/cli/files.d.ts +83 -0
  43. package/dist/cli/files.d.ts.map +1 -0
  44. package/dist/cli/files.js +389 -0
  45. package/dist/cli/files.js.map +1 -0
  46. package/dist/cli/index.d.ts +8 -0
  47. package/dist/cli/index.d.ts.map +1 -0
  48. package/dist/cli/index.js +8 -0
  49. package/dist/cli/index.js.map +1 -0
  50. package/dist/cli/overview.d.ts +6 -0
  51. package/dist/cli/overview.d.ts.map +1 -0
  52. package/dist/cli/overview.js +379 -0
  53. package/dist/cli/overview.js.map +1 -0
  54. package/dist/cli/parts.d.ts +5 -0
  55. package/dist/cli/parts.d.ts.map +1 -0
  56. package/dist/cli/parts.js +414 -0
  57. package/dist/cli/parts.js.map +1 -0
  58. package/dist/cli/sources.d.ts +37 -0
  59. package/dist/cli/sources.d.ts.map +1 -0
  60. package/dist/cli/sources.js +91 -0
  61. package/dist/cli/sources.js.map +1 -0
  62. package/dist/cli/terminal.d.ts +135 -0
  63. package/dist/cli/terminal.d.ts.map +1 -0
  64. package/dist/cli/terminal.js +353 -0
  65. package/dist/cli/terminal.js.map +1 -0
  66. package/dist/cli/ui-page.d.ts +8 -0
  67. package/dist/cli/ui-page.d.ts.map +1 -0
  68. package/dist/cli/ui-page.js +216 -0
  69. package/dist/cli/ui-page.js.map +1 -0
  70. package/dist/cli/ui.d.ts +54 -0
  71. package/dist/cli/ui.d.ts.map +1 -0
  72. package/dist/cli/ui.js +251 -0
  73. package/dist/cli/ui.js.map +1 -0
  74. package/dist/client.d.ts +88 -0
  75. package/dist/client.d.ts.map +1 -0
  76. package/dist/client.js +165 -0
  77. package/dist/client.js.map +1 -0
  78. package/dist/contacts.d.ts +43 -0
  79. package/dist/contacts.d.ts.map +1 -0
  80. package/dist/contacts.js +46 -0
  81. package/dist/contacts.js.map +1 -0
  82. package/dist/definition-set.d.ts +731 -0
  83. package/dist/definition-set.d.ts.map +1 -0
  84. package/dist/definition-set.js +659 -0
  85. package/dist/definition-set.js.map +1 -0
  86. package/dist/definitions.d.ts +42 -0
  87. package/dist/definitions.d.ts.map +1 -0
  88. package/dist/definitions.js +154 -0
  89. package/dist/definitions.js.map +1 -0
  90. package/dist/enrolment.d.ts +9 -0
  91. package/dist/enrolment.d.ts.map +1 -0
  92. package/dist/enrolment.js +8 -0
  93. package/dist/enrolment.js.map +1 -0
  94. package/dist/fill.d.ts +73 -0
  95. package/dist/fill.d.ts.map +1 -0
  96. package/dist/fill.js +46 -0
  97. package/dist/fill.js.map +1 -0
  98. package/dist/index.d.ts +39 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +39 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/notifications.d.ts +33 -0
  103. package/dist/notifications.d.ts.map +1 -0
  104. package/dist/notifications.js +36 -0
  105. package/dist/notifications.js.map +1 -0
  106. package/dist/oidc.d.ts +122 -0
  107. package/dist/oidc.d.ts.map +1 -0
  108. package/dist/oidc.js +150 -0
  109. package/dist/oidc.js.map +1 -0
  110. package/dist/overlay.d.ts +109 -0
  111. package/dist/overlay.d.ts.map +1 -0
  112. package/dist/overlay.js +58 -0
  113. package/dist/overlay.js.map +1 -0
  114. package/dist/passes.d.ts +95 -0
  115. package/dist/passes.d.ts.map +1 -0
  116. package/dist/passes.js +140 -0
  117. package/dist/passes.js.map +1 -0
  118. package/dist/portal-options.d.ts +65 -0
  119. package/dist/portal-options.d.ts.map +1 -0
  120. package/dist/portal-options.js +120 -0
  121. package/dist/portal-options.js.map +1 -0
  122. package/dist/reads.d.ts +41 -0
  123. package/dist/reads.d.ts.map +1 -0
  124. package/dist/reads.js +44 -0
  125. package/dist/reads.js.map +1 -0
  126. package/dist/recovery-words.d.ts +8 -0
  127. package/dist/recovery-words.d.ts.map +1 -0
  128. package/dist/recovery-words.js +136 -0
  129. package/dist/recovery-words.js.map +1 -0
  130. package/dist/recovery.d.ts +198 -0
  131. package/dist/recovery.d.ts.map +1 -0
  132. package/dist/recovery.js +112 -0
  133. package/dist/recovery.js.map +1 -0
  134. package/dist/reveal.d.ts +35 -0
  135. package/dist/reveal.d.ts.map +1 -0
  136. package/dist/reveal.js +66 -0
  137. package/dist/reveal.js.map +1 -0
  138. package/dist/seal.d.ts +15 -0
  139. package/dist/seal.d.ts.map +1 -0
  140. package/dist/seal.js +0 -0
  141. package/dist/seal.js.map +1 -0
  142. package/dist/session.d.ts +66 -0
  143. package/dist/session.d.ts.map +1 -0
  144. package/dist/session.js +61 -0
  145. package/dist/session.js.map +1 -0
  146. package/dist/signing-in-mark.d.ts +14 -0
  147. package/dist/signing-in-mark.d.ts.map +1 -0
  148. package/dist/signing-in-mark.js +24 -0
  149. package/dist/signing-in-mark.js.map +1 -0
  150. package/dist/signing-in.d.ts +22 -0
  151. package/dist/signing-in.d.ts.map +1 -0
  152. package/dist/signing-in.js +203 -0
  153. package/dist/signing-in.js.map +1 -0
  154. package/dist/tags.d.ts +96 -0
  155. package/dist/tags.d.ts.map +1 -0
  156. package/dist/tags.js +88 -0
  157. package/dist/tags.js.map +1 -0
  158. package/dist/tenant-subscription.d.ts +47 -0
  159. package/dist/tenant-subscription.d.ts.map +1 -0
  160. package/dist/tenant-subscription.js +7 -0
  161. package/dist/tenant-subscription.js.map +1 -0
  162. package/dist/testing/index.d.ts +125 -0
  163. package/dist/testing/index.d.ts.map +1 -0
  164. package/dist/testing/index.js +320 -0
  165. package/dist/testing/index.js.map +1 -0
  166. package/dist/theme.d.ts +237 -0
  167. package/dist/theme.d.ts.map +1 -0
  168. package/dist/theme.js +504 -0
  169. package/dist/theme.js.map +1 -0
  170. package/dist/tickets.d.ts +152 -0
  171. package/dist/tickets.d.ts.map +1 -0
  172. package/dist/tickets.js +65 -0
  173. package/dist/tickets.js.map +1 -0
  174. package/dist/tiers.d.ts +168 -0
  175. package/dist/tiers.d.ts.map +1 -0
  176. package/dist/tiers.js +341 -0
  177. package/dist/tiers.js.map +1 -0
  178. package/dist/types.d.ts +885 -0
  179. package/dist/types.d.ts.map +1 -0
  180. package/dist/types.js +12 -0
  181. package/dist/types.js.map +1 -0
  182. package/dist/urlid.d.ts +50 -0
  183. package/dist/urlid.d.ts.map +1 -0
  184. package/dist/urlid.js +78 -0
  185. package/dist/urlid.js.map +1 -0
  186. package/dist/version.d.ts +15 -0
  187. package/dist/version.d.ts.map +1 -0
  188. package/dist/version.js +15 -0
  189. package/dist/version.js.map +1 -0
  190. package/make/asturiu.mk +43 -0
  191. package/package.json +63 -4
  192. package/src/branding.ts +221 -0
  193. package/src/changesets.ts +61 -0
  194. package/src/cli/bin.ts +12 -0
  195. package/src/cli/changesets.ts +233 -0
  196. package/src/cli/cli.ts +425 -0
  197. package/src/cli/context.ts +299 -0
  198. package/src/cli/engine.ts +112 -0
  199. package/src/cli/feedback.ts +406 -0
  200. package/src/cli/files.ts +371 -0
  201. package/src/cli/index.ts +7 -0
  202. package/src/cli/overview.ts +343 -0
  203. package/src/cli/parts.ts +371 -0
  204. package/src/cli/sources.ts +111 -0
  205. package/src/cli/terminal.ts +384 -0
  206. package/src/cli/ui-page.ts +215 -0
  207. package/src/cli/ui.ts +266 -0
  208. package/src/client.ts +202 -0
  209. package/src/contacts.ts +61 -0
  210. package/src/definition-set.ts +965 -0
  211. package/src/definitions.ts +156 -0
  212. package/src/enrolment.ts +10 -0
  213. package/src/fill.ts +83 -0
  214. package/src/index.ts +38 -0
  215. package/src/notifications.ts +55 -0
  216. package/src/oidc.ts +199 -0
  217. package/src/overlay.ts +137 -0
  218. package/src/passes.ts +168 -0
  219. package/src/portal-options.ts +125 -0
  220. package/src/reads.ts +71 -0
  221. package/src/recovery-words.ts +137 -0
  222. package/src/recovery.ts +269 -0
  223. package/src/reveal.ts +72 -0
  224. package/src/seal.ts +0 -0
  225. package/src/session.ts +93 -0
  226. package/src/signing-in-mark.ts +23 -0
  227. package/src/signing-in.ts +213 -0
  228. package/src/tags.ts +146 -0
  229. package/src/tenant-subscription.ts +44 -0
  230. package/src/testing/index.ts +337 -0
  231. package/src/theme.ts +628 -0
  232. package/src/tickets.ts +195 -0
  233. package/src/tiers.ts +397 -0
  234. package/src/types.ts +847 -0
  235. package/src/urlid.ts +77 -0
  236. package/src/version.ts +15 -0
  237. package/templates/asturiu/branding.json +4 -0
  238. package/templates/asturiu/definitions.json +23 -0
  239. package/templates/asturiu/portal.json +16 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * What a Tenant's repository may set of its branding and portal options, and
3
+ * the rule for branding images (ADR-038, ADR-039). Pure and dependency-free:
4
+ * the Engine checks writes with these, the Admin UI and a Tenant's
5
+ * application prepare them.
6
+ */
7
+ import { type PortalOptions, type PortalPage, type PortalSwitch } from "./portal-options.js";
8
+ import type { PortalThemeSpec } from "./theme.js";
9
+ /** Who edits a tab: a person in the Admin UI, or the Tenant's application (ADR-038, decision 3). */
10
+ export declare const TENANT_SOURCES: readonly ["admin_ui", "repository"];
11
+ export type TenantSource = (typeof TENANT_SOURCES)[number];
12
+ export interface TenantSources {
13
+ branding: TenantSource;
14
+ portal: TenantSource;
15
+ /** ADR-061 §10. */
16
+ tiers: TenantSource;
17
+ }
18
+ /** A Tenant's sources, `admin_ui` where unset or unreadable. */
19
+ export declare function tenantSourcesOf(raw: {
20
+ sources?: unknown;
21
+ } | null | undefined): TenantSources;
22
+ /**
23
+ * The branding keys a repository sets (ADR-038, decision 2). Everything else
24
+ * — `portal_url`, `product_url`, `app_url`, `billing_url`, the support
25
+ * addresses — decides where a customer is sent and stays with an administrator.
26
+ */
27
+ export declare const BRANDING_REPOSITORY_KEYS: readonly ["theme", "primary_color", "logo_url", "logo_dark_url", "favicon_url"];
28
+ export type BrandingRepositoryKey = (typeof BRANDING_REPOSITORY_KEYS)[number];
29
+ /**
30
+ * What `PUT /tenant/v0/branding` takes and `GET /tenant/v0/branding` answers:
31
+ * the whole look of the portal, as the Admin UI's Branding tab edits it, and
32
+ * no address. A key left out of a `PUT` is cleared.
33
+ */
34
+ export interface RepositoryBranding {
35
+ /** The portal theme (ADR-033): a preset and overrides from the kit's closed lists (`THEME_*`). */
36
+ theme?: PortalThemeSpec;
37
+ /** `#rrggbb`. Used only while no theme is set. */
38
+ primary_color?: string;
39
+ /** Inline images (`inlineImage(bytes, type)`), at most `INLINE_IMAGE_MAX_BYTES` each. */
40
+ logo_url?: string;
41
+ /** The logo drawn on dark backgrounds. */
42
+ logo_dark_url?: string;
43
+ favicon_url?: string;
44
+ }
45
+ /**
46
+ * The page modes a repository sets (ADR-039): whether a page shows. A
47
+ * `redirect` carries the address a customer is sent to and stays with an
48
+ * administrator.
49
+ */
50
+ export declare const PORTAL_REPOSITORY_PAGE_MODES: readonly ["portal", "off"];
51
+ export type PortalRepositoryPageMode = (typeof PORTAL_REPOSITORY_PAGE_MODES)[number];
52
+ /**
53
+ * What `PUT /tenant/v0/portal` takes: every switch (one left out is on) and
54
+ * which pages show (one left out is back to its default). A page an administrator
55
+ * moved to the Tenant's application keeps its redirect.
56
+ */
57
+ export type RepositoryPortal = Partial<Record<PortalSwitch, boolean>> & {
58
+ pages?: Partial<Record<PortalPage, {
59
+ mode: PortalRepositoryPageMode;
60
+ }>>;
61
+ };
62
+ /** The portal options a repository sets: the switches and which pages show. Redirects and their URLs stay with an administrator. */
63
+ export declare const PORTAL_REPOSITORY_KEYS: readonly ["account_link", "open_app", "back_link", "language_menu", "appearance", "pages"];
64
+ /**
65
+ * The repository's part of a stored branding, as `GET /tenant/v0/branding`
66
+ * answers it and `PUT` takes it back: the theme, the colour and the images,
67
+ * images only when inline (a link stored before ADR-038 is not shown anyway).
68
+ */
69
+ export declare function repositoryBrandingOf(branding: unknown): RepositoryBranding;
70
+ /**
71
+ * The repository's part of stored portal options, as `GET /tenant/v0/portal`
72
+ * answers it: every switch, every page that is not redirected, and the pages
73
+ * an administrator moved to the Tenant's application (without their URLs).
74
+ */
75
+ export declare function repositoryPortalOf(portal: unknown, ctx?: {
76
+ collection?: string;
77
+ }): {
78
+ portal: Record<PortalSwitch, boolean> & {
79
+ pages: Partial<Record<PortalPage, {
80
+ mode: PortalRepositoryPageMode;
81
+ }>>;
82
+ };
83
+ redirected: PortalPage[];
84
+ };
85
+ /**
86
+ * A repository's portal options over the stored ones (ADR-039): the switches
87
+ * and page modes it sends replace the stored ones, one left out is back to
88
+ * its default, and a page an administrator redirected keeps its redirect
89
+ * (`kept`, when the body names it). `problems` are what the body may not
90
+ * hold, each with its path; the record's own rules (security and privacy
91
+ * never off, plan not off while the platform bills) are the Tenant schema's.
92
+ */
93
+ export declare function mergeRepositoryPortal(stored: unknown, body: Record<string, unknown>): {
94
+ portal: Record<string, unknown>;
95
+ kept: PortalPage[];
96
+ problems: {
97
+ path: string;
98
+ message: string;
99
+ }[];
100
+ };
101
+ /**
102
+ * Pages an administrator may not change while the Portal tab comes from the
103
+ * repository (ADR-039): an administrator moves a page to the Tenant's
104
+ * application, or brings a redirected page back to the portal; whether a page
105
+ * that is not redirected shows is the repository's.
106
+ */
107
+ export declare function adminPageConflicts(stored: PortalOptions, patchPages: unknown): PortalPage[];
108
+ /** Every image in `branding`, as a path into it (ADR-038, decision 6). */
109
+ export declare const BRANDING_IMAGE_PATHS: readonly [readonly ["logo_url"], readonly ["logo_dark_url"], readonly ["favicon_url"], readonly ["theme", "background", "image_url"], readonly ["theme", "sign_in", "image_url"]];
110
+ /** An inline base64 image of a type a browser shows in `<img>` and CSS. */
111
+ export declare const INLINE_IMAGE_PATTERN: RegExp;
112
+ export declare const INLINE_IMAGE_TYPES: readonly ["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon"];
113
+ /** The most an image may weigh, decoded. */
114
+ export declare const INLINE_IMAGE_MAX_BYTES: number;
115
+ /** The decoded size of an inline image, or null when the value is not one. */
116
+ export declare function inlineImageBytes(v: unknown): number | null;
117
+ /** The MIME type of an inline image, or null. */
118
+ export declare function inlineImageType(v: unknown): string | null;
119
+ /** An image file as the inline value `branding` takes: `inlineImage(await readFile("brand/logo.png"), "image/png")`. */
120
+ export declare function inlineImage(bytes: Uint8Array, type: string): string;
121
+ /**
122
+ * Images that break the rule: every image is inline and at most
123
+ * `INLINE_IMAGE_MAX_BYTES`, so the portal serves it from its own host and no
124
+ * other host sees who opens a portal page. A URL or a path on the Tenant's
125
+ * site is refused when it is written.
126
+ */
127
+ export declare function brandingImageProblems(branding: unknown): {
128
+ path: string[];
129
+ message: string;
130
+ }[];
131
+ //# sourceMappingURL=branding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../src/branding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * What a Tenant's repository may set of its branding and portal options, and
3
+ * the rule for branding images (ADR-038, ADR-039). Pure and dependency-free:
4
+ * the Engine checks writes with these, the Admin UI and a Tenant's
5
+ * application prepare them.
6
+ */
7
+ import { PORTAL_PAGES, PORTAL_SWITCHES, defaultPortalOptions, resolvePortalOptions } from "./portal-options.js";
8
+ /** Who edits a tab: a person in the Admin UI, or the Tenant's application (ADR-038, decision 3). */
9
+ export const TENANT_SOURCES = ["admin_ui", "repository"];
10
+ /** A Tenant's sources, `admin_ui` where unset or unreadable. */
11
+ export function tenantSourcesOf(raw) {
12
+ const s = raw?.sources && typeof raw.sources === "object" ? raw.sources : {};
13
+ const one = (v) => (v === "repository" ? "repository" : "admin_ui");
14
+ return { branding: one(s.branding), portal: one(s.portal), tiers: one(s.tiers) };
15
+ }
16
+ /**
17
+ * The branding keys a repository sets (ADR-038, decision 2). Everything else
18
+ * — `portal_url`, `product_url`, `app_url`, `billing_url`, the support
19
+ * addresses — decides where a customer is sent and stays with an administrator.
20
+ */
21
+ export const BRANDING_REPOSITORY_KEYS = ["theme", "primary_color", "logo_url", "logo_dark_url", "favicon_url"];
22
+ /**
23
+ * The page modes a repository sets (ADR-039): whether a page shows. A
24
+ * `redirect` carries the address a customer is sent to and stays with an
25
+ * administrator.
26
+ */
27
+ export const PORTAL_REPOSITORY_PAGE_MODES = ["portal", "off"];
28
+ /** The portal options a repository sets: the switches and which pages show. Redirects and their URLs stay with an administrator. */
29
+ export const PORTAL_REPOSITORY_KEYS = [...PORTAL_SWITCHES, "pages"];
30
+ const isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
31
+ /**
32
+ * The repository's part of a stored branding, as `GET /tenant/v0/branding`
33
+ * answers it and `PUT` takes it back: the theme, the colour and the images,
34
+ * images only when inline (a link stored before ADR-038 is not shown anyway).
35
+ */
36
+ export function repositoryBrandingOf(branding) {
37
+ const b = isObj(branding) ? branding : {};
38
+ const out = {};
39
+ if (isObj(b.theme) && Object.keys(b.theme).length) {
40
+ const theme = JSON.parse(JSON.stringify(b.theme));
41
+ for (const part of ["background", "sign_in"]) {
42
+ const p = theme[part];
43
+ if (!isObj(p))
44
+ continue;
45
+ if (p.image_url !== undefined && inlineImageBytes(p.image_url) === null)
46
+ delete p.image_url;
47
+ if (!Object.keys(p).length)
48
+ delete theme[part];
49
+ }
50
+ if (Object.keys(theme).length)
51
+ out.theme = theme;
52
+ }
53
+ if (typeof b.primary_color === "string" && b.primary_color)
54
+ out.primary_color = b.primary_color;
55
+ for (const k of ["logo_url", "logo_dark_url", "favicon_url"])
56
+ if (inlineImageBytes(b[k]) !== null)
57
+ out[k] = b[k];
58
+ return out;
59
+ }
60
+ /**
61
+ * The repository's part of stored portal options, as `GET /tenant/v0/portal`
62
+ * answers it: every switch, every page that is not redirected, and the pages
63
+ * an administrator moved to the Tenant's application (without their URLs).
64
+ */
65
+ export function repositoryPortalOf(portal, ctx = {}) {
66
+ const o = resolvePortalOptions(portal, ctx);
67
+ const pages = {};
68
+ const redirected = [];
69
+ for (const p of PORTAL_PAGES) {
70
+ const mode = o.pages[p].mode;
71
+ if (mode === "redirect")
72
+ redirected.push(p);
73
+ else
74
+ pages[p] = { mode };
75
+ }
76
+ const switches = Object.fromEntries(PORTAL_SWITCHES.map((k) => [k, o[k]]));
77
+ return { portal: { ...switches, pages }, redirected };
78
+ }
79
+ /**
80
+ * A repository's portal options over the stored ones (ADR-039): the switches
81
+ * and page modes it sends replace the stored ones, one left out is back to
82
+ * its default, and a page an administrator redirected keeps its redirect
83
+ * (`kept`, when the body names it). `problems` are what the body may not
84
+ * hold, each with its path; the record's own rules (security and privacy
85
+ * never off, plan not off while the platform bills) are the Tenant schema's.
86
+ */
87
+ export function mergeRepositoryPortal(stored, body) {
88
+ const problems = [];
89
+ for (const k of Object.keys(body))
90
+ if (!PORTAL_REPOSITORY_KEYS.includes(k))
91
+ problems.push({ path: `portal.${k}`, message: `set in the Admin UI, not from a repository; accepted here: ${PORTAL_REPOSITORY_KEYS.join(", ")}` });
92
+ for (const k of PORTAL_SWITCHES)
93
+ if (k in body && typeof body[k] !== "boolean")
94
+ problems.push({ path: `portal.${k}`, message: "must be true or false" });
95
+ const s = isObj(stored) ? stored : {};
96
+ const storedPages = isObj(s.pages) ? s.pages : {};
97
+ if (body.pages !== undefined && !isObj(body.pages))
98
+ problems.push({ path: "portal.pages", message: "an object with a { mode } per page" });
99
+ const wanted = isObj(body.pages) ? body.pages : {};
100
+ for (const p of Object.keys(wanted))
101
+ if (!PORTAL_PAGES.includes(p))
102
+ problems.push({ path: `portal.pages.${p}`, message: `not a page; the pages are ${PORTAL_PAGES.join(", ")}` });
103
+ const pages = {};
104
+ const kept = [];
105
+ const defaults = defaultPortalOptions().pages;
106
+ for (const p of PORTAL_PAGES) {
107
+ const w = wanted[p];
108
+ let mode = defaults[p].mode === "off" ? "off" : "portal";
109
+ if (w !== undefined) {
110
+ if (!isObj(w) || Object.keys(w).some((k) => k !== "mode"))
111
+ problems.push({ path: `portal.pages.${p}`, message: "must be { mode: portal | off }; a URL is set by an administrator" });
112
+ else if (w.mode === "redirect")
113
+ problems.push({ path: `portal.pages.${p}.mode`, message: "moving a page to the Tenant's application takes its address, which an administrator sets in the Admin UI" });
114
+ else if (!PORTAL_REPOSITORY_PAGE_MODES.includes(w.mode))
115
+ problems.push({ path: `portal.pages.${p}.mode`, message: "must be portal or off" });
116
+ else
117
+ mode = w.mode;
118
+ }
119
+ const st = storedPages[p];
120
+ if (isObj(st) && st.mode === "redirect") {
121
+ pages[p] = st;
122
+ if (w !== undefined)
123
+ kept.push(p);
124
+ }
125
+ else
126
+ pages[p] = { mode };
127
+ }
128
+ const rest = Object.fromEntries(Object.entries(s).filter(([k]) => !PORTAL_REPOSITORY_KEYS.includes(k)));
129
+ const switches = Object.fromEntries(PORTAL_SWITCHES.filter((k) => typeof body[k] === "boolean").map((k) => [k, body[k]]));
130
+ return { portal: { ...rest, ...switches, pages }, kept, problems };
131
+ }
132
+ /**
133
+ * Pages an administrator may not change while the Portal tab comes from the
134
+ * repository (ADR-039): an administrator moves a page to the Tenant's
135
+ * application, or brings a redirected page back to the portal; whether a page
136
+ * that is not redirected shows is the repository's.
137
+ */
138
+ export function adminPageConflicts(stored, patchPages) {
139
+ if (!isObj(patchPages))
140
+ return [];
141
+ const out = [];
142
+ for (const p of PORTAL_PAGES) {
143
+ const w = patchPages[p];
144
+ if (!isObj(w))
145
+ continue;
146
+ const from = stored.pages[p].mode;
147
+ if (w.mode === "redirect" || (from === "redirect" && w.mode === "portal"))
148
+ continue;
149
+ if (w.mode !== from)
150
+ out.push(p);
151
+ }
152
+ return out;
153
+ }
154
+ /** Every image in `branding`, as a path into it (ADR-038, decision 6). */
155
+ export const BRANDING_IMAGE_PATHS = [["logo_url"], ["logo_dark_url"], ["favicon_url"], ["theme", "background", "image_url"], ["theme", "sign_in", "image_url"]];
156
+ /** An inline base64 image of a type a browser shows in `<img>` and CSS. */
157
+ export const INLINE_IMAGE_PATTERN = /^data:image\/(png|jpeg|gif|webp|svg\+xml|x-icon|vnd\.microsoft\.icon);base64,[A-Za-z0-9+/]+={0,2}$/;
158
+ export const INLINE_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon"];
159
+ /** The most an image may weigh, decoded. */
160
+ export const INLINE_IMAGE_MAX_BYTES = 256 * 1024;
161
+ /** The decoded size of an inline image, or null when the value is not one. */
162
+ export function inlineImageBytes(v) {
163
+ if (typeof v !== "string" || !INLINE_IMAGE_PATTERN.test(v))
164
+ return null;
165
+ const data = v.slice(v.indexOf(",") + 1);
166
+ const pad = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
167
+ return Math.floor((data.length * 3) / 4) - pad;
168
+ }
169
+ /** The MIME type of an inline image, or null. */
170
+ export function inlineImageType(v) {
171
+ return typeof v === "string" && INLINE_IMAGE_PATTERN.test(v) ? v.slice(5, v.indexOf(";")) : null;
172
+ }
173
+ /** An image file as the inline value `branding` takes: `inlineImage(await readFile("brand/logo.png"), "image/png")`. */
174
+ export function inlineImage(bytes, type) {
175
+ if (!INLINE_IMAGE_TYPES.includes(type))
176
+ throw new Error(`an image of type ${type} is not accepted; use one of ${INLINE_IMAGE_TYPES.join(", ")}`);
177
+ let bin = "";
178
+ for (let i = 0; i < bytes.length; i += 0x8000)
179
+ bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
180
+ return `data:${type};base64,${btoa(bin)}`;
181
+ }
182
+ /**
183
+ * Images that break the rule: every image is inline and at most
184
+ * `INLINE_IMAGE_MAX_BYTES`, so the portal serves it from its own host and no
185
+ * other host sees who opens a portal page. A URL or a path on the Tenant's
186
+ * site is refused when it is written.
187
+ */
188
+ export function brandingImageProblems(branding) {
189
+ if (!branding || typeof branding !== "object")
190
+ return [];
191
+ const out = [];
192
+ for (const path of BRANDING_IMAGE_PATHS) {
193
+ let v = branding;
194
+ for (const k of path)
195
+ v = v && typeof v === "object" ? v[k] : undefined;
196
+ if (v === undefined || v === null || v === "")
197
+ continue;
198
+ const bytes = inlineImageBytes(v);
199
+ if (bytes === null)
200
+ out.push({ path: [...path], message: "must be an inline base64 image (data:image/png;base64,…); a URL or a path on the Tenant's site is not accepted (ADR-038)" });
201
+ else if (bytes > INLINE_IMAGE_MAX_BYTES)
202
+ out.push({ path: [...path], message: `must be at most ${INLINE_IMAGE_MAX_BYTES / 1024} KB; this one is ${Math.ceil(bytes / 1024)} KB` });
203
+ }
204
+ return out;
205
+ }
206
+ //# sourceMappingURL=branding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branding.js","sourceRoot":"","sources":["../src/branding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Tenant changesets (ADR-054 §7, ADR-059 §2, ADR-074 §9): what changed on the
3
+ * Tenant-facing surface, Engine release by Engine release. The documents are
4
+ * the Engine's: published on the Engine site and listed by
5
+ * `GET /tenant/v0/changesets`. The SDK carries none of them, only the shape of
6
+ * the answer, so an SDK installed months ago never holds a stale list.
7
+ */
8
+ export interface ChangesetEntry {
9
+ number: number;
10
+ slug: string;
11
+ /** `<nnn>-<slug>.md`, under `/changesets/` on the Engine site. */
12
+ file: string;
13
+ date: string;
14
+ title: string;
15
+ /** What it applies to, as the document's header says it. */
16
+ applies_to: string;
17
+ /** The Engine decisions it follows from (`ADR-058`). */
18
+ decisions: string[];
19
+ /** Whether a Tenant may have to act: anything but a plain "No" in the header. */
20
+ action_required: boolean;
21
+ /** From when the old behaviour is gone, a date or an Engine version, when the change comes with a window. */
22
+ deadline: string | null;
23
+ /** The first SDK release that carries the change (ADR-074 §4); null for "No SDK change" or a changeset from before the row. */
24
+ sdk_version: string | null;
25
+ }
26
+ /** A changeset's status for one Tenant: its ticket's (ADR-059 §2). */
27
+ export declare const CHANGESET_STATUSES: readonly ["new", "acknowledged", "in_progress", "on_hold", "resolved", "canceled"];
28
+ export type ChangesetStatus = (typeof CHANGESET_STATUSES)[number];
29
+ /** One changeset as a Tenant reads it from `GET /tenant/v0/changesets`: the entry, its address, and this Tenant's ticket when it has one. */
30
+ export interface TenantChangeset extends ChangesetEntry {
31
+ url: string | null;
32
+ ticket: string | null;
33
+ status: ChangesetStatus | null;
34
+ }
35
+ /** The published document's address on the Engine site, or null when the site is not configured. */
36
+ export declare function changesetUrl(site: string | null | undefined, c: Pick<ChangesetEntry, "file">): string | null;
37
+ /** The Tenant's feedback (ADR-054 §7, ADR-059 §3): what the agent sends when the Engine cannot do what the application needs. */
38
+ export declare const FEEDBACK_KINDS: readonly ["limitation", "defect", "question"];
39
+ export type FeedbackKind = (typeof FEEDBACK_KINDS)[number];
40
+ /** The platform's ticket type each feedback kind opens (ADR-058 §3). */
41
+ export declare const FEEDBACK_TYPE: Record<FeedbackKind, "engine_limitation" | "engine_defect" | "engine_question">;
42
+ export interface FeedbackReport {
43
+ kind: FeedbackKind;
44
+ area: string;
45
+ summary: string;
46
+ detail: string;
47
+ context: {
48
+ engine?: string;
49
+ changeset?: number | null;
50
+ skill?: string;
51
+ };
52
+ refusal?: {
53
+ status: number;
54
+ type?: string;
55
+ detail?: string;
56
+ };
57
+ }
58
+ //# sourceMappingURL=changesets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changesets.d.ts","sourceRoot":"","sources":["../src/changesets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iFAAiF;IACjF,eAAe,EAAE,OAAO,CAAC;IACzB,6GAA6G;IAC7G,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,+HAA+H;IAC/H,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,oFAAqF,CAAC;AAErH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,6IAA6I;AAC7I,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CAChC;AAED,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAE5G;AAED,iIAAiI;AACjI,eAAO,MAAM,cAAc,+CAAgD,CAAC;AAE5E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,wEAAwE;AACxE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,mBAAmB,GAAG,eAAe,GAAG,iBAAiB,CAA6F,CAAC;AAExM,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Tenant changesets (ADR-054 §7, ADR-059 §2, ADR-074 §9): what changed on the
3
+ * Tenant-facing surface, Engine release by Engine release. The documents are
4
+ * the Engine's: published on the Engine site and listed by
5
+ * `GET /tenant/v0/changesets`. The SDK carries none of them, only the shape of
6
+ * the answer, so an SDK installed months ago never holds a stale list.
7
+ */
8
+ /** A changeset's status for one Tenant: its ticket's (ADR-059 §2). */
9
+ export const CHANGESET_STATUSES = ["new", "acknowledged", "in_progress", "on_hold", "resolved", "canceled"];
10
+ /** The published document's address on the Engine site, or null when the site is not configured. */
11
+ export function changesetUrl(site, c) {
12
+ return site ? `${site.replace(/\/+$/, "")}/changesets/${c.file}` : null;
13
+ }
14
+ /** The Tenant's feedback (ADR-054 §7, ADR-059 §3): what the agent sends when the Engine cannot do what the application needs. */
15
+ export const FEEDBACK_KINDS = ["limitation", "defect", "question"];
16
+ /** The platform's ticket type each feedback kind opens (ADR-058 §3). */
17
+ export const FEEDBACK_TYPE = { limitation: "engine_limitation", defect: "engine_defect", question: "engine_question" };
18
+ //# sourceMappingURL=changesets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changesets.js","sourceRoot":"","sources":["../src/changesets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH,sEAAsE;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AAWrH,oGAAoG;AACpG,MAAM,UAAU,YAAY,CAAC,IAA+B,EAAE,CAA+B;IAC3F,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,iIAAiI;AACjI,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAU,CAAC;AAI5E,wEAAwE;AACxE,MAAM,CAAC,MAAM,aAAa,GAAoF,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The `asturiu-v0-tenant` command (ADR-074 §5). Run it through the repository's package script
4
+ * (`"asturiu": "asturiu-v0-tenant"`) or `npx --no-install asturiu-v0-tenant`: never plain `npx`, which would fetch
5
+ * whatever the registry holds under that name when the SDK is not installed.
6
+ */
7
+ import { run } from "./cli.js";
8
+ // A closed pipe (`… | head`) ends the run quietly.
9
+ for (const stream of [process.stdout, process.stderr])
10
+ stream.on("error", (e) => (e.code === "EPIPE" ? process.exit(0) : undefined));
11
+ process.exitCode = await run(process.argv.slice(2));
12
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,mDAAmD;AACnD,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;IAAE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAwB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAE5J,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type Ctx } from "./context.js";
2
+ /**
3
+ * The prompt for the Tenant's coding agent, as a changeset document writes it: the first fenced block under the
4
+ * heading "Prompt for your coding agent". Text to show the person, never to run.
5
+ */
6
+ export declare function promptOf(document: string): string | null;
7
+ /** The pulled document of a changeset, with its prompt, when the repository has it. */
8
+ export declare function pulledDocument(ctx: Ctx, file: string): {
9
+ path: string;
10
+ prompt: string | null;
11
+ } | null;
12
+ export declare function cmdChangesets(ctx: Ctx, args: string[]): Promise<void>;
13
+ export declare function cmdChangeset(ctx: Ctx, args: string[]): Promise<void>;
14
+ //# sourceMappingURL=changesets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changesets.d.ts","sourceRoot":"","sources":["../../src/cli/changesets.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,GAAG,EAA0H,MAAM,cAAc,CAAC;AAYhK;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASxD;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAIrG;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,iBAiD3D;AA0CD,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,iBAK1D"}