@jini-ai/admin 0.1.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 (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +138 -0
  3. package/dist/browser/index.d.ts +8 -0
  4. package/dist/browser/index.d.ts.map +1 -0
  5. package/dist/browser/index.js +8 -0
  6. package/dist/browser/index.js.map +1 -0
  7. package/dist/browser/navigation.d.ts +39 -0
  8. package/dist/browser/navigation.d.ts.map +1 -0
  9. package/dist/browser/navigation.js +113 -0
  10. package/dist/browser/navigation.js.map +1 -0
  11. package/dist/core/gated/types.d.ts +87 -0
  12. package/dist/core/gated/types.d.ts.map +1 -0
  13. package/dist/core/gated/types.js +37 -0
  14. package/dist/core/gated/types.js.map +1 -0
  15. package/dist/core/index.d.ts +20 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +15 -0
  18. package/dist/core/index.js.map +1 -0
  19. package/dist/core/manifest/rules.d.ts +84 -0
  20. package/dist/core/manifest/rules.d.ts.map +1 -0
  21. package/dist/core/manifest/rules.js +130 -0
  22. package/dist/core/manifest/rules.js.map +1 -0
  23. package/dist/core/manifest/types.d.ts +154 -0
  24. package/dist/core/manifest/types.d.ts.map +1 -0
  25. package/dist/core/manifest/types.js +31 -0
  26. package/dist/core/manifest/types.js.map +1 -0
  27. package/dist/core/permissions/rules.d.ts +32 -0
  28. package/dist/core/permissions/rules.d.ts.map +1 -0
  29. package/dist/core/permissions/rules.js +34 -0
  30. package/dist/core/permissions/rules.js.map +1 -0
  31. package/dist/core/ports/analytics.d.ts +35 -0
  32. package/dist/core/ports/analytics.d.ts.map +1 -0
  33. package/dist/core/ports/analytics.js +14 -0
  34. package/dist/core/ports/analytics.js.map +1 -0
  35. package/dist/core/ports/auth.d.ts +49 -0
  36. package/dist/core/ports/auth.d.ts.map +1 -0
  37. package/dist/core/ports/auth.js +19 -0
  38. package/dist/core/ports/auth.js.map +1 -0
  39. package/dist/core/ports/comments.d.ts +90 -0
  40. package/dist/core/ports/comments.d.ts.map +1 -0
  41. package/dist/core/ports/comments.js +24 -0
  42. package/dist/core/ports/comments.js.map +1 -0
  43. package/dist/core/ports/database.d.ts +101 -0
  44. package/dist/core/ports/database.d.ts.map +1 -0
  45. package/dist/core/ports/database.js +2 -0
  46. package/dist/core/ports/database.js.map +1 -0
  47. package/dist/core/ports/forms.d.ts +130 -0
  48. package/dist/core/ports/forms.d.ts.map +1 -0
  49. package/dist/core/ports/forms.js +62 -0
  50. package/dist/core/ports/forms.js.map +1 -0
  51. package/dist/core/ports/identity.d.ts +114 -0
  52. package/dist/core/ports/identity.d.ts.map +1 -0
  53. package/dist/core/ports/identity.js +28 -0
  54. package/dist/core/ports/identity.js.map +1 -0
  55. package/dist/core/ports/index.d.ts +21 -0
  56. package/dist/core/ports/index.d.ts.map +1 -0
  57. package/dist/core/ports/index.js +6 -0
  58. package/dist/core/ports/index.js.map +1 -0
  59. package/dist/core/ports/integrations.d.ts +81 -0
  60. package/dist/core/ports/integrations.d.ts.map +1 -0
  61. package/dist/core/ports/integrations.js +21 -0
  62. package/dist/core/ports/integrations.js.map +1 -0
  63. package/dist/core/ports/media.d.ts +74 -0
  64. package/dist/core/ports/media.d.ts.map +1 -0
  65. package/dist/core/ports/media.js +28 -0
  66. package/dist/core/ports/media.js.map +1 -0
  67. package/dist/core/ports/members.d.ts +50 -0
  68. package/dist/core/ports/members.d.ts.map +1 -0
  69. package/dist/core/ports/members.js +17 -0
  70. package/dist/core/ports/members.js.map +1 -0
  71. package/dist/core/ports/menus.d.ts +179 -0
  72. package/dist/core/ports/menus.d.ts.map +1 -0
  73. package/dist/core/ports/menus.js +70 -0
  74. package/dist/core/ports/menus.js.map +1 -0
  75. package/dist/core/ports/plugins.d.ts +68 -0
  76. package/dist/core/ports/plugins.d.ts.map +1 -0
  77. package/dist/core/ports/plugins.js +27 -0
  78. package/dist/core/ports/plugins.js.map +1 -0
  79. package/dist/core/ports/recovery.d.ts +171 -0
  80. package/dist/core/ports/recovery.d.ts.map +1 -0
  81. package/dist/core/ports/recovery.js +2 -0
  82. package/dist/core/ports/recovery.js.map +1 -0
  83. package/dist/core/ports/redirects.d.ts +139 -0
  84. package/dist/core/ports/redirects.d.ts.map +1 -0
  85. package/dist/core/ports/redirects.js +55 -0
  86. package/dist/core/ports/redirects.js.map +1 -0
  87. package/dist/core/ports/seo.d.ts +147 -0
  88. package/dist/core/ports/seo.d.ts.map +1 -0
  89. package/dist/core/ports/seo.js +39 -0
  90. package/dist/core/ports/seo.js.map +1 -0
  91. package/dist/core/ports/settings.d.ts +87 -0
  92. package/dist/core/ports/settings.d.ts.map +1 -0
  93. package/dist/core/ports/settings.js +23 -0
  94. package/dist/core/ports/settings.js.map +1 -0
  95. package/dist/core/ports/workspace.d.ts +44 -0
  96. package/dist/core/ports/workspace.d.ts.map +1 -0
  97. package/dist/core/ports/workspace.js +29 -0
  98. package/dist/core/ports/workspace.js.map +1 -0
  99. package/dist/core/routing/rules.d.ts +54 -0
  100. package/dist/core/routing/rules.d.ts.map +1 -0
  101. package/dist/core/routing/rules.js +113 -0
  102. package/dist/core/routing/rules.js.map +1 -0
  103. package/dist/core/routing/types.d.ts +36 -0
  104. package/dist/core/routing/types.d.ts.map +1 -0
  105. package/dist/core/routing/types.js +17 -0
  106. package/dist/core/routing/types.js.map +1 -0
  107. package/dist/core/transport/errors.d.ts +53 -0
  108. package/dist/core/transport/errors.d.ts.map +1 -0
  109. package/dist/core/transport/errors.js +63 -0
  110. package/dist/core/transport/errors.js.map +1 -0
  111. package/dist/core/transport/http.d.ts +63 -0
  112. package/dist/core/transport/http.d.ts.map +1 -0
  113. package/dist/core/transport/http.js +63 -0
  114. package/dist/core/transport/http.js.map +1 -0
  115. package/dist/core/transport/index.d.ts +5 -0
  116. package/dist/core/transport/index.d.ts.map +1 -0
  117. package/dist/core/transport/index.js +3 -0
  118. package/dist/core/transport/index.js.map +1 -0
  119. package/dist/core/transport/types.d.ts +81 -0
  120. package/dist/core/transport/types.d.ts.map +1 -0
  121. package/dist/core/transport/types.js +43 -0
  122. package/dist/core/transport/types.js.map +1 -0
  123. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts +40 -0
  124. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts.map +1 -0
  125. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +22 -0
  126. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts.map +1 -0
  127. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +59 -0
  128. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js.map +1 -0
  129. package/dist/react/components/ConfirmButton/ConfirmButton.js +40 -0
  130. package/dist/react/components/ConfirmButton/ConfirmButton.js.map +1 -0
  131. package/dist/react/components/ConfirmButton.d.ts +39 -0
  132. package/dist/react/components/ConfirmButton.d.ts.map +1 -0
  133. package/dist/react/components/ConfirmButton.js +79 -0
  134. package/dist/react/components/ConfirmButton.js.map +1 -0
  135. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +90 -0
  136. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
  137. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +49 -0
  138. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +1 -0
  139. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +81 -0
  140. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js.map +1 -0
  141. package/dist/react/components/ConfirmDialog/ConfirmDialog.js +92 -0
  142. package/dist/react/components/ConfirmDialog/ConfirmDialog.js.map +1 -0
  143. package/dist/react/components/ConfirmDialog.d.ts +57 -0
  144. package/dist/react/components/ConfirmDialog.d.ts.map +1 -0
  145. package/dist/react/components/ConfirmDialog.js +85 -0
  146. package/dist/react/components/ConfirmDialog.js.map +1 -0
  147. package/dist/react/components/DataTable.d.ts +97 -0
  148. package/dist/react/components/DataTable.d.ts.map +1 -0
  149. package/dist/react/components/DataTable.js +20 -0
  150. package/dist/react/components/DataTable.js.map +1 -0
  151. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +25 -0
  152. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts.map +1 -0
  153. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +148 -0
  154. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js.map +1 -0
  155. package/dist/react/components/RowMenu/RowMenu.d.ts +77 -0
  156. package/dist/react/components/RowMenu/RowMenu.d.ts.map +1 -0
  157. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +30 -0
  158. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts.map +1 -0
  159. package/dist/react/components/RowMenu/RowMenu.hooks.js +154 -0
  160. package/dist/react/components/RowMenu/RowMenu.hooks.js.map +1 -0
  161. package/dist/react/components/RowMenu/RowMenu.js +46 -0
  162. package/dist/react/components/RowMenu/RowMenu.js.map +1 -0
  163. package/dist/react/components/RowMenu.d.ts +44 -0
  164. package/dist/react/components/RowMenu.d.ts.map +1 -0
  165. package/dist/react/components/RowMenu.js +149 -0
  166. package/dist/react/components/RowMenu.js.map +1 -0
  167. package/dist/react/components/Sidebar.d.ts +128 -0
  168. package/dist/react/components/Sidebar.d.ts.map +1 -0
  169. package/dist/react/components/Sidebar.js +168 -0
  170. package/dist/react/components/Sidebar.js.map +1 -0
  171. package/dist/react/hooks/use-nav-sections.d.ts +50 -0
  172. package/dist/react/hooks/use-nav-sections.d.ts.map +1 -0
  173. package/dist/react/hooks/use-nav-sections.js +112 -0
  174. package/dist/react/hooks/use-nav-sections.js.map +1 -0
  175. package/dist/react/hooks/use-sidebar-rail.d.ts +39 -0
  176. package/dist/react/hooks/use-sidebar-rail.d.ts.map +1 -0
  177. package/dist/react/hooks/use-sidebar-rail.js +93 -0
  178. package/dist/react/hooks/use-sidebar-rail.js.map +1 -0
  179. package/dist/react/index.d.ts +53 -0
  180. package/dist/react/index.d.ts.map +1 -0
  181. package/dist/react/index.js +53 -0
  182. package/dist/react/index.js.map +1 -0
  183. package/dist/react/types.d.ts +28 -0
  184. package/dist/react/types.d.ts.map +1 -0
  185. package/dist/react/types.js +23 -0
  186. package/dist/react/types.js.map +1 -0
  187. package/dist/server/composio/bounded-data.d.ts +36 -0
  188. package/dist/server/composio/bounded-data.d.ts.map +1 -0
  189. package/dist/server/composio/bounded-data.js +181 -0
  190. package/dist/server/composio/bounded-data.js.map +1 -0
  191. package/dist/server/composio/catalog.d.ts +147 -0
  192. package/dist/server/composio/catalog.d.ts.map +1 -0
  193. package/dist/server/composio/catalog.js +126 -0
  194. package/dist/server/composio/catalog.js.map +1 -0
  195. package/dist/server/composio/composio-config.d.ts +42 -0
  196. package/dist/server/composio/composio-config.d.ts.map +1 -0
  197. package/dist/server/composio/composio-config.js +145 -0
  198. package/dist/server/composio/composio-config.js.map +1 -0
  199. package/dist/server/composio/composio-descriptions.d.ts +16 -0
  200. package/dist/server/composio/composio-descriptions.d.ts.map +1 -0
  201. package/dist/server/composio/composio-descriptions.js +766 -0
  202. package/dist/server/composio/composio-descriptions.js.map +1 -0
  203. package/dist/server/composio/composio.d.ts +364 -0
  204. package/dist/server/composio/composio.d.ts.map +1 -0
  205. package/dist/server/composio/composio.js +1902 -0
  206. package/dist/server/composio/composio.js.map +1 -0
  207. package/dist/server/composio/errors.d.ts +15 -0
  208. package/dist/server/composio/errors.d.ts.map +1 -0
  209. package/dist/server/composio/errors.js +16 -0
  210. package/dist/server/composio/errors.js.map +1 -0
  211. package/dist/server/composio/file-lock.d.ts +13 -0
  212. package/dist/server/composio/file-lock.d.ts.map +1 -0
  213. package/dist/server/composio/file-lock.js +92 -0
  214. package/dist/server/composio/file-lock.js.map +1 -0
  215. package/dist/server/composio/index.d.ts +18 -0
  216. package/dist/server/composio/index.d.ts.map +1 -0
  217. package/dist/server/composio/index.js +7 -0
  218. package/dist/server/composio/index.js.map +1 -0
  219. package/dist/server/composio/json-schema.d.ts +93 -0
  220. package/dist/server/composio/json-schema.d.ts.map +1 -0
  221. package/dist/server/composio/json-schema.js +498 -0
  222. package/dist/server/composio/json-schema.js.map +1 -0
  223. package/dist/server/composio/output-protection.d.ts +32 -0
  224. package/dist/server/composio/output-protection.d.ts.map +1 -0
  225. package/dist/server/composio/output-protection.js +105 -0
  226. package/dist/server/composio/output-protection.js.map +1 -0
  227. package/dist/server/composio/service.d.ts +181 -0
  228. package/dist/server/composio/service.d.ts.map +1 -0
  229. package/dist/server/composio/service.js +758 -0
  230. package/dist/server/composio/service.js.map +1 -0
  231. package/dist/server/index.d.ts +15 -0
  232. package/dist/server/index.d.ts.map +1 -0
  233. package/dist/server/index.js +15 -0
  234. package/dist/server/index.js.map +1 -0
  235. package/package.json +92 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @file `AdminRedirectsPort` — manual URL redirect rules layered in front of a host's own content
3
+ * resolution (a 404-fill pass by default, or an early override pass for retiring a live URL).
4
+ *
5
+ * ## `matchType: "regex"` is a real, typed, always-rejected request shape
6
+ *
7
+ * `RedirectMatchType` includes `"regex"` because the reference implementation's own API surface
8
+ * accepts it as a well-formed request value — but its write chokepoint hard-rejects it
9
+ * unconditionally in v1 (its own matcher source literally comments "never actually reachable — validatePattern always rejects it
10
+ * at write time"). This is not a permission gate or a feature flag despite how it may look from the
11
+ * type alone: every `createRedirect`/`updateRedirect`/`importRedirects` call carrying `"regex"`
12
+ * fails validation, full stop, on the reference implementation. A panel must not offer `regex` as a
13
+ * selectable match type unless it has independently confirmed the host it's talking to actually
14
+ * implements it — do not infer support from this type accepting the literal.
15
+ *
16
+ * This is the "loudly-rejected input stays and gets documented" half of the rule `forms.ts`'s file
17
+ * header states in full (its counterpart, a silently-ignored input, is why that port's update patch
18
+ * has no `slug` field at all) — kept here because the union is OPEN and a different host may
19
+ * legitimately implement `regex` even though the reference implementation refuses it.
20
+ *
21
+ * ## `tombstoneRedirect` is a soft delete
22
+ *
23
+ * Mirrors `AdminIntegrationsPort.deleteIntegrationSubscription`, not `AdminMediaPort.deleteMedia`:
24
+ * the rule's `status` flips to `"disabled"` and the row is retained (audit trail, still readable
25
+ * via `listRedirects`/`getRedirect`), never hard-purged. The method resolves to the updated record
26
+ * (200-style), not `void` — a panel can render the new state without a re-fetch.
27
+ *
28
+ * ## `source: "auto_slug_change"` is read-only provenance
29
+ *
30
+ * Rows carrying this source are minted internally by the host's own content pipeline when a piece
31
+ * of content's slug changes (never-break-links) — it is not a value a caller chooses. It appears
32
+ * on `AdminRedirect.source` for display, but `AdminRedirectCreateInput` (used by both
33
+ * `createRedirect` and each item of `importRedirects`) has no `source` field at all: there is
34
+ * nothing to set. Do not offer `auto_slug_change` as a choice in a create/import form.
35
+ *
36
+ * ## `importRedirects` never fails as a whole
37
+ *
38
+ * The reference implementation's route always answers 207 Multi-Status: each rule is validated and written
39
+ * independently through the same path `createRedirect` uses, so one bad item never aborts the
40
+ * batch or rolls back already-written ones. Check `AdminRedirectImportResult.failed` for per-item
41
+ * rejections — a resolved promise here does not mean every rule in the batch was created.
42
+ *
43
+ * ## Open vs. closed unions
44
+ *
45
+ * `RedirectStatusCode` is CLOSED (`301 | 302 | 307 | 308`) — this is the complete set the
46
+ * reference implementation's write chokepoint accepts, and it is a subset of a real HTTP standard,
47
+ * not the reference implementation's to extend (a 5th caller-supplied code would need a 5th value
48
+ * here to be meaningful, and the reference server would reject it anyway). `RedirectMatchType`,
49
+ * `RedirectSource`, and `RedirectStatus` are reference-implementation-specific vocabularies that
50
+ * another host's routing engine will diverge from — OPEN, via the `T | (string & {})` idiom
51
+ * `seo.ts`'s file header introduces for this port
52
+ * set.
53
+ */
54
+ /** How a rule's pattern is matched against an incoming path — open, see file header
55
+ * (`"regex"` is a real literal that is always rejected on the reference implementation). */
56
+ export type RedirectMatchType = "exact" | "prefix" | "wildcard" | "regex" | (string & {});
57
+ /** HTTP status a matched rule emits — closed, see file header. */
58
+ export type RedirectStatusCode = 301 | 302 | 307 | 308;
59
+ /** Provenance of a rule — open, see file header (`"auto_slug_change"` is read-only). */
60
+ export type RedirectSource = "manual" | "auto_slug_change" | "import" | (string & {});
61
+ /** Lifecycle of a rule — open, see file header. */
62
+ export type RedirectStatus = "active" | "disabled" | (string & {});
63
+ export interface AdminRedirect {
64
+ readonly id: string;
65
+ readonly matchType: RedirectMatchType;
66
+ readonly fromPattern: string;
67
+ /** A normalized site-relative path, or an absolute URL. */
68
+ readonly toTarget: string;
69
+ readonly statusCode: RedirectStatusCode;
70
+ readonly status: RedirectStatus;
71
+ /** When true, this rule is consulted before live content resolution (retires a live URL);
72
+ * when false (the default), it only fills the not-found path. */
73
+ readonly override: boolean;
74
+ /** Explicit tie-breaker within an equal-specificity band — higher wins. */
75
+ readonly priority: number;
76
+ readonly source: RedirectSource;
77
+ /** The content item whose slug change minted this rule — set only for `source:
78
+ * "auto_slug_change"` rows. */
79
+ readonly sourceEntryId: string | null;
80
+ readonly fromPathAtCapture: string | null;
81
+ readonly toPathAtCapture: string | null;
82
+ readonly createdByPrincipal: string;
83
+ readonly createdByPluginId: string | null;
84
+ readonly createdAt: string;
85
+ readonly updatedAt: string;
86
+ readonly version: number;
87
+ }
88
+ /** No `source` field — see file header, there is nothing for a caller to set. */
89
+ export interface AdminRedirectCreateInput {
90
+ readonly matchType: RedirectMatchType;
91
+ readonly fromPattern: string;
92
+ readonly toTarget: string;
93
+ readonly statusCode: RedirectStatusCode;
94
+ readonly override?: boolean;
95
+ readonly priority?: number;
96
+ }
97
+ export interface AdminRedirectUpdatePatch {
98
+ readonly matchType?: RedirectMatchType;
99
+ readonly fromPattern?: string;
100
+ readonly toTarget?: string;
101
+ readonly statusCode?: RedirectStatusCode;
102
+ readonly status?: RedirectStatus;
103
+ readonly override?: boolean;
104
+ readonly priority?: number;
105
+ }
106
+ export interface AdminRedirectListFilter {
107
+ readonly status?: RedirectStatus;
108
+ readonly source?: RedirectSource;
109
+ readonly matchType?: RedirectMatchType;
110
+ }
111
+ export interface AdminRedirectHitStats {
112
+ readonly redirectId: string;
113
+ readonly hitCount: number;
114
+ readonly lastHitAt: string | null;
115
+ }
116
+ export interface AdminRedirectImportFailure {
117
+ readonly index: number;
118
+ readonly code: string;
119
+ readonly message: string;
120
+ }
121
+ export interface AdminRedirectImportResult {
122
+ readonly created: readonly AdminRedirect[];
123
+ readonly failed: readonly AdminRedirectImportFailure[];
124
+ }
125
+ export interface AdminRedirectsPort {
126
+ listRedirects(filter?: AdminRedirectListFilter): Promise<readonly AdminRedirect[]>;
127
+ getRedirect(id: string): Promise<AdminRedirect>;
128
+ createRedirect(input: AdminRedirectCreateInput): Promise<AdminRedirect>;
129
+ updateRedirect(id: string, patch: AdminRedirectUpdatePatch): Promise<AdminRedirect>;
130
+ /** Soft delete — returns the tombstoned record, not `void`. See file header. */
131
+ tombstoneRedirect(id: string): Promise<AdminRedirect>;
132
+ /** Resolves with `hitCount: 0`/`lastHitAt: null` when no hits have been recorded yet — distinct
133
+ * from the redirect itself not existing, which is a not-found-class rejection instead. */
134
+ getRedirectHitStats(id: string): Promise<AdminRedirectHitStats>;
135
+ /** Always a partial-success batch — see file header. Each item shares `AdminRedirectCreateInput`'s
136
+ * shape (provenance is stamped `"import"` automatically, not caller-supplied). */
137
+ importRedirects(rules: readonly AdminRedirectCreateInput[]): Promise<AdminRedirectImportResult>;
138
+ }
139
+ //# sourceMappingURL=redirects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../../src/core/ports/redirects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @file `AdminRedirectsPort` — manual URL redirect rules layered in front of a host's own content
3
+ * resolution (a 404-fill pass by default, or an early override pass for retiring a live URL).
4
+ *
5
+ * ## `matchType: "regex"` is a real, typed, always-rejected request shape
6
+ *
7
+ * `RedirectMatchType` includes `"regex"` because the reference implementation's own API surface
8
+ * accepts it as a well-formed request value — but its write chokepoint hard-rejects it
9
+ * unconditionally in v1 (its own matcher source literally comments "never actually reachable — validatePattern always rejects it
10
+ * at write time"). This is not a permission gate or a feature flag despite how it may look from the
11
+ * type alone: every `createRedirect`/`updateRedirect`/`importRedirects` call carrying `"regex"`
12
+ * fails validation, full stop, on the reference implementation. A panel must not offer `regex` as a
13
+ * selectable match type unless it has independently confirmed the host it's talking to actually
14
+ * implements it — do not infer support from this type accepting the literal.
15
+ *
16
+ * This is the "loudly-rejected input stays and gets documented" half of the rule `forms.ts`'s file
17
+ * header states in full (its counterpart, a silently-ignored input, is why that port's update patch
18
+ * has no `slug` field at all) — kept here because the union is OPEN and a different host may
19
+ * legitimately implement `regex` even though the reference implementation refuses it.
20
+ *
21
+ * ## `tombstoneRedirect` is a soft delete
22
+ *
23
+ * Mirrors `AdminIntegrationsPort.deleteIntegrationSubscription`, not `AdminMediaPort.deleteMedia`:
24
+ * the rule's `status` flips to `"disabled"` and the row is retained (audit trail, still readable
25
+ * via `listRedirects`/`getRedirect`), never hard-purged. The method resolves to the updated record
26
+ * (200-style), not `void` — a panel can render the new state without a re-fetch.
27
+ *
28
+ * ## `source: "auto_slug_change"` is read-only provenance
29
+ *
30
+ * Rows carrying this source are minted internally by the host's own content pipeline when a piece
31
+ * of content's slug changes (never-break-links) — it is not a value a caller chooses. It appears
32
+ * on `AdminRedirect.source` for display, but `AdminRedirectCreateInput` (used by both
33
+ * `createRedirect` and each item of `importRedirects`) has no `source` field at all: there is
34
+ * nothing to set. Do not offer `auto_slug_change` as a choice in a create/import form.
35
+ *
36
+ * ## `importRedirects` never fails as a whole
37
+ *
38
+ * The reference implementation's route always answers 207 Multi-Status: each rule is validated and written
39
+ * independently through the same path `createRedirect` uses, so one bad item never aborts the
40
+ * batch or rolls back already-written ones. Check `AdminRedirectImportResult.failed` for per-item
41
+ * rejections — a resolved promise here does not mean every rule in the batch was created.
42
+ *
43
+ * ## Open vs. closed unions
44
+ *
45
+ * `RedirectStatusCode` is CLOSED (`301 | 302 | 307 | 308`) — this is the complete set the
46
+ * reference implementation's write chokepoint accepts, and it is a subset of a real HTTP standard,
47
+ * not the reference implementation's to extend (a 5th caller-supplied code would need a 5th value
48
+ * here to be meaningful, and the reference server would reject it anyway). `RedirectMatchType`,
49
+ * `RedirectSource`, and `RedirectStatus` are reference-implementation-specific vocabularies that
50
+ * another host's routing engine will diverge from — OPEN, via the `T | (string & {})` idiom
51
+ * `seo.ts`'s file header introduces for this port
52
+ * set.
53
+ */
54
+ export {};
55
+ //# sourceMappingURL=redirects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirects.js","sourceRoot":"","sources":["../../../src/core/ports/redirects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * @file `AdminSeoPort` — per-entry SEO meta overrides layered over workspace-level defaults, plus
3
+ * the resolved output an editor/analyzer/renderer all consume, and a sitemap regeneration trigger.
4
+ *
5
+ * `entryId` throughout this port is an opaque host content-item id — this port does not know or
6
+ * care whether it names a post, a page, or anything else; the host resolves it against whatever
7
+ * object of its own owns SEO meta. No content-type vocabulary lives here.
8
+ *
9
+ * ## `putSeoEntry` resolves to the full effective meta, not an echo of your patch
10
+ *
11
+ * The reference implementation's route writes the raw override patch, then re-reads and returns
12
+ * the fully resolved `AdminSeoMeta` (override ▸ site default ▸ derived-from-content, per field) rather than
13
+ * the patch itself or the raw override bag. Concretely: patching only `title` can still change
14
+ * `openGraph.title` in the response, because an unset `ogTitle` override falls back to the
15
+ * (now-different) resolved `title`. Do not diff the response against the patch you sent to detect
16
+ * "what changed" — every field in the response reflects the full resolution, not just your edit.
17
+ *
18
+ * ## `regenerateSeoSitemap` is a fire-and-accept trigger, not a trackable job
19
+ *
20
+ * The reference implementation's route answers `202 Accepted` synchronously and hands back nothing but an
21
+ * acknowledgement — no job id, no status endpoint, no completion event on this contract. Mirrors
22
+ * `analytics.ts`'s stance on staying exactly as thin as the reference implementation: a host that
23
+ * needs progress/queueing semantics around regeneration needs a different, dedicated contract, not
24
+ * options bolted onto this method over time.
25
+ *
26
+ * ## Open vs. closed unions in this port (and the idiom used across this slice)
27
+ *
28
+ * `SeoOpenGraphType`/`SeoTwitterCardKind` are literal web standards (OpenGraph's `og:type`,
29
+ * Twitter/X's card kinds) — CLOSED, because there is no host-specific value space to widen; every
30
+ * implementer speaks the same vocabulary. `SeoIssueSeverity` is the reference implementation's own
31
+ * analysis-engine taxonomy (today just `error`/`warning`/`info`), not a standard, and a host's analyzer may grade
32
+ * findings more finely — OPEN, via the `T | (string & {})` widening idiom (preserves autocomplete
33
+ * on the known values while still accepting an arbitrary host-defined string). No widening idiom
34
+ * was established elsewhere in this port set before this slice; this file introduces it, and
35
+ * `redirects.ts`/`menus.ts`/`forms.ts` follow the same idiom for their own reference-implementation-
36
+ * specific unions rather than inventing their own.
37
+ */
38
+ /** OpenGraph object type (`og:type`) — closed, see file header. */
39
+ export type SeoOpenGraphType = "website" | "article" | "profile";
40
+ /** Twitter/X card kind — closed, see file header. */
41
+ export type SeoTwitterCardKind = "summary" | "summary_large_image";
42
+ /** Severity of one `AdminSeoIssue` — open, see file header. */
43
+ export type SeoIssueSeverity = "error" | "warning" | "info" | (string & {});
44
+ /**
45
+ * The author-authored override bag for one entry. Every field is OPTIONAL — omitting a field
46
+ * means "derive from site defaults / the content itself," not "clear it"; `putSeoEntry` merge-
47
+ * patches this bag onto whatever was previously stored; there is no way to unset a single
48
+ * previously-set field back to "derive" short of the host's own reset affordance (the reference
49
+ * implementation has none either).
50
+ */
51
+ export interface AdminSeoOverrides {
52
+ readonly title?: string;
53
+ readonly description?: string;
54
+ /** Accepted cross-domain as-is; a host may reject unsafe schemes (`javascript:`, `data:`, ...)
55
+ * server-side rather than this port validating client-side. */
56
+ readonly canonical?: string;
57
+ readonly noindex?: boolean;
58
+ readonly nofollow?: boolean;
59
+ /** schema.org `@type` override (else derived from content type). */
60
+ readonly schemaType?: string;
61
+ readonly ogTitle?: string;
62
+ readonly ogDescription?: string;
63
+ /** A media ref or absolute URL; resolved to a renderable URL in `AdminSeoMeta.openGraph.image`. */
64
+ readonly ogImage?: string;
65
+ readonly ogType?: SeoOpenGraphType;
66
+ readonly twitterCard?: SeoTwitterCardKind;
67
+ readonly twitterTitle?: string;
68
+ readonly twitterDescription?: string;
69
+ readonly twitterImage?: string;
70
+ }
71
+ export interface AdminSeoOpenGraph {
72
+ readonly title: string;
73
+ readonly description?: string;
74
+ readonly type: SeoOpenGraphType;
75
+ readonly url: string;
76
+ /** Already resolved to a renderable URL — never a media ref. */
77
+ readonly image?: string;
78
+ readonly siteName?: string;
79
+ }
80
+ export interface AdminSeoTwitterCard {
81
+ readonly card: SeoTwitterCardKind;
82
+ readonly title: string;
83
+ readonly description?: string;
84
+ readonly image?: string;
85
+ readonly site?: string;
86
+ }
87
+ export interface AdminSeoRobotsDirective {
88
+ readonly noindex: boolean;
89
+ readonly nofollow: boolean;
90
+ }
91
+ /** The fully-resolved effective meta for one entry — what `getSeoEntry`/`putSeoEntry` return and
92
+ * what `AdminSeoAnalysis.resolved` embeds. Never partial: every override/default/derivation
93
+ * decision is already made. */
94
+ export interface AdminSeoMeta {
95
+ readonly title: string;
96
+ readonly description?: string;
97
+ readonly canonical: string;
98
+ readonly robots: AdminSeoRobotsDirective;
99
+ readonly openGraph: AdminSeoOpenGraph;
100
+ readonly twitter: AdminSeoTwitterCard;
101
+ /** schema.org JSON-LD graph objects (`@context`/`@type`/...). Opaque to this port beyond being
102
+ * plain JSON objects. */
103
+ readonly jsonLd: readonly Record<string, unknown>[];
104
+ }
105
+ export interface AdminSeoIssue {
106
+ readonly code: string;
107
+ readonly severity: SeoIssueSeverity;
108
+ readonly message: string;
109
+ /** One of `AdminSeoMeta`'s top-level field names, when the issue is about a specific resolved
110
+ * field (e.g. `"title"`, `"description"`). Absent for a whole-entry issue. */
111
+ readonly field?: string;
112
+ }
113
+ export interface AdminSeoAnalysis {
114
+ readonly entryId: string;
115
+ readonly score: number;
116
+ readonly issues: readonly AdminSeoIssue[];
117
+ readonly resolved: AdminSeoMeta;
118
+ }
119
+ export interface AdminSeoRobotsRule {
120
+ readonly userAgent: string;
121
+ readonly allow?: readonly string[];
122
+ readonly disallow?: readonly string[];
123
+ }
124
+ /** Workspace-level SEO defaults every entry's resolution falls back to. */
125
+ export interface AdminSeoSettings {
126
+ /** e.g. `"%s — My Site"`; `%s` is substituted with the per-entry title. */
127
+ readonly titleTemplate: string;
128
+ readonly defaultDescription?: string;
129
+ readonly defaultOgImage?: string;
130
+ readonly twitterSite?: string;
131
+ readonly defaultRobots: AdminSeoRobotsDirective;
132
+ readonly sitemapEnabled: boolean;
133
+ readonly robotsRules: readonly AdminSeoRobotsRule[];
134
+ }
135
+ export interface AdminSeoPort {
136
+ getSeoEntry(entryId: string): Promise<AdminSeoMeta>;
137
+ /** Merge-patches the override bag and returns the newly-resolved meta — see file header. */
138
+ putSeoEntry(entryId: string, patch: AdminSeoOverrides): Promise<AdminSeoMeta>;
139
+ analyzeSeoEntry(entryId: string): Promise<AdminSeoAnalysis>;
140
+ getSeoSettings(): Promise<AdminSeoSettings>;
141
+ putSeoSettings(patch: Partial<AdminSeoSettings>): Promise<AdminSeoSettings>;
142
+ /** Fire-and-accept trigger, not a trackable job — see file header. */
143
+ regenerateSeoSitemap(): Promise<{
144
+ accepted: boolean;
145
+ }>;
146
+ }
147
+ //# sourceMappingURL=seo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../../src/core/ports/seo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @file `AdminSeoPort` — per-entry SEO meta overrides layered over workspace-level defaults, plus
3
+ * the resolved output an editor/analyzer/renderer all consume, and a sitemap regeneration trigger.
4
+ *
5
+ * `entryId` throughout this port is an opaque host content-item id — this port does not know or
6
+ * care whether it names a post, a page, or anything else; the host resolves it against whatever
7
+ * object of its own owns SEO meta. No content-type vocabulary lives here.
8
+ *
9
+ * ## `putSeoEntry` resolves to the full effective meta, not an echo of your patch
10
+ *
11
+ * The reference implementation's route writes the raw override patch, then re-reads and returns
12
+ * the fully resolved `AdminSeoMeta` (override ▸ site default ▸ derived-from-content, per field) rather than
13
+ * the patch itself or the raw override bag. Concretely: patching only `title` can still change
14
+ * `openGraph.title` in the response, because an unset `ogTitle` override falls back to the
15
+ * (now-different) resolved `title`. Do not diff the response against the patch you sent to detect
16
+ * "what changed" — every field in the response reflects the full resolution, not just your edit.
17
+ *
18
+ * ## `regenerateSeoSitemap` is a fire-and-accept trigger, not a trackable job
19
+ *
20
+ * The reference implementation's route answers `202 Accepted` synchronously and hands back nothing but an
21
+ * acknowledgement — no job id, no status endpoint, no completion event on this contract. Mirrors
22
+ * `analytics.ts`'s stance on staying exactly as thin as the reference implementation: a host that
23
+ * needs progress/queueing semantics around regeneration needs a different, dedicated contract, not
24
+ * options bolted onto this method over time.
25
+ *
26
+ * ## Open vs. closed unions in this port (and the idiom used across this slice)
27
+ *
28
+ * `SeoOpenGraphType`/`SeoTwitterCardKind` are literal web standards (OpenGraph's `og:type`,
29
+ * Twitter/X's card kinds) — CLOSED, because there is no host-specific value space to widen; every
30
+ * implementer speaks the same vocabulary. `SeoIssueSeverity` is the reference implementation's own
31
+ * analysis-engine taxonomy (today just `error`/`warning`/`info`), not a standard, and a host's analyzer may grade
32
+ * findings more finely — OPEN, via the `T | (string & {})` widening idiom (preserves autocomplete
33
+ * on the known values while still accepting an arbitrary host-defined string). No widening idiom
34
+ * was established elsewhere in this port set before this slice; this file introduces it, and
35
+ * `redirects.ts`/`menus.ts`/`forms.ts` follow the same idiom for their own reference-implementation-
36
+ * specific unions rather than inventing their own.
37
+ */
38
+ export {};
39
+ //# sourceMappingURL=seo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo.js","sourceRoot":"","sources":["../../../src/core/ports/seo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @file `AdminSettingsPort` — a layered settings ledger: global defaults, workspace overrides, and
3
+ * per-user overrides on top of those, resolved to one effective value per key.
4
+ *
5
+ * ## Why three layers, and why `getSettingsEffective` returns the resolved view, not the raw layers
6
+ *
7
+ * A setting's effective value is whichever of `user` (most specific), `workspace`, or `global`
8
+ * (least specific) has a value set, falling back to a compiled-in default when none do — that
9
+ * resolution is exactly what `getSettingsEffective` returns per key via `SettingResolvedValue`'s
10
+ * `sourceLayer`. There is deliberately no "list raw values across every layer" or "list every
11
+ * registered definition" method on this contract: the reference implementation does not
12
+ * have those routes server-side either (only the 5 operations below shipped), so a panel that needs
13
+ * to distinguish "the user override" from "everything else" composes two `getSettingsEffective`
14
+ * calls — one with `principalId` set, one without — and diffs them. That is an application-level
15
+ * technique, not something this port needs to special-case.
16
+ *
17
+ * ## `namespace` scopes every call
18
+ *
19
+ * Settings are grouped into namespaces (a plugin's own settings, a core feature's settings, ...);
20
+ * every method here operates within exactly one namespace at a time, never across all of them.
21
+ */
22
+ export type SettingScope = "global" | "workspace" | "user";
23
+ /** One key's fully-resolved effective value, as returned by `getSettingsEffective`. */
24
+ export interface SettingResolvedValue {
25
+ readonly key: string;
26
+ readonly value: unknown;
27
+ /** Which layer actually supplied `value` — `"default"` means no layer had an override and this
28
+ * is the compiled-in fallback. */
29
+ readonly sourceLayer: "user" | "workspace" | "global" | "default";
30
+ /** Version of the setting's definition (validation rules, default) this value was resolved
31
+ * against — a host may use this to detect a stale client against a since-changed definition. */
32
+ readonly defVersion: number;
33
+ }
34
+ /** The single value written or cleared, as returned by `setSetting`/`clearSetting`. */
35
+ export interface SettingValueResponse {
36
+ readonly key: string;
37
+ readonly scope: SettingScope;
38
+ readonly value: unknown;
39
+ /** Monotonic per-key revision counter — a host may use this for optimistic-concurrency or
40
+ * audit-ordering purposes. */
41
+ readonly revisionSeq: number;
42
+ }
43
+ /** The outcome of clearing an entire namespace at one scope, as returned by
44
+ * `resetSettingsNamespace`. */
45
+ export interface SettingResetResponse {
46
+ readonly namespace: string;
47
+ readonly clearedCount: number;
48
+ readonly revisionSeqs: readonly number[];
49
+ }
50
+ export interface AdminSettingsPort {
51
+ /**
52
+ * Resolved effective values for every key in `namespace`. Pass `principalId` to resolve as that
53
+ * principal would see it (i.e. including their `user`-scope overrides); omit it to resolve
54
+ * without any user layer — see the file header for the diff technique this enables.
55
+ */
56
+ getSettingsEffective(input: {
57
+ namespace: string;
58
+ }, options?: {
59
+ principalId?: string;
60
+ }): Promise<readonly SettingResolvedValue[]>;
61
+ /** Writes one key at one scope. `options.principalId` is required when `input.scope === "user"`
62
+ * (there is no "current user" implied server-side) and ignored otherwise. */
63
+ setSetting(input: {
64
+ namespace: string;
65
+ key: string;
66
+ scope: SettingScope;
67
+ value: unknown;
68
+ }, options?: {
69
+ principalId?: string;
70
+ }): Promise<SettingValueResponse>;
71
+ /** Removes one key's override at one scope, letting resolution fall through to the next layer
72
+ * down. Same `principalId` contract as `setSetting`. */
73
+ clearSetting(input: {
74
+ namespace: string;
75
+ key: string;
76
+ scope: SettingScope;
77
+ }, options?: {
78
+ principalId?: string;
79
+ }): Promise<SettingValueResponse>;
80
+ /** Clears every key in `namespace` at one scope in one call — the bulk counterpart to repeated
81
+ * `clearSetting` calls, and typically cheaper for a host to implement atomically. */
82
+ resetSettingsNamespace(input: {
83
+ namespace: string;
84
+ scope: SettingScope;
85
+ }): Promise<SettingResetResponse>;
86
+ }
87
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/core/ports/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;AAE3D,uFAAuF;AACvF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;uCACmC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAClE;qGACiG;IACjG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,uFAAuF;AACvF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;mCAC+B;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;gCACgC;AAChC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,oBAAoB,CAClB,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,EAC5B,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACjC,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;IAC5C;kFAC8E;IAC9E,UAAU,CACR,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAC9E,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC;6DACyD;IACzD,YAAY,CACV,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,EAC9D,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC;0FACsF;IACtF,sBAAsB,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC1G"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file `AdminSettingsPort` — a layered settings ledger: global defaults, workspace overrides, and
3
+ * per-user overrides on top of those, resolved to one effective value per key.
4
+ *
5
+ * ## Why three layers, and why `getSettingsEffective` returns the resolved view, not the raw layers
6
+ *
7
+ * A setting's effective value is whichever of `user` (most specific), `workspace`, or `global`
8
+ * (least specific) has a value set, falling back to a compiled-in default when none do — that
9
+ * resolution is exactly what `getSettingsEffective` returns per key via `SettingResolvedValue`'s
10
+ * `sourceLayer`. There is deliberately no "list raw values across every layer" or "list every
11
+ * registered definition" method on this contract: the reference implementation does not
12
+ * have those routes server-side either (only the 5 operations below shipped), so a panel that needs
13
+ * to distinguish "the user override" from "everything else" composes two `getSettingsEffective`
14
+ * calls — one with `principalId` set, one without — and diffs them. That is an application-level
15
+ * technique, not something this port needs to special-case.
16
+ *
17
+ * ## `namespace` scopes every call
18
+ *
19
+ * Settings are grouped into namespaces (a plugin's own settings, a core feature's settings, ...);
20
+ * every method here operates within exactly one namespace at a time, never across all of them.
21
+ */
22
+ export {};
23
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/core/ports/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @file `AdminWorkspacePort` — the tenant/site the admin is currently operating on.
3
+ *
4
+ * ## This port models tenancy generically; the reference implementation's own client does not
5
+ *
6
+ * The reference implementation's API client hard-codes a single workspace id constant and bakes
7
+ * that constant into every route it builds (`/workspaces/${WORKSPACE_ID}/...`) — it is a
8
+ * single-workspace-per-instance product today, and its client reflects that. This port deliberately does
9
+ * not carry a workspace id as a parameter on any method here: each method operates on "the
10
+ * workspace the current client/transport is scoped to". A genuinely multi-workspace host resolves
11
+ * *which* workspace that is at the transport/route-group-factory layer (a later, per-host slice —
12
+ * e.g. constructing one client per workspace, or a factory parameterized by workspace id), not by
13
+ * threading an id through every call on this port. Baking a `workspaceId` parameter into every
14
+ * method here would be designing for a host shape (multi-workspace-per-client) that does not yet
15
+ * exist anywhere in the corpus this port was derived from.
16
+ *
17
+ * ## `deleteWorkspace` exists on the contract; the reference implementation always refuses it
18
+ *
19
+ * The reference implementation's `DELETE /workspaces/:id` route is real and reachable, but its
20
+ * write-path unconditionally rejects with a `LAST_WORKSPACE`-class conflict when deleting would
21
+ * leave zero workspaces — which, in a single-workspace-per-instance deployment, is every call. The
22
+ * method stays on this port because the guard is a product policy of *today's* reference
23
+ * deployment, not a
24
+ * statement that workspace deletion is meaningless in general; a host that supports genuinely
25
+ * disposable workspaces needs this method to work. A panel built against this port should not
26
+ * assume `deleteWorkspace` succeeds just because the call is well-formed and authorized.
27
+ */
28
+ /** The workspace (tenant/site) itself. */
29
+ export interface AdminWorkspace {
30
+ readonly id: string;
31
+ readonly name: string;
32
+ readonly slug: string;
33
+ readonly createdAt: string;
34
+ }
35
+ export interface AdminWorkspacePort {
36
+ getWorkspace(): Promise<AdminWorkspace>;
37
+ updateWorkspace(patch: {
38
+ name?: string;
39
+ slug?: string;
40
+ }): Promise<AdminWorkspace>;
41
+ /** May unconditionally reject — see the file header. */
42
+ deleteWorkspace(): Promise<void>;
43
+ }
44
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/core/ports/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,eAAe,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAClF,wDAAwD;IACxD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @file `AdminWorkspacePort` — the tenant/site the admin is currently operating on.
3
+ *
4
+ * ## This port models tenancy generically; the reference implementation's own client does not
5
+ *
6
+ * The reference implementation's API client hard-codes a single workspace id constant and bakes
7
+ * that constant into every route it builds (`/workspaces/${WORKSPACE_ID}/...`) — it is a
8
+ * single-workspace-per-instance product today, and its client reflects that. This port deliberately does
9
+ * not carry a workspace id as a parameter on any method here: each method operates on "the
10
+ * workspace the current client/transport is scoped to". A genuinely multi-workspace host resolves
11
+ * *which* workspace that is at the transport/route-group-factory layer (a later, per-host slice —
12
+ * e.g. constructing one client per workspace, or a factory parameterized by workspace id), not by
13
+ * threading an id through every call on this port. Baking a `workspaceId` parameter into every
14
+ * method here would be designing for a host shape (multi-workspace-per-client) that does not yet
15
+ * exist anywhere in the corpus this port was derived from.
16
+ *
17
+ * ## `deleteWorkspace` exists on the contract; the reference implementation always refuses it
18
+ *
19
+ * The reference implementation's `DELETE /workspaces/:id` route is real and reachable, but its
20
+ * write-path unconditionally rejects with a `LAST_WORKSPACE`-class conflict when deleting would
21
+ * leave zero workspaces — which, in a single-workspace-per-instance deployment, is every call. The
22
+ * method stays on this port because the guard is a product policy of *today's* reference
23
+ * deployment, not a
24
+ * statement that workspace deletion is meaningless in general; a host that supports genuinely
25
+ * disposable workspaces needs this method to work. A panel built against this port should not
26
+ * assume `deleteWorkspace` succeeds just because the call is well-formed and authorized.
27
+ */
28
+ export {};
29
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/core/ports/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG"}