@happyvertical/smrt-content 0.40.65 → 0.40.67

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.
@@ -0,0 +1,719 @@
1
+ import { t as playground_default } from "./chunks/playground-DryZ2Hm_.js";
2
+ import ContentContributionsRoute from "./svelte/routes/ContentContributionsRoute.svelte";
3
+ import ContentFactsRoute from "./svelte/routes/ContentFactsRoute.svelte";
4
+ import ContentGovernanceRoute from "./svelte/routes/ContentGovernanceRoute.svelte";
5
+ import ContentWorkspaceRoute from "./svelte/routes/ContentWorkspaceRoute.svelte";
6
+ import PublishedArticleRoute from "./svelte/routes/PublishedArticleRoute.svelte";
7
+ //#region src/route-loaders.ts
8
+ function createContentRouteLoadError(status, message, code) {
9
+ const error = new Error(message);
10
+ error.name = "ContentRouteLoadError";
11
+ error.status = status;
12
+ error.code = code;
13
+ return error;
14
+ }
15
+ function getItemData(payload) {
16
+ if (!payload || typeof payload !== "object") return payload;
17
+ const wrappedPayload = payload;
18
+ if ("result" in wrappedPayload) return wrappedPayload.result;
19
+ if ("data" in wrappedPayload) return wrappedPayload.data;
20
+ return payload;
21
+ }
22
+ async function loadPublishedArticleRouteData({ fetch, slug, apiBasePath = "/api/v1" }) {
23
+ const contentResponse = await fetch(`${apiBasePath}/contents/by-slug?${new URLSearchParams({
24
+ slug,
25
+ status: "published"
26
+ }).toString()}`);
27
+ if (!contentResponse.ok) throw createContentRouteLoadError(contentResponse.status, "Failed to load article", "content_fetch_failed");
28
+ const content = getItemData(await contentResponse.json());
29
+ if (!content?.id) throw createContentRouteLoadError(404, "Article not found", "content_not_found");
30
+ const transparencyResponse = await fetch(`${apiBasePath}/contents/${content.id}/transparency`);
31
+ if (!transparencyResponse.ok) throw createContentRouteLoadError(transparencyResponse.status, "Failed to load transparency", "transparency_fetch_failed");
32
+ return {
33
+ content,
34
+ transparency: getItemData(await transparencyResponse.json())
35
+ };
36
+ }
37
+ //#endregion
38
+ //#region src/svelte/routes/shared.ts
39
+ var CONTENT_ROUTE_IDS = {
40
+ workspace: "content.workspace",
41
+ facts: "content.facts",
42
+ governance: "content.governance",
43
+ contributions: "content.contributions",
44
+ article: "content.article"
45
+ };
46
+ var CONTENT_ROUTE_META = {
47
+ workspace: {
48
+ id: CONTENT_ROUTE_IDS.workspace,
49
+ title: "Contents",
50
+ description: "Author, review, and publish content records against the content module workflows.",
51
+ defaultPath: "/workspace",
52
+ nav: {
53
+ label: "Workspace",
54
+ description: "Authoring and publishing workspace",
55
+ icon: "file-text",
56
+ order: 10,
57
+ group: "content"
58
+ }
59
+ },
60
+ governance: {
61
+ id: CONTENT_ROUTE_IDS.governance,
62
+ title: "Governance Admin",
63
+ description: "Manage review policies, profiles, and publication assignments for governed content.",
64
+ defaultPath: "/governance",
65
+ nav: {
66
+ label: "Governance",
67
+ description: "Policy, profile, and assignment management",
68
+ icon: "shield-check",
69
+ order: 20,
70
+ group: "content"
71
+ }
72
+ },
73
+ facts: {
74
+ id: CONTENT_ROUTE_IDS.facts,
75
+ title: "Fact Catalog",
76
+ description: "Browse extracted facts, search by text or domain, and confirm what content workflows can cite.",
77
+ defaultPath: "/facts",
78
+ nav: {
79
+ label: "Facts",
80
+ description: "Browse indexed facts and confidence",
81
+ icon: "sparkles",
82
+ order: 15,
83
+ group: "content"
84
+ }
85
+ },
86
+ contributions: {
87
+ id: CONTENT_ROUTE_IDS.contributions,
88
+ title: "Contribution Intake and Review",
89
+ description: "Review contributor submissions, moderation state, and promotion flows into content.",
90
+ defaultPath: "/contributions",
91
+ nav: {
92
+ label: "Contributions",
93
+ description: "Contributor intake, moderation, and promotion",
94
+ icon: "inbox",
95
+ order: 30,
96
+ group: "content"
97
+ }
98
+ },
99
+ article: {
100
+ id: CONTENT_ROUTE_IDS.article,
101
+ title: "Published article",
102
+ description: "Render a published content record with its public transparency information.",
103
+ defaultPath: "/articles/[slug]",
104
+ loadKind: "page"
105
+ }
106
+ };
107
+ var CONTENT_NAV_ROUTE_KEYS = [
108
+ "workspace",
109
+ "facts",
110
+ "governance",
111
+ "contributions"
112
+ ];
113
+ function createContentRouteNavigation(pathOverrides = {}) {
114
+ return CONTENT_NAV_ROUTE_KEYS.map((routeKey) => {
115
+ const route = CONTENT_ROUTE_META[routeKey];
116
+ return {
117
+ routeId: route.id,
118
+ href: pathOverrides[route.id] || route.defaultPath,
119
+ label: route.nav.label,
120
+ description: route.nav.description,
121
+ icon: route.nav.icon,
122
+ order: route.nav.order,
123
+ group: route.nav.group
124
+ };
125
+ }).sort((left, right) => (left.order || 0) - (right.order || 0));
126
+ }
127
+ createContentRouteNavigation();
128
+ //#endregion
129
+ //#region src/route-module.ts
130
+ var CONTENT_ROUTE_MODULE = {
131
+ packageName: "@happyvertical/smrt-content",
132
+ displayName: "Content",
133
+ description: "Package-owned route surfaces for authoring, facts, governance, contributions, and published article rendering.",
134
+ routes: {
135
+ workspace: {
136
+ ...CONTENT_ROUTE_META.workspace,
137
+ component: ContentWorkspaceRoute,
138
+ tags: [
139
+ "content",
140
+ "authoring",
141
+ "admin"
142
+ ]
143
+ },
144
+ facts: {
145
+ ...CONTENT_ROUTE_META.facts,
146
+ component: ContentFactsRoute,
147
+ tags: [
148
+ "content",
149
+ "facts",
150
+ "admin"
151
+ ]
152
+ },
153
+ governance: {
154
+ ...CONTENT_ROUTE_META.governance,
155
+ component: ContentGovernanceRoute,
156
+ tags: [
157
+ "content",
158
+ "governance",
159
+ "admin"
160
+ ]
161
+ },
162
+ contributions: {
163
+ ...CONTENT_ROUTE_META.contributions,
164
+ component: ContentContributionsRoute,
165
+ tags: [
166
+ "content",
167
+ "contributions",
168
+ "admin"
169
+ ]
170
+ },
171
+ article: {
172
+ ...CONTENT_ROUTE_META.article,
173
+ component: PublishedArticleRoute,
174
+ load: loadPublishedArticleRouteData,
175
+ tags: [
176
+ "content",
177
+ "article",
178
+ "public"
179
+ ]
180
+ }
181
+ }
182
+ };
183
+ //#endregion
184
+ //#region src/workbench.ts
185
+ var sampleContents = [{
186
+ id: "content-workbench-brief",
187
+ slug: "workbench-editorial-brief",
188
+ title: "Workbench Editorial Brief",
189
+ description: "A draft content record used to exercise the shared route shell.",
190
+ body: "## Editorial Brief\n\nThis fixture is served by the workbench route module so the authoring route can render inline.",
191
+ bodyFormat: "markdown",
192
+ author: "Content Systems",
193
+ type: "article",
194
+ status: "draft",
195
+ state: "active",
196
+ source: "manual",
197
+ factIds: ["fact-workbench-route"],
198
+ createdAt: "2026-03-20T12:00:00.000Z",
199
+ updatedAt: "2026-03-20T12:00:00.000Z"
200
+ }, {
201
+ id: "content-workbench-published",
202
+ slug: "shared-route-workbench",
203
+ title: "Shared Route Workbench",
204
+ description: "Published sample content with a slug so the workspace can show the public route affordance.",
205
+ body: "Shared routes render inside one Workbench app instead of redirecting to package-local dev servers.",
206
+ bodyFormat: "markdown",
207
+ author: "Content Ops",
208
+ type: "article",
209
+ status: "published",
210
+ state: "active",
211
+ source: "manual",
212
+ publish_date: "2026-03-21T09:00:00.000Z",
213
+ factIds: ["fact-workbench-route", "fact-governance-visible"],
214
+ createdAt: "2026-03-19T15:00:00.000Z",
215
+ updatedAt: "2026-03-21T09:00:00.000Z"
216
+ }];
217
+ var sampleFacts = [{
218
+ id: "fact-workbench-route",
219
+ textRaw: "Workbench route demos render inside the shared workbench host.",
220
+ textRefined: "Workbench route demos render inside the shared workbench host.",
221
+ status: "active",
222
+ domain: "developer-tools",
223
+ confidence: .94,
224
+ sourceCount: 3,
225
+ metadata: {
226
+ package: "@happyvertical/smrt-content",
227
+ source: "workbench"
228
+ },
229
+ createdAt: "2026-03-20T12:00:00.000Z",
230
+ updatedAt: "2026-03-20T12:00:00.000Z"
231
+ }, {
232
+ id: "fact-governance-visible",
233
+ textRaw: "Governance policies should be visible before publishing.",
234
+ textRefined: "Governance policies should be visible before publishing.",
235
+ status: "active",
236
+ domain: "content-governance",
237
+ confidence: .88,
238
+ sourceCount: 2,
239
+ metadata: { policy: "facts" },
240
+ createdAt: "2026-03-18T16:00:00.000Z",
241
+ updatedAt: "2026-03-19T10:00:00.000Z"
242
+ }];
243
+ var sampleGovernanceDefinitions = {
244
+ effective: {
245
+ policies: [{
246
+ id: "policy-facts",
247
+ key: "facts",
248
+ label: "Facts review",
249
+ kind: "facts",
250
+ instructions: "Compare claims against linked facts before publication.",
251
+ enabled: true
252
+ }, {
253
+ id: "policy-style",
254
+ key: "style",
255
+ label: "Style review",
256
+ kind: "custom",
257
+ instructions: "Apply editorial style and clarity guidelines.",
258
+ enabled: true
259
+ }],
260
+ profiles: [{
261
+ id: "profile-publication",
262
+ key: "publication",
263
+ label: "Publication",
264
+ description: "Required before governed content can be published.",
265
+ enabled: true,
266
+ requirements: [{
267
+ policyKey: "facts",
268
+ label: "Facts review",
269
+ blocking: true,
270
+ acceptedStatuses: ["passed"]
271
+ }, {
272
+ policyKey: "style",
273
+ label: "Style review",
274
+ blocking: false,
275
+ acceptedStatuses: ["passed", "warning"]
276
+ }]
277
+ }],
278
+ assignments: [{
279
+ id: "assignment-article",
280
+ key: "article",
281
+ label: "Articles",
282
+ contentType: "article",
283
+ contentVariant: null,
284
+ enabled: true,
285
+ factLinkingEnabled: true,
286
+ transparencyEnabled: true,
287
+ publicationProfileKey: "publication",
288
+ correctionProfileKey: null,
289
+ enforcePublishReadiness: true,
290
+ defaultFactRelationship: "supports"
291
+ }]
292
+ },
293
+ persisted: {
294
+ policies: [{
295
+ id: "policy-style",
296
+ key: "style",
297
+ label: "Style review",
298
+ kind: "custom",
299
+ instructions: "Apply editorial style and clarity guidelines.",
300
+ enabled: true
301
+ }],
302
+ profiles: [{
303
+ id: "profile-publication",
304
+ key: "publication",
305
+ label: "Publication",
306
+ description: "Required before governed content can be published.",
307
+ enabled: true,
308
+ requirements: [{
309
+ policyKey: "facts",
310
+ label: "Facts review",
311
+ blocking: true,
312
+ acceptedStatuses: ["passed"]
313
+ }, {
314
+ policyKey: "style",
315
+ label: "Style review",
316
+ blocking: false,
317
+ acceptedStatuses: ["passed", "warning"]
318
+ }]
319
+ }],
320
+ assignments: [{
321
+ id: "assignment-article",
322
+ key: "article",
323
+ label: "Articles",
324
+ contentType: "article",
325
+ contentVariant: null,
326
+ enabled: true,
327
+ factLinkingEnabled: true,
328
+ transparencyEnabled: true,
329
+ publicationProfileKey: "publication",
330
+ correctionProfileKey: null,
331
+ enforcePublishReadiness: true,
332
+ defaultFactRelationship: "supports"
333
+ }]
334
+ }
335
+ };
336
+ var sampleContributionTypes = [{
337
+ id: "type-article",
338
+ key: "article",
339
+ label: "Article pitch",
340
+ enabled: true,
341
+ allowedChannels: ["web", "email"],
342
+ allowText: true,
343
+ allowFiles: true,
344
+ allowEmptyText: false,
345
+ intakeRules: { requireTitle: true }
346
+ }, {
347
+ id: "type-field-report",
348
+ key: "field-report",
349
+ label: "Field report",
350
+ enabled: true,
351
+ allowedChannels: ["web"],
352
+ allowText: true,
353
+ allowFiles: false,
354
+ allowEmptyText: false
355
+ }];
356
+ var sampleContributors = [{
357
+ id: "contributor-taylor",
358
+ email: "taylor@example.com",
359
+ name: "Taylor Rowan",
360
+ trustLevel: "trusted"
361
+ }, {
362
+ id: "contributor-jordan",
363
+ email: "jordan@example.com",
364
+ name: "Jordan Lee",
365
+ trustLevel: "new"
366
+ }];
367
+ var sampleContributions = [{
368
+ id: "contribution-spring-guide",
369
+ contributorId: "contributor-taylor",
370
+ contributionTypeKey: "article",
371
+ status: "needs_changes",
372
+ intakeDecision: "needs_changes",
373
+ channel: "web",
374
+ title: "Spring buyer guide",
375
+ description: "Draft guide with sourcing notes for editorial review.",
376
+ body: "The spring buyer guide draft includes product comparisons and sourcing notes.",
377
+ contributorEmail: "taylor@example.com",
378
+ contributorName: "Taylor Rowan",
379
+ revisionCount: 2,
380
+ editorNotes: "Please tighten the sourcing notes in the opening section.",
381
+ updatedAt: "2026-03-20T15:18:00.000Z"
382
+ }, {
383
+ id: "contribution-field-report",
384
+ contributorId: "contributor-jordan",
385
+ contributionTypeKey: "field-report",
386
+ status: "submitted",
387
+ intakeDecision: "submitted",
388
+ channel: "web",
389
+ title: "Field report: Pacific logistics",
390
+ description: "Field notes from the Pacific corridor.",
391
+ body: "Updated shipping windows, route constraints, and operator interviews.",
392
+ contributorEmail: "jordan@example.com",
393
+ contributorName: "Jordan Lee",
394
+ revisionCount: 1,
395
+ updatedAt: "2026-03-18T10:40:00.000Z"
396
+ }];
397
+ function cloneValue(value) {
398
+ if (value === void 0) return value;
399
+ return JSON.parse(JSON.stringify(value));
400
+ }
401
+ function buildResponse(data) {
402
+ return {
403
+ data: cloneValue(data),
404
+ success: true
405
+ };
406
+ }
407
+ function upsertByIdOrKey(items, value, prefix) {
408
+ const id = value.id || `${prefix}-${value.key || items.length + 1}`;
409
+ const nextValue = {
410
+ ...value,
411
+ id
412
+ };
413
+ const index = items.findIndex((item) => item.id === id || Boolean(value.key && item.key === value.key));
414
+ if (index === -1) return [...items, nextValue];
415
+ const nextItems = [...items];
416
+ nextItems[index] = {
417
+ ...nextItems[index],
418
+ ...nextValue
419
+ };
420
+ return nextItems;
421
+ }
422
+ function createContentWorkbenchClient() {
423
+ let contents = cloneValue(sampleContents);
424
+ let facts = cloneValue(sampleFacts);
425
+ let policies = cloneValue(sampleGovernanceDefinitions.effective.policies);
426
+ let profiles = cloneValue(sampleGovernanceDefinitions.effective.profiles);
427
+ let assignments = cloneValue(sampleGovernanceDefinitions.effective.assignments);
428
+ let contributionTypes = cloneValue(sampleContributionTypes);
429
+ let contributors = cloneValue(sampleContributors);
430
+ let contributions = cloneValue(sampleContributions);
431
+ const getDefinitions = () => ({
432
+ effective: {
433
+ policies: cloneValue(policies),
434
+ profiles: cloneValue(profiles),
435
+ assignments: cloneValue(assignments)
436
+ },
437
+ persisted: {
438
+ policies: cloneValue(policies),
439
+ profiles: cloneValue(profiles),
440
+ assignments: cloneValue(assignments)
441
+ }
442
+ });
443
+ const resolveGovernance = (type, variant) => {
444
+ const assignment = assignments.find((item) => item.contentType === type && (item.contentVariant || null) === (variant || null)) || assignments.find((item) => item.contentType === type) || assignments[0] || null;
445
+ return {
446
+ isGoverned: Boolean(assignment),
447
+ factLinkingEnabled: assignment?.factLinkingEnabled ?? true,
448
+ transparencyEnabled: assignment?.transparencyEnabled ?? true,
449
+ publicationProfileKey: assignment?.publicationProfileKey || null,
450
+ correctionProfileKey: assignment?.correctionProfileKey || null,
451
+ enforcePublishReadiness: assignment?.enforcePublishReadiness ?? Boolean(assignment),
452
+ defaultFactRelationship: assignment?.defaultFactRelationship || "supports",
453
+ reviewPolicies: cloneValue(policies),
454
+ availableProfiles: cloneValue(profiles),
455
+ assignment: cloneValue(assignment)
456
+ };
457
+ };
458
+ const updateContributionStatus = (id, status, extra = {}) => {
459
+ contributions = contributions.map((item) => item.id === id ? {
460
+ ...item,
461
+ status,
462
+ intakeDecision: status,
463
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
464
+ ...extra
465
+ } : item);
466
+ return contributions.find((item) => item.id === id) || null;
467
+ };
468
+ const getContributionTypes = () => ({
469
+ effective: cloneValue(contributionTypes),
470
+ persisted: cloneValue(contributionTypes)
471
+ });
472
+ return {
473
+ contents: {
474
+ list: async () => buildResponse(contents),
475
+ get: async (id) => buildResponse(contents.find((item) => item.id === id) || contents[0]),
476
+ create: async (content) => {
477
+ const nextContent = {
478
+ type: "article",
479
+ status: "draft",
480
+ state: "active",
481
+ source: "manual",
482
+ ...content,
483
+ id: content.id || `content-workbench-${contents.length + 1}`,
484
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
485
+ };
486
+ contents = [nextContent, ...contents];
487
+ return buildResponse(nextContent);
488
+ },
489
+ update: async (id, updates) => {
490
+ contents = contents.map((item) => item.id === id ? {
491
+ ...item,
492
+ ...updates,
493
+ id,
494
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
495
+ } : item);
496
+ return buildResponse(contents.find((item) => item.id === id) || contents[0]);
497
+ },
498
+ delete: async (id) => {
499
+ contents = contents.filter((item) => item.id !== id);
500
+ return buildResponse(void 0);
501
+ },
502
+ browseFacts: async (query = "", _options = {}) => {
503
+ const normalizedQuery = query.trim().toLowerCase();
504
+ facts = cloneValue(sampleFacts);
505
+ return buildResponse(normalizedQuery ? facts.filter((fact) => [
506
+ fact.textRaw,
507
+ fact.textRefined,
508
+ fact.domain,
509
+ JSON.stringify(fact.metadata || {})
510
+ ].join(" ").toLowerCase().includes(normalizedQuery)) : facts);
511
+ },
512
+ getGovernanceDefinitions: async () => buildResponse(getDefinitions()),
513
+ resolveGovernance: async (options) => buildResponse(resolveGovernance(options.type, options.variant))
514
+ },
515
+ contentGovernancePolicies: {
516
+ create: async (policy) => {
517
+ policies = upsertByIdOrKey(policies, policy, "policy");
518
+ return buildResponse(policies[policies.length - 1]);
519
+ },
520
+ update: async (id, policy) => {
521
+ policies = upsertByIdOrKey(policies, {
522
+ ...policy,
523
+ id
524
+ }, "policy");
525
+ return buildResponse(policies.find((item) => item.id === id) || policies[0]);
526
+ },
527
+ delete: async (id) => {
528
+ policies = policies.filter((item) => item.id !== id);
529
+ return buildResponse(void 0);
530
+ }
531
+ },
532
+ contentGovernanceProfiles: {
533
+ create: async (profile) => {
534
+ profiles = upsertByIdOrKey(profiles, profile, "profile");
535
+ return buildResponse(profiles[profiles.length - 1]);
536
+ },
537
+ update: async (id, profile) => {
538
+ profiles = upsertByIdOrKey(profiles, {
539
+ ...profile,
540
+ id
541
+ }, "profile");
542
+ return buildResponse(profiles.find((item) => item.id === id) || profiles[0]);
543
+ },
544
+ delete: async (id) => {
545
+ profiles = profiles.filter((item) => item.id !== id);
546
+ return buildResponse(void 0);
547
+ }
548
+ },
549
+ contentGovernanceAssignments: {
550
+ create: async (assignment) => {
551
+ assignments = upsertByIdOrKey(assignments, assignment, "assignment");
552
+ return buildResponse(assignments[assignments.length - 1]);
553
+ },
554
+ update: async (id, assignment) => {
555
+ assignments = upsertByIdOrKey(assignments, {
556
+ ...assignment,
557
+ id
558
+ }, "assignment");
559
+ return buildResponse(assignments.find((item) => item.id === id) || assignments[0]);
560
+ },
561
+ delete: async (id) => {
562
+ assignments = assignments.filter((item) => item.id !== id);
563
+ return buildResponse(void 0);
564
+ }
565
+ },
566
+ contentContributions: {
567
+ getContributionTypes: async () => buildResponse(getContributionTypes()),
568
+ listInbox: async () => buildResponse(contributions),
569
+ listForContributor: async (options) => buildResponse(contributions.filter((item) => options.contributorId ? item.contributorId === options.contributorId : item.contributorEmail === options.contributorEmail)),
570
+ submitWebContribution: async (payload) => {
571
+ const contributor = contributors.find((item) => item.email === payload.contributorEmail);
572
+ const nextContribution = {
573
+ id: `contribution-workbench-${contributions.length + 1}`,
574
+ contributorId: contributor?.id,
575
+ contributionTypeKey: payload.typeKey || payload.contributionTypeKey,
576
+ status: "submitted",
577
+ intakeDecision: "submitted",
578
+ channel: "web",
579
+ title: payload.title,
580
+ description: payload.description,
581
+ body: payload.body,
582
+ contributorEmail: payload.contributorEmail,
583
+ contributorName: payload.contributorName,
584
+ revisionCount: 1,
585
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
586
+ };
587
+ contributions = [nextContribution, ...contributions];
588
+ return buildResponse({ contribution: nextContribution });
589
+ },
590
+ ingestEmailContribution: async (payload) => buildResponse({ contribution: {
591
+ ...payload,
592
+ id: `contribution-email-${contributions.length + 1}`,
593
+ status: "submitted"
594
+ } }),
595
+ appendRevision: async (id) => buildResponse(updateContributionStatus(id, "submitted", { revisionCount: (contributions.find((item) => item.id === id)?.revisionCount || 0) + 1 })),
596
+ requestChanges: async (id) => buildResponse(updateContributionStatus(id, "needs_changes")),
597
+ approve: async (id) => buildResponse(updateContributionStatus(id, "approved", { approvedAt: (/* @__PURE__ */ new Date()).toISOString() })),
598
+ reject: async (id) => buildResponse(updateContributionStatus(id, "rejected", { rejectedAt: (/* @__PURE__ */ new Date()).toISOString() })),
599
+ withdraw: async (id) => buildResponse(updateContributionStatus(id, "withdrawn", { withdrawnAt: (/* @__PURE__ */ new Date()).toISOString() })),
600
+ promote: async (id) => buildResponse(updateContributionStatus(id, "promoted", { promotedAt: (/* @__PURE__ */ new Date()).toISOString() }))
601
+ },
602
+ contentContributionTypes: {
603
+ create: async (type) => {
604
+ contributionTypes = upsertByIdOrKey(contributionTypes, type, "contribution-type");
605
+ return buildResponse(contributionTypes[contributionTypes.length - 1]);
606
+ },
607
+ update: async (id, type) => {
608
+ contributionTypes = upsertByIdOrKey(contributionTypes, {
609
+ ...type,
610
+ id
611
+ }, "contribution-type");
612
+ return buildResponse(contributionTypes.find((item) => item.id === id) || contributionTypes[0]);
613
+ },
614
+ delete: async (id) => {
615
+ contributionTypes = contributionTypes.filter((item) => item.id !== id);
616
+ return buildResponse(void 0);
617
+ }
618
+ },
619
+ contentContributors: {
620
+ list: async () => buildResponse(contributors),
621
+ create: async (contributor) => {
622
+ const nextContributor = {
623
+ ...contributor,
624
+ id: contributor.id || `contributor-${contributors.length + 1}`
625
+ };
626
+ contributors = [nextContributor, ...contributors];
627
+ return buildResponse(nextContributor);
628
+ },
629
+ update: async (id, contributor) => {
630
+ contributors = contributors.map((item) => item.id === id ? {
631
+ ...item,
632
+ ...contributor,
633
+ id
634
+ } : item);
635
+ return buildResponse(contributors.find((item) => item.id === id) || contributors[0]);
636
+ },
637
+ delete: async (id) => {
638
+ contributors = contributors.filter((item) => item.id !== id);
639
+ return buildResponse(void 0);
640
+ }
641
+ }
642
+ };
643
+ }
644
+ var contentRouteProps = {
645
+ embedded: true,
646
+ client: createContentWorkbenchClient(),
647
+ navigation: createContentRouteNavigation({
648
+ [CONTENT_ROUTE_IDS.workspace]: "#content-workspace",
649
+ [CONTENT_ROUTE_IDS.facts]: "#content-facts",
650
+ [CONTENT_ROUTE_IDS.governance]: "#content-governance",
651
+ [CONTENT_ROUTE_IDS.contributions]: "#content-contributions"
652
+ })
653
+ };
654
+ var articleRouteData = {
655
+ content: {
656
+ id: "workbench-article",
657
+ slug: "workbench-reference-article",
658
+ title: "Workbench Reference Article",
659
+ description: "Inline route sample rendered inside the shared SMRT workbench.",
660
+ author: "Content Systems",
661
+ body: "## Reference Article\n\nThis article route is rendered without redirecting to a package-local dev server.",
662
+ bodyFormat: "markdown",
663
+ publish_date: "2026-03-20T12:00:00.000Z",
664
+ status: "published"
665
+ },
666
+ transparency: null
667
+ };
668
+ var workbench_default = {
669
+ packageName: "@happyvertical/smrt-content",
670
+ displayName: "Content",
671
+ description: "Workbench surfaces for content authoring, governance, facts, contributions, articles, and package previews.",
672
+ routeModules: [{
673
+ ...CONTENT_ROUTE_MODULE,
674
+ routes: {
675
+ workspace: {
676
+ ...CONTENT_ROUTE_MODULE.routes.workspace,
677
+ props: contentRouteProps
678
+ },
679
+ facts: {
680
+ ...CONTENT_ROUTE_MODULE.routes.facts,
681
+ props: contentRouteProps
682
+ },
683
+ governance: {
684
+ ...CONTENT_ROUTE_MODULE.routes.governance,
685
+ props: contentRouteProps
686
+ },
687
+ contributions: {
688
+ ...CONTENT_ROUTE_MODULE.routes.contributions,
689
+ props: contentRouteProps
690
+ },
691
+ article: {
692
+ ...CONTENT_ROUTE_MODULE.routes.article,
693
+ props: {
694
+ data: articleRouteData,
695
+ backHref: "#content-workspace"
696
+ }
697
+ }
698
+ }
699
+ }],
700
+ recommendedCommands: [{
701
+ id: "content:test",
702
+ label: "Test",
703
+ command: "pnpm --filter @happyvertical/smrt-content test"
704
+ }, {
705
+ id: "content:typecheck",
706
+ label: "Typecheck",
707
+ command: "pnpm --filter @happyvertical/smrt-content typecheck"
708
+ }],
709
+ examples: [{
710
+ id: "content:playground",
711
+ title: "Content playground module",
712
+ path: "src/svelte/playground.ts",
713
+ source: "playground"
714
+ }]
715
+ };
716
+ //#endregion
717
+ export { workbench_default as default, playground_default as playground };
718
+
719
+ //# sourceMappingURL=workbench.js.map