@bkazemi/verily 0.6.0 → 0.8.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 (62) hide show
  1. package/README.md +197 -91
  2. package/dist/browser/connect-dialog.js +3 -4
  3. package/dist/browser/evidence-dialog.d.ts +7 -2
  4. package/dist/browser/evidence-dialog.js +62 -26
  5. package/dist/browser/index.js +3 -0
  6. package/dist/browser/mark.d.ts +2 -6
  7. package/dist/browser/mark.js +6 -12
  8. package/dist/browser/provider-mark.d.ts +3 -3
  9. package/dist/browser/provider-mark.js +15 -90
  10. package/dist/core/index.d.ts +78 -2
  11. package/dist/core/index.js +26 -2
  12. package/dist/instance/auth.d.ts +14 -0
  13. package/dist/instance/auth.js +80 -0
  14. package/dist/instance/bin.d.ts +2 -0
  15. package/dist/instance/bin.js +36 -0
  16. package/dist/instance/cloudflare.d.ts +57 -0
  17. package/dist/instance/cloudflare.js +71 -0
  18. package/dist/instance/env.d.ts +51 -0
  19. package/dist/instance/env.js +84 -0
  20. package/dist/instance/index.d.ts +136 -0
  21. package/dist/instance/index.js +777 -0
  22. package/dist/instance/init.d.ts +6 -0
  23. package/dist/instance/init.js +28 -0
  24. package/dist/instance/limits.d.ts +30 -0
  25. package/dist/instance/limits.js +45 -0
  26. package/dist/instance/node.d.ts +13 -0
  27. package/dist/instance/node.js +43 -0
  28. package/dist/instance/page.d.ts +18 -0
  29. package/dist/instance/page.js +30 -0
  30. package/dist/instance/postgres.d.ts +19 -0
  31. package/dist/instance/postgres.js +83 -0
  32. package/dist/instance/routes.d.ts +7 -0
  33. package/dist/instance/routes.js +22 -0
  34. package/dist/instance/serve.d.ts +31 -0
  35. package/dist/instance/serve.js +49 -0
  36. package/dist/instance/sites.d.ts +169 -0
  37. package/dist/instance/sites.js +413 -0
  38. package/dist/instance/starter.d.ts +6 -0
  39. package/dist/instance/starter.js +99 -0
  40. package/dist/instance/store.d.ts +20 -0
  41. package/dist/instance/store.js +11 -0
  42. package/dist/instance/undici.d.ts +8 -0
  43. package/dist/instance/undici.js +9 -0
  44. package/dist/marks.d.ts +44 -0
  45. package/dist/marks.js +98 -0
  46. package/dist/server/discord.js +3 -0
  47. package/dist/server/domain.js +37 -10
  48. package/dist/server/github-gist.js +16 -4
  49. package/dist/server/github.js +3 -0
  50. package/dist/server/index.js +20 -47
  51. package/dist/server/link.js +9 -4
  52. package/dist/server/render.d.ts +49 -0
  53. package/dist/server/render.js +104 -0
  54. package/dist/server/service.d.ts +44 -1
  55. package/dist/server/service.js +225 -19
  56. package/dist/server/style.d.ts +1 -1
  57. package/dist/server/style.js +132 -2
  58. package/dist/server/youtube.js +5 -0
  59. package/dist/verily.js +155 -124
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/package.json +30 -2
@@ -15,6 +15,7 @@ export const stylesheet = `:root {
15
15
  --surface: #fff;
16
16
  --raised: #f7f9f7;
17
17
  --accent: #245f43;
18
+ --warn: #a4442b;
18
19
  color-scheme: light dark;
19
20
  accent-color: var(--accent);
20
21
  }
@@ -27,6 +28,7 @@ export const stylesheet = `:root {
27
28
  --surface: #161a18;
28
29
  --raised: #1d2220;
29
30
  --accent: #7fc4a2;
31
+ --warn: #e59a82;
30
32
  }
31
33
  }
32
34
 
