@kernhq/module-quire 0.13.1 → 0.15.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 (123) hide show
  1. package/dist/contract/models.d.ts +394 -0
  2. package/dist/contract/models.d.ts.map +1 -1
  3. package/dist/contract/models.js +284 -0
  4. package/dist/contract/models.js.map +1 -1
  5. package/dist/contract/permissions.d.ts +14 -0
  6. package/dist/contract/permissions.d.ts.map +1 -1
  7. package/dist/contract/permissions.js +114 -0
  8. package/dist/contract/permissions.js.map +1 -1
  9. package/dist/contract/properties.d.ts +7 -7
  10. package/dist/contract/router.d.ts +1124 -96
  11. package/dist/contract/router.d.ts.map +1 -1
  12. package/dist/contract/router.js +343 -1
  13. package/dist/contract/router.js.map +1 -1
  14. package/dist/server/_impl.d.ts +983 -1168
  15. package/dist/server/_impl.d.ts.map +1 -1
  16. package/dist/server/_impl.js +308 -0
  17. package/dist/server/_impl.js.map +1 -1
  18. package/dist/server/export/html.d.ts +67 -0
  19. package/dist/server/export/html.d.ts.map +1 -0
  20. package/dist/server/export/html.js +206 -0
  21. package/dist/server/export/html.js.map +1 -0
  22. package/dist/server/export/markdown.d.ts +51 -0
  23. package/dist/server/export/markdown.d.ts.map +1 -0
  24. package/dist/server/export/markdown.js +351 -0
  25. package/dist/server/export/markdown.js.map +1 -0
  26. package/dist/server/export/pdf.d.ts +20 -0
  27. package/dist/server/export/pdf.d.ts.map +1 -0
  28. package/dist/server/export/pdf.js +91 -0
  29. package/dist/server/export/pdf.js.map +1 -0
  30. package/dist/server/export/zip.d.ts +31 -0
  31. package/dist/server/export/zip.d.ts.map +1 -0
  32. package/dist/server/export/zip.js +158 -0
  33. package/dist/server/export/zip.js.map +1 -0
  34. package/dist/server/import/csv.d.ts +77 -0
  35. package/dist/server/import/csv.d.ts.map +1 -0
  36. package/dist/server/import/csv.js +263 -0
  37. package/dist/server/import/csv.js.map +1 -0
  38. package/dist/server/import/html.d.ts +52 -0
  39. package/dist/server/import/html.d.ts.map +1 -0
  40. package/dist/server/import/html.js +472 -0
  41. package/dist/server/import/html.js.map +1 -0
  42. package/dist/server/import/markdown.d.ts +63 -0
  43. package/dist/server/import/markdown.d.ts.map +1 -0
  44. package/dist/server/import/markdown.js +692 -0
  45. package/dist/server/import/markdown.js.map +1 -0
  46. package/dist/server/import/plan.d.ts +70 -0
  47. package/dist/server/import/plan.d.ts.map +1 -0
  48. package/dist/server/import/plan.js +761 -0
  49. package/dist/server/import/plan.js.map +1 -0
  50. package/dist/server/import/ydoc.d.ts +35 -0
  51. package/dist/server/import/ydoc.d.ts.map +1 -0
  52. package/dist/server/import/ydoc.js +91 -0
  53. package/dist/server/import/ydoc.js.map +1 -0
  54. package/dist/server/import/zip.d.ts +63 -0
  55. package/dist/server/import/zip.d.ts.map +1 -0
  56. package/dist/server/import/zip.js +308 -0
  57. package/dist/server/import/zip.js.map +1 -0
  58. package/dist/server/index.d.ts.map +1 -1
  59. package/dist/server/index.js +3 -1
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/server/render.d.ts +158 -0
  62. package/dist/server/render.d.ts.map +1 -1
  63. package/dist/server/render.js +240 -0
  64. package/dist/server/render.js.map +1 -1
  65. package/dist/server/schema.d.ts +704 -1
  66. package/dist/server/schema.d.ts.map +1 -1
  67. package/dist/server/schema.js +254 -1
  68. package/dist/server/schema.js.map +1 -1
  69. package/dist/server/services/databases.d.ts +10 -10
  70. package/dist/server/services/export.d.ts +176 -0
  71. package/dist/server/services/export.d.ts.map +1 -0
  72. package/dist/server/services/export.js +822 -0
  73. package/dist/server/services/export.js.map +1 -0
  74. package/dist/server/services/import.d.ts +109 -0
  75. package/dist/server/services/import.d.ts.map +1 -0
  76. package/dist/server/services/import.js +570 -0
  77. package/dist/server/services/import.js.map +1 -0
  78. package/dist/server/services/index.d.ts +32 -1
  79. package/dist/server/services/index.d.ts.map +1 -1
  80. package/dist/server/services/index.js +87 -4
  81. package/dist/server/services/index.js.map +1 -1
  82. package/dist/server/services/macros.d.ts +83 -0
  83. package/dist/server/services/macros.d.ts.map +1 -0
  84. package/dist/server/services/macros.js +488 -0
  85. package/dist/server/services/macros.js.map +1 -0
  86. package/dist/server/services/publications.d.ts +2 -1
  87. package/dist/server/services/publications.d.ts.map +1 -1
  88. package/dist/server/services/publications.js +43 -4
  89. package/dist/server/services/publications.js.map +1 -1
  90. package/dist/server/services/templates.d.ts +135 -0
  91. package/dist/server/services/templates.d.ts.map +1 -0
  92. package/dist/server/services/templates.js +897 -0
  93. package/dist/server/services/templates.js.map +1 -0
  94. package/dist/server/services/versions.d.ts +13 -1
  95. package/dist/server/services/versions.d.ts.map +1 -1
  96. package/dist/server/services/versions.js +3 -1
  97. package/dist/server/services/versions.js.map +1 -1
  98. package/migrations/0010_transfers.sql +154 -0
  99. package/migrations/0011_templates.sql +157 -0
  100. package/migrations/meta/_journal.json +14 -0
  101. package/package.json +5 -5
  102. package/src/client/components/ExportDialog.svelte +685 -0
  103. package/src/client/components/ImportDialog.svelte +702 -0
  104. package/src/client/components/ImportReport.svelte +310 -0
  105. package/src/client/components/NewSpaceDialog.svelte +77 -8
  106. package/src/client/components/PageEditor.svelte +80 -0
  107. package/src/client/components/PagePicker.svelte +264 -0
  108. package/src/client/components/SaveAsTemplateDialog.svelte +502 -0
  109. package/src/client/components/SidebarSpaces.svelte +112 -1
  110. package/src/client/components/TemplatePicker.svelte +437 -0
  111. package/src/client/i18n.ts +941 -0
  112. package/src/client/index.ts +51 -0
  113. package/src/client/mock.ts +592 -0
  114. package/src/client/module.ts +36 -0
  115. package/src/client/pages/PageView.svelte +86 -0
  116. package/src/client/pages/SpacePage.svelte +20 -4
  117. package/src/client/pages/TransfersPage.svelte +570 -0
  118. package/src/client/permissions.ts +11 -0
  119. package/src/client/query.ts +40 -0
  120. package/src/client/transfers.ts +142 -0
  121. package/src/contract/models.ts +343 -0
  122. package/src/contract/permissions.ts +117 -0
  123. package/src/contract/router.ts +375 -0