@@ -74,6 +76,13 @@ h1 {
74
76
  */
75
77
  main.single h1 { margin-bottom: 1.25rem; padding-bottom: 0; border-bottom: none; }
76
78
 
79
+ /*
80
+ * A page holding one thing sits in the middle of the window rather than at its top,
81
+ * where it would leave most of the window empty below it.
82
+ */
83
+ body:has(main.single) { display: flex; min-height: 100vh; min-height: 100dvh; }
84
+ main.single { width: 100%; max-width: 24rem; margin: auto; padding-bottom: 3rem; }
85
+
77
86
  h2 { margin: 2rem 0 .75rem; font-size: 1.125rem; font-weight: 620; letter-spacing: -.01em; }
78
87
 
79
88
  h3 { margin: 0 0 .5rem; font-size: 1rem; font-weight: 620; }
@@ -179,7 +188,17 @@ main:has(.accounts) { max-width: 54rem; }
179
188
  letter-spacing: .02em;
180
189
  }
181
190
 
182
- .name { margin: 0; font-size: 1.0625rem; font-weight: 620; letter-spacing: -.01em; }
191
+ /* A provider's mark before its name, at the height of the letters. */
192
+ .who .provider { display: inline-block; width: .875rem; height: .875rem; margin-right: .375rem; vertical-align: -.125rem; }
193
+
194
+ /* Clipped 4px left of the text, which hides the date's dot when the date wraps to a new line. */
195
+ .name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 1rem; margin: 0 0 0 -4px; padding-left: 4px; overflow-x: clip; font-size: 1.0625rem; font-weight: 620; letter-spacing: -.01em; }
196
+
197
+ /* The account's creation date, after the name and a dot. It wraps under a long name. */
198
+ .name .since { position: relative; color: var(--muted); font-size: .8125rem; font-weight: 400; letter-spacing: 0; white-space: nowrap; }
199
+
200
+ /* The dot sits in the gap before the date. */
201
+ .name .since::before { content: "·"; position: absolute; left: -.5rem; transform: translateX(-50%); }
183
202
 
184
203
  /* The name is the card's subject before it is a link, so the rule is drawn on hover. */
185
204
  .name a { text-decoration: none; }
@@ -192,6 +211,8 @@ main:has(.accounts) { max-width: 54rem; }
192
211
  .fingerprint { font-family: ui-monospace, monospace; text-wrap: balance; }
193
212
  .fingerprint span { display: inline-block; margin-right: .5ch; }
194
213
  .how.additional { padding-left: .75rem; }
214
+ /* The "signed" pill after the verifier's name, one size smaller than the line it sits on. */
215
+ .how .signed-mark { display: inline-block; margin-left: .3125rem; padding: 0 .375rem; border: 1px solid var(--line); border-radius: 999px; font-size: .625rem; font-weight: 550; line-height: 1.3; text-decoration: none; vertical-align: .0625rem; }
195
216
 
196
217
  .fine { color: var(--muted); font-size: .8125rem; line-height: 1.55; margin-bottom: .625rem; }
197
218
 
@@ -255,12 +276,121 @@ button {
255
276
  border-radius: 6px;
256
277
  background: var(--accent);
257
278
  color: var(--surface);
258
- font: 500 .9375rem/1.4 inherit;
279
+ font: 500 .9375rem/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
259
280
  cursor: pointer;
260
281
  }
261
282
 
283
+ /* A link that starts something, drawn as a button. */
284
+ a.button {
285
+ display: inline-block;
286
+ padding: .5rem 1rem;
287
+ border: 1px solid var(--accent);
288
+ border-radius: 6px;
289
+ background: var(--accent);
290
+ color: var(--surface);
291
+ font-weight: 500;
292
+ font-size: .9375rem;
293
+ line-height: 1.4;
294
+ text-decoration: none;
295
+ }
296
+
262
297
  button + button { margin-left: .5rem; border-color: var(--line); background: none; color: var(--ink); }
263
298
 