@@ -1,11 +1,15 @@
1
- import type { Kernel } from '@kernhq/kernel';
1
+ import type { JobDef, Kernel } from '@kernhq/kernel';
2
2
  import { quireAccess } from './access.js';
3
3
  import { quireComments } from './comments.js';
4
4
  import { quireDatabases } from './databases.js';
5
+ import { quireExport } from './export.js';
6
+ import { quireImport } from './import.js';
7
+ import { quireMacros } from './macros.js';
5
8
  import { quireOrganisation } from './organisation.js';
6
9
  import { quirePages } from './pages.js';
7
10
  import { quirePublications } from './publications.js';
8
11
  import { quireSpaces } from './spaces.js';
12
+ import { quireTemplates } from './templates.js';
9
13
  import { quireVersions } from './versions.js';
10
14
  export interface QuireServices {
11
15
  access: ReturnType<typeof quireAccess>;
@@ -16,17 +20,44 @@ export interface QuireServices {
16
20
  databases: ReturnType<typeof quireDatabases>;
17
21
  organisation: ReturnType<typeof quireOrganisation>;
18
22
  publications: ReturnType<typeof quirePublications>;
23
+ exports: ReturnType<typeof quireExport>;
24
+ imports: ReturnType<typeof quireImport>;
25
+ templates: ReturnType<typeof quireTemplates>;
26
+ macros: ReturnType<typeof quireMacros>;
19
27
  }
20
28
  /** One set of services per kernel: they are stateless, and rebuilding them per request is waste. */
21
29
  export declare function quireServices(kernel: Kernel): QuireServices;
30
+ /**
31
+ * The background work this module hands to a worker process, gathered here rather than in
32
+ * `index.ts`.
33
+ *
34
+ * One line in the module definition, so adding a job is an edit to this file and not to the file
35
+ * every other part of the module is also editing. The names reach pg-boss as `quire.<name>` — the
36
+ * kernel prefixes them — and only a process started with a worker role runs them; an API process
37
+ * registers nothing and merely sends.
38
+ *
39
+ * `retryLimit` is deliberately small. An export that fails for a reason of its own — Gotenberg is
40
+ * not running, a page will not render — records that reason on its row and returns *successfully*,
41
+ * because it has finished: it failed, and it said so, and repeating it would only write the same
42
+ * sentence three more times. A throw out of the handler means something underneath went wrong
43
+ * (the database, the broker), which is the case a retry is for.
44
+ */
45
+ export declare const quireJobs: JobDef<{
46
+ workspaceId: string;
47
+ jobId: string;
48
+ }>[];
22
49
  export * from './access.js';
23
50
  export * from './comments.js';
24
51
  export * from './databases.js';
52
+ export * from './export.js';
53
+ export * from './import.js';
54
+ export * from './macros.js';
25
55
  export * from './organisation.js';
26
56
  export * from './pages.js';
27
57
  export * from './publications.js';
28
58
  /** The public surface resolves a workspace slug before anything touches the schema. */
29
59
  export { resolveWorkspaceSegment } from './publications.js';
30
60
  export * from './spaces.js';
61
+ export * from './templates.js';
31
62
  export * from './versions.js';
32
63
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;IACpC,QAAQ,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC1C,QAAQ,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC1C,SAAS,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;IAC5C,YAAY,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IAClD,YAAY,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;CACnD;AAID,oGAAoG;AACpG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAiB3D;AAED,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,uFAAuF;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;IACpC,QAAQ,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC1C,QAAQ,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC1C,SAAS,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;IAC5C,YAAY,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IAClD,YAAY,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IAClD,OAAO,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACvC,OAAO,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACvC,SAAS,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;IAC5C,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;CACvC;AAID,oGAAoG;AACpG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CA0C3D;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAiCrE,CAAA;AAED,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,uFAAuF;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA"}
@@ -1,10 +1,15 @@
1
+ import { z } from 'zod';
1
2
  import { quireAccess } from './access.js';
2
3
  import { quireComments } from './comments.js';
3
4
  import { quireDatabases } from './databases.js';
5
+ import { quireExport } from './export.js';
6
+ import { quireImport } from './import.js';
7
+ import { quireMacros } from './macros.js';
4
8
  import { quireOrganisation } from './organisation.js';
5
9
  import { quirePages } from './pages.js';
6
10
  import { quirePublications } from './publications.js';
7
11
  import { quireSpaces } from './spaces.js';
12
+ import { quireTemplates } from './templates.js';
8
13
  import { quireVersions } from './versions.js';
9
14
  const cache = new WeakMap();
10
15
  /** One set of services per kernel: they are stateless, and rebuilding them per request is waste. */
@@ -14,27 +19,105 @@ export function quireServices(kernel) {
14
19
  return existing;
15
20
  const access = quireAccess(kernel);
16
21
  const versions = quireVersions(kernel, access);
22
+ // An import writes pages *and* databases, so it is the one service built on another one: it needs
23
+ // `databases` to mint the properties whose keys its rows are keyed by. See `import.ts`'s `write`.
24
+ const databases = quireDatabases(kernel, access);
25
+ /*
26
+ * Templates make pages and spaces, so they are built on the two services that already know how —
27
+ * a second implementation of "create a page" would be a second fractional-index algorithm, and two
28
+ * orderings of one tree is a sidebar that disagrees with itself.
29
+ */
30
+ const spaces = quireSpaces(access);
31
+ const pages = quirePages(access);
32
+ /*
33
+ * Built before `publications`, which needs it: a published page's HTML is rendered on the public
34
+ * path, and a macro inside it has to resolve there too — against the publication rather than
35
+ * against a reader, because on that path there is no reader at all.
36
+ */
37
+ const macros = quireMacros(kernel, access);
17
38
  const services = {
18
39
  access,
19
- spaces: quireSpaces(access),
20
- pages: quirePages(access),
40
+ spaces,
41
+ pages,
21
42
  versions,
22
43
  comments: quireComments(access),
23
- databases: quireDatabases(kernel, access),
44
+ databases,
24
45
  organisation: quireOrganisation(access),
25
- publications: quirePublications(kernel, access, versions),
46
+ publications: quirePublications(kernel, access, versions, macros),
47
+ exports: quireExport(kernel, access),
48
+ imports: quireImport(kernel, access, databases),
49
+ templates: quireTemplates(kernel, access, pages, spaces),
50
+ /*
51
+ * Macros resolve *reads* against whoever is reading, so this service has `access` and nothing
52
+ * that writes. It is deliberately not built on `pages`: a macro must never reach a procedure
53
+ * that answers for the caller rather than for the reader.
54
+ */
55
+ macros,
26
56
  };
27
57
  cache.set(kernel, services);
28
58
  return services;
29
59
  }
60
+ /**
61
+ * The background work this module hands to a worker process, gathered here rather than in
62
+ * `index.ts`.
63
+ *
64
+ * One line in the module definition, so adding a job is an edit to this file and not to the file
65
+ * every other part of the module is also editing. The names reach pg-boss as `quire.<name>` — the
66
+ * kernel prefixes them — and only a process started with a worker role runs them; an API process
67
+ * registers nothing and merely sends.
68
+ *
69
+ * `retryLimit` is deliberately small. An export that fails for a reason of its own — Gotenberg is
70
+ * not running, a page will not render — records that reason on its row and returns *successfully*,
71
+ * because it has finished: it failed, and it said so, and repeating it would only write the same
72
+ * sentence three more times. A throw out of the handler means something underneath went wrong
73
+ * (the database, the broker), which is the case a retry is for.
74
+ */
75
+ export const quireJobs = [
76
+ {
77
+ name: 'export',
78
+ schema: z.object({ workspaceId: z.uuid(), jobId: z.uuid() }),
79
+ handler: async (input, { kernel }) => {
80
+ await quireServices(kernel).exports.run(input.workspaceId, input.jobId);
81
+ },
82
+ options: { retryLimit: 2, retryDelay: 30, expireInSeconds: 900 },
83
+ },
84
+ /**
85
+ * An import, with **no retries at all** — the one place in this module where that is the safe
86
+ * setting rather than the timid one.
87
+ *
88
+ * `run` is idempotent against its own row (`done` and `failed` are terminal, and it claims the row
89
+ * before it does anything), so a retry after a *completed* run is a no-op. What a retry cannot be
90
+ * safe against is the case pg-boss actually retries: a handler that threw. An import commits its
91
+ * pages and its finished row in one transaction, so a throw means nothing was written — but a
92
+ * *lost connection after the commit* looks exactly the same from here, and running it again would
93
+ * write every page in the archive a second time. Two hundred duplicate pages in somebody's space
94
+ * is a worse outcome than a job that says it failed and can be started again by a person who can
95
+ * see what is in the space.
96
+ *
97
+ * The window is longer than an export's for the obvious reason: reading a few hundred megabytes of
98
+ * zip and writing four thousand rows is not a fifteen-minute job on a busy instance.
99
+ */
100
+ {
101
+ name: 'import',
102
+ schema: z.object({ workspaceId: z.uuid(), jobId: z.uuid() }),
103
+ handler: async (input, { kernel }) => {
104
+ await quireServices(kernel).imports.run(input.workspaceId, input.jobId);
105
+ },
106
+ options: { retryLimit: 0, expireInSeconds: 3600 },
107
+ },
108
+ ];
30
109
  export * from './access.js';
31
110
  export * from './comments.js';
32
111
  export * from './databases.js';
112
+ export * from './export.js';
113
+ export * from './import.js';
114
+ export * from './macros.js';
33
115
  export * from './organisation.js';
34
116
  export * from './pages.js';
35
117
  export * from './publications.js';
36
118
  /** The public surface resolves a workspace slug before anything touches the schema. */
37
119
  export { resolveWorkspaceSegment } from './publications.js';
38
120
  export * from './spaces.js';
121
+ export * from './templates.js';
39
122
  export * from './versions.js';
40
123
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAa7C,MAAM,KAAK,GAAG,IAAI,OAAO,EAAyB,CAAA;AAElD,oGAAoG;AACpG,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAClC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9C,MAAM,QAAQ,GAAkB;QAC9B,MAAM;QACN,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC;QACzB,QAAQ;QACR,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC;QAC/B,SAAS,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC;QACzC,YAAY,EAAE,iBAAiB,CAAC,MAAM,CAAC;QACvC,YAAY,EAAE,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;KAC1D,CAAA;IACD,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAC3B,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,uFAAuF;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * What a macro is allowed to say, to the person actually reading.
3
+ *
4
+ * Five of the eight macros draw pages that are not in the document — `pageChildren`,
5
+ * `excerptInclude`, `includePage`, `recentlyUpdated` and `contributors`. Everything about them that
6
+ * matters is in this file, because this is the only place that decides *which* pages, and the
7
+ * decision is the feature's whole risk: a children macro that forgets its filter still compiles,
8
+ * still renders, and looks right to the author, because the author can read everything on it.
9
+ *
10
+ * The rule, in three parts, and `macros.int.test.ts` holds all three:
11
+ *
12
+ * 1. **The renderer never reads a database.** `renderPageDoc` draws a reading macro only from a
13
+ * `MacroResolver` it was handed. With none — which is what every caller written before this
14
+ * feature passes, the exporters and the publish-time render included — a reading macro draws
15
+ * its frame and nothing else. Fail-closed is the default rather than a branch to remember.
16
+ * 2. **A signed-in reader sees exactly what they could open.** Every page named here is asked
17
+ * about with `quire.page.view` at *page* scope, so a DENY bound to one page removes it.
18
+ * 3. **A published site has no reader, so the publication is the audience.** The set of publicly
19
+ * reachable pages — which `publications.walk` already computes, root first and pruned — is the
20
+ * whole of what exists. Anything outside it is not drawn as a title with a dead link; it is
21
+ * not drawn.
22
+ *
23
+ * Two structural choices follow from that and are worth stating rather than leaving to be inferred.
24
+ *
25
+ * **Resolution is a pass, not a per-node lookup.** `macrosIn` collects the reading macros in a
26
+ * document and de-duplicates them by their attributes, this file answers them against one audience,
27
+ * and `renderPageDoc` reads the answers out of a map. The alternative — resolving inside the
28
+ * renderer — is a database round trip per macro in render order, on a request that is otherwise two
29
+ * queries, and it would make the renderer async for every caller that has no macros at all.
30
+ *
31
+ * **A prune is not a filter.** Where a page is not visible, its descendants go with it. Removing a
32
+ * page from a children list and then listing its children anyway would name every page under it to
33
+ * whoever guessed there was something there, which is exactly the shape `publications.ts`'s walk
34
+ * exists to avoid — and the reason that walk prunes is the reason this one does.
35
+ */
36
+ import type { Principal } from '@kernhq/contracts';
37
+ import type { Kernel, Tx } from '@kernhq/kernel';
38
+ import { type PageDoc } from '@kernhq/ui/editor/page-doc';
39
+ import { type MacroResolver } from '../render.js';
40
+ import type { QuireAccess } from './access.js';
41
+ /**
42
+ * Who is being drawn for.
43
+ *
44
+ * A discriminated union with exactly two members, and there is deliberately no third: a caller
45
+ * cannot express "resolve this for nobody in particular", because that is the shape that leaks. A
46
+ * caller with no audience passes no resolver at all, and the renderer draws empty frames.
47
+ */
48
+ export type MacroAudience = {
49
+ kind: 'reader';
50
+ principal: Principal;
51
+ }
52
+ /**
53
+ * The publicly reachable pages, as `publications.walk` computed them for *this* publication.
54
+ * A set rather than a publication id, so this file cannot disagree with the walk about what
55
+ * "public" means — there is only one definition of it and it is not here.
56
+ */
57
+ | {
58
+ kind: 'publication';
59
+ pageIds: ReadonlySet<string>;
60
+ };
61
+ export interface MacroContext {
62
+ /** The page the document belongs to. `null` for a render with no page — a preview, an import. */
63
+ pageId: string | null;
64
+ /** Where to send a reader for a page id, if this render has addresses at all. */
65
+ pageHref?: (pageId: string) => string | null;
66
+ /** For the dates a list macro draws. `principal.locale` for a reader; the site's for a publication. */
67
+ locale?: string | null;
68
+ }
69
+ export declare function quireMacros(kernel: Kernel, access: QuireAccess): {
70
+ /**
71
+ * Answer every reading macro in a document, for one audience, in one pass.
72
+ *
73
+ * Returns the synchronous lookup `renderPageDoc` takes. A macro this could not answer — a page
74
+ * that was deleted, a page the audience may not see, a lookup that failed — is simply absent
75
+ * from the map, and an absent answer is the empty frame. There is no path through this function
76
+ * that returns a page the audience failed the gate on, and no way to express one: `visible` is
77
+ * the only thing that builds a `MacroPageRef`'s input, and every caller of `refOf` has just
78
+ * awaited it.
79
+ */
80
+ resolve(tx: Tx, workspaceId: string, doc: PageDoc | null | undefined, audience: MacroAudience, ctx: MacroContext): Promise<MacroResolver>;
81
+ };
82
+ export type QuireMacros = ReturnType<typeof quireMacros>;
83
+ //# sourceMappingURL=macros.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macros.d.ts","sourceRoot":"","sources":["../../../src/server/services/macros.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAGL,KAAK,OAAO,EAEb,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EAGL,KAAK,aAAa,EAKnB,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE;AAC1C;;;;GAIG;GACD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AAEzD,MAAM,WAAW,YAAY;IAC3B,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IAC5C,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AA6GD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAgV3D;;;;;;;;;OASG;gBAEG,EAAE,eACO,MAAM,OACd,OAAO,GAAG,IAAI,GAAG,SAAS,YACrB,aAAa,OAClB,YAAY,GAChB,OAAO,CAAC,aAAa,CAAC;EA0H5B;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA"}