299
+ /* The other choice beside a page's one action, such as Cancel. */
300
+ a.button.secondary { border-color: var(--line); background: none; color: var(--ink); }
301
+
302
+ /* A page's action and its alternative, side by side. */
303
+ .choice { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }
304
+ .choice form { margin: 0; }
305
+
306
+ /* A control that ends something. Filled where it is the page's one action. */
307
+ button.danger { border-color: var(--warn); background: var(--warn); }
308
+
309
+ /*
310
+ * A connection on the settings page: the account's card, then what can be done with it.
311
+ * Its state sits in the card's corner, on the line that names the method.
312
+ */
313
+ .connection { position: relative; margin-bottom: 1rem; }
314
+
315
+ .state {
316
+ position: absolute;
317
+ top: .75rem;
318
+ right: .875rem;
319
+ display: flex;
320
+ align-items: center;
321
+ gap: .375rem;
322
+ height: 1.625rem;
323
+ padding: 0 .75rem 0 .5rem;
324
+ border: 1px solid var(--line);
325
+ border-radius: 999px;
326
+ background: var(--surface);
327
+ color: var(--ink);
328
+ font-size: .8125rem;
329
+ font-weight: 550;
330
+ }
331
+
332
+ /*
333
+ * The V the badge draws, in the tone that says how the record stands. A record that claims
334
+ * nothing is drawn faint in the text colour, as the badge draws it.
335
+ */
336
+ .verdict { flex-shrink: 0; width: 1rem; height: 1rem; }
337
+ .verdict.pending { opacity: .45; }
338
+ .how .verdict { width: .875rem; height: .875rem; margin-right: .3125rem; vertical-align: -.125rem; }
339
+ h1 .verdict { width: 1.25rem; height: 1.25rem; margin-right: .5rem; vertical-align: -.0625rem; }
340
+
341
+ /*
342
+ * In a state pill the V is cropped to its strokes and fills the pill's height, so its arms
343
+ * and its foot meet the border. The pill's left padding keeps the arms clear of its curve.
344
+ */
345
+ .state .verdict { width: auto; height: 100%; }
346
+
347
+ /*
348
+ * A pill's line includes room for descenders below the letters, which leaves its text
349
+ * sitting high. Trimmed to the letters, the padding alone sets the space above and below.
350
+ * In a state pill the word alone is trimmed, so it centres on the V by its letters.
351
+ */
352
+ @supports (text-box: trim-both cap alphabetic) {
353
+ .listing { padding: .3125rem .5rem; text-box: trim-both cap alphabetic; }
354
+ .state > span { text-box: trim-both cap alphabetic; }
355
+ }
356
+
357
+ /* Links that sit together on one line, wrapping where there is no room. */
358
+ .links { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem; font-size: .875rem; }
359
+
360
+ /* Under the account's id, with the facts about it rather than the controls. */
361
+ .evidence { margin: .375rem 0 0; font-size: .8125rem; }
362
+
363
+ .connection dl { margin-bottom: .75rem; }
364
+ .connection .side > :last-child { margin-bottom: 0; }
365
+ .connection pre { margin: .75rem 0; background: var(--surface); }
366
+ .connection .actions { margin-top: .875rem; }
367
+
368
+ /* The buttons for one connection in a row, wrapping where there is no room. */
369
+ .actions { display: flex; flex-wrap: wrap; gap: .5rem; }
370
+ .actions form { display: contents; }
371
+
372
+ .actions button, .actions a.button {
373
+ margin: 0;
374
+ padding: .3125rem .75rem;
375
+ border-color: var(--line);
376
+ background: var(--surface);
377
+ color: var(--ink);
378
+ font-size: .8125rem;
379
+ }
380
+
381
+ .actions button:hover, .actions a.button:hover { border-color: var(--muted); }
382
+
383
+ /* The controls that cannot be undone, together at the foot of the card. */
384
+ .ending { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); }
385
+ .ending form { margin: 0; }
386
+
387
+ .ending button.danger {
388
+ padding: .3125rem .75rem;
389
+ background: var(--surface);
390
+ color: var(--warn);
391
+ font-size: .8125rem;
392
+ }
393
+
264
394
  fieldset { margin: 0 0 1.25rem; padding: 1rem 1.125rem .25rem; border: 1px solid var(--line); border-radius: 8px; }
265
395
 
266
396
  legend { padding: 0 .375rem; color: var(--muted); font-size: .8125rem; }
@@ -78,10 +78,15 @@ export function youtubeProvider(options) {
78
78
  : undefined;
79
79
  if (!handle)
80
80
  throw new Error('Invalid provider identity');
81
+ // The channel's creation date, not the Google account's. Optional: a missing or
82
+ // unparseable date is left off and the sign-in still succeeds.
83
+ const publishedAt = channel.snippet.publishedAt;
84
+ const createdAt = typeof publishedAt === 'string' ? Date.parse(publishedAt) : NaN;
81
85
  return {
82
86
  id: channel.id,
83
87
  handle,
84
88
  profileUrl: `https://www.youtube.com/channel/${channel.id}`,
89
+ ...(Number.isFinite(createdAt) ? { createdAt } : {}),
85
90
  };
86
91
  }
87
92
  finally {