@streamplace/components 0.7.34 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/components/content-metadata/content-metadata-form.js +404 -0
  2. package/dist/components/content-metadata/content-rights.js +78 -0
  3. package/dist/components/content-metadata/content-warnings.js +68 -0
  4. package/dist/components/content-metadata/index.js +11 -0
  5. package/dist/components/dashboard/header.js +16 -2
  6. package/dist/components/dashboard/problems.js +29 -28
  7. package/dist/components/mobile-player/player.js +4 -0
  8. package/dist/components/mobile-player/ui/report-modal.js +3 -2
  9. package/dist/components/mobile-player/ui/viewer-context-menu.js +44 -1
  10. package/dist/components/ui/button.js +9 -9
  11. package/dist/components/ui/checkbox.js +87 -0
  12. package/dist/components/ui/dialog.js +188 -83
  13. package/dist/components/ui/dropdown.js +15 -10
  14. package/dist/components/ui/icons.js +6 -0
  15. package/dist/components/ui/primitives/button.js +0 -7
  16. package/dist/components/ui/primitives/input.js +13 -1
  17. package/dist/components/ui/primitives/modal.js +2 -2
  18. package/dist/components/ui/select.js +89 -0
  19. package/dist/components/ui/textarea.js +23 -4
  20. package/dist/components/ui/toast.js +464 -114
  21. package/dist/components/ui/tooltip.js +103 -0
  22. package/dist/index.js +2 -0
  23. package/dist/lib/metadata-constants.js +157 -0
  24. package/dist/lib/theme/theme.js +5 -3
  25. package/dist/lib/theme/tokens.js +9 -0
  26. package/dist/streamplace-provider/index.js +14 -4
  27. package/dist/streamplace-store/content-metadata-actions.js +118 -0
  28. package/dist/streamplace-store/graph.js +195 -0
  29. package/dist/streamplace-store/streamplace-store.js +18 -5
  30. package/dist/streamplace-store/user.js +67 -7
  31. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  32. package/package.json +3 -3
  33. package/src/components/content-metadata/content-metadata-form.tsx +761 -0
  34. package/src/components/content-metadata/content-rights.tsx +104 -0
  35. package/src/components/content-metadata/content-warnings.tsx +100 -0
  36. package/src/components/content-metadata/index.tsx +18 -0
  37. package/src/components/dashboard/header.tsx +37 -3
  38. package/src/components/dashboard/index.tsx +1 -1
  39. package/src/components/dashboard/problems.tsx +57 -46
  40. package/src/components/mobile-player/player.tsx +5 -0
  41. package/src/components/mobile-player/ui/report-modal.tsx +13 -7
  42. package/src/components/mobile-player/ui/viewer-context-menu.tsx +100 -1
  43. package/src/components/ui/button.tsx +10 -13
  44. package/src/components/ui/checkbox.tsx +147 -0
  45. package/src/components/ui/dialog.tsx +319 -99
  46. package/src/components/ui/dropdown.tsx +27 -13
  47. package/src/components/ui/icons.tsx +14 -0
  48. package/src/components/ui/primitives/button.tsx +0 -7
  49. package/src/components/ui/primitives/input.tsx +19 -2
  50. package/src/components/ui/primitives/modal.tsx +4 -2
  51. package/src/components/ui/select.tsx +175 -0
  52. package/src/components/ui/textarea.tsx +47 -29
  53. package/src/components/ui/toast.tsx +785 -179
  54. package/src/components/ui/tooltip.tsx +131 -0
  55. package/src/index.tsx +3 -0
  56. package/src/lib/metadata-constants.ts +180 -0
  57. package/src/lib/theme/theme.tsx +10 -6
  58. package/src/lib/theme/tokens.ts +9 -0
  59. package/src/streamplace-provider/index.tsx +20 -2
  60. package/src/streamplace-store/content-metadata-actions.tsx +142 -0
  61. package/src/streamplace-store/graph.tsx +232 -0
  62. package/src/streamplace-store/streamplace-store.tsx +30 -4
  63. package/src/streamplace-store/user.tsx +71 -7
  64. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tooltip = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ const theme_1 = require("../../lib/theme/theme");
8
+ const text_1 = require("../ui/text");
9
+ exports.Tooltip = (0, react_1.forwardRef)(({ content, children, position = "top", style }, ref) => {
10
+ const { theme } = (0, theme_1.useTheme)();
11
+ const [isVisible, setIsVisible] = (0, react_1.useState)(false);
12
+ const styles = createStyles(theme, position);
13
+ const handleHoverIn = () => {
14
+ setIsVisible(true);
15
+ };
16
+ const handleHoverOut = () => {
17
+ setIsVisible(false);
18
+ };
19
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { ref: ref, style: [styles.container, style], onPointerEnter: handleHoverIn, onPointerLeave: handleHoverOut, children: [children, isVisible && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.tooltip, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.tooltipText, children: content }) }))] }));
20
+ });
21
+ exports.Tooltip.displayName = "Tooltip";
22
+ function createStyles(theme, position) {
23
+ const positionStyles = {
24
+ top: {
25
+ tooltip: {
26
+ bottom: "100%",
27
+ left: "50%",
28
+ transform: [{ translateX: -50 }],
29
+ marginBottom: theme.spacing[1],
30
+ },
31
+ arrow: {
32
+ top: "100%",
33
+ left: "50%",
34
+ transform: [{ translateX: -50 }],
35
+ borderTopColor: theme.colors.card,
36
+ },
37
+ },
38
+ bottom: {
39
+ tooltip: {
40
+ top: "100%",
41
+ left: "50%",
42
+ transform: [{ translateX: -50 }],
43
+ marginTop: theme.spacing[1],
44
+ },
45
+ arrow: {
46
+ bottom: "100%",
47
+ left: "50%",
48
+ transform: [{ translateX: -50 }],
49
+ borderBottomColor: theme.colors.card,
50
+ },
51
+ },
52
+ left: {
53
+ tooltip: {
54
+ right: "100%",
55
+ top: "50%",
56
+ transform: [{ translateY: -50 }],
57
+ marginRight: theme.spacing[1],
58
+ },
59
+ arrow: {
60
+ left: "100%",
61
+ top: "50%",
62
+ transform: [{ translateY: -50 }],
63
+ borderLeftColor: theme.colors.card,
64
+ },
65
+ },
66
+ right: {
67
+ tooltip: {
68
+ left: "100%",
69
+ top: "50%",
70
+ transform: [{ translateY: -50 }],
71
+ marginLeft: theme.spacing[1],
72
+ },
73
+ arrow: {
74
+ right: "100%",
75
+ top: "50%",
76
+ transform: [{ translateY: -50 }],
77
+ borderRightColor: theme.colors.card,
78
+ },
79
+ },
80
+ };
81
+ const currentPosition = positionStyles[position];
82
+ return react_native_1.StyleSheet.create({
83
+ container: {
84
+ position: "relative",
85
+ },
86
+ tooltip: {
87
+ position: "absolute",
88
+ backgroundColor: theme.colors.card,
89
+ borderRadius: theme.borderRadius.md,
90
+ padding: theme.spacing[2],
91
+ maxWidth: 200,
92
+ ...theme.shadows.lg,
93
+ ...currentPosition.tooltip,
94
+ zIndex: 1000,
95
+ },
96
+ tooltipText: {
97
+ color: theme.colors.text,
98
+ fontSize: 12,
99
+ lineHeight: 16,
100
+ textAlign: "left",
101
+ },
102
+ });
103
+ }
package/dist/index.js CHANGED
@@ -36,3 +36,5 @@ exports.Dashboard = tslib_1.__importStar(require("./components/dashboard"));
36
36
  // Storage exports
37
37
  var storage_1 = require("./storage");
38
38
  Object.defineProperty(exports, "storage", { enumerable: true, get: function () { return tslib_1.__importDefault(storage_1).default; } });
39
+ // Content metadata components
40
+ tslib_1.__exportStar(require("./components/content-metadata"), exports);
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.C2PA_WARNING_LABELS = exports.LICENSE_URL_LABELS = exports.LICENSE_OPTIONS = exports.CONTENT_WARNINGS = void 0;
4
+ const streamplace_1 = require("streamplace");
5
+ // Content warnings derived from lexicon schema
6
+ exports.CONTENT_WARNINGS = (() => {
7
+ // Find the content warnings schema
8
+ const contentWarningsSchema = streamplace_1.schemas.find((schema) => schema.id === "place.stream.metadata.contentWarnings");
9
+ if (!contentWarningsSchema?.defs) {
10
+ throw new Error("Could not find place.stream.metadata.contentWarnings schema");
11
+ }
12
+ const contentWarningConstants = [
13
+ { constant: "place.stream.metadata.contentWarnings#death", label: "Death" },
14
+ {
15
+ constant: "place.stream.metadata.contentWarnings#drugUse",
16
+ label: "Drug Use",
17
+ },
18
+ {
19
+ constant: "place.stream.metadata.contentWarnings#fantasyViolence",
20
+ label: "Fantasy Violence",
21
+ },
22
+ {
23
+ constant: "place.stream.metadata.contentWarnings#flashingLights",
24
+ label: "Flashing Lights",
25
+ },
26
+ {
27
+ constant: "place.stream.metadata.contentWarnings#language",
28
+ label: "Language",
29
+ },
30
+ {
31
+ constant: "place.stream.metadata.contentWarnings#nudity",
32
+ label: "Nudity",
33
+ },
34
+ {
35
+ constant: "place.stream.metadata.contentWarnings#PII",
36
+ label: "Personally Identifiable Information",
37
+ },
38
+ {
39
+ constant: "place.stream.metadata.contentWarnings#sexuality",
40
+ label: "Sexuality",
41
+ },
42
+ {
43
+ constant: "place.stream.metadata.contentWarnings#suffering",
44
+ label: "Upsetting or Disturbing",
45
+ },
46
+ {
47
+ constant: "place.stream.metadata.contentWarnings#violence",
48
+ label: "Violence",
49
+ },
50
+ ];
51
+ return contentWarningConstants.map(({ constant, label }) => {
52
+ // Extract the key from the constant by splitting on '#'
53
+ const key = constant.split("#")[1];
54
+ const def = contentWarningsSchema.defs[key];
55
+ const description = def?.description || `Description for ${label}`;
56
+ return {
57
+ value: constant,
58
+ label: label,
59
+ description: description,
60
+ };
61
+ });
62
+ })();
63
+ // License options derived from lexicon schema
64
+ exports.LICENSE_OPTIONS = (() => {
65
+ // Find the content rights schema
66
+ const contentRightsSchema = streamplace_1.schemas.find((schema) => schema.id === "place.stream.metadata.contentRights");
67
+ if (!contentRightsSchema?.defs) {
68
+ throw new Error("Could not find place.stream.metadata.contentRights schema");
69
+ }
70
+ const licenseConstants = [
71
+ {
72
+ constant: "place.stream.metadata.contentRights#all-rights-reserved",
73
+ label: "All Rights Reserved",
74
+ },
75
+ {
76
+ constant: "place.stream.metadata.contentRights#cc0_1__0",
77
+ label: "CC0 (Public Domain) 1.0",
78
+ },
79
+ {
80
+ constant: "place.stream.metadata.contentRights#cc-by_4__0",
81
+ label: "CC BY 4.0",
82
+ },
83
+ {
84
+ constant: "place.stream.metadata.contentRights#cc-by-sa_4__0",
85
+ label: "CC BY-SA 4.0",
86
+ },
87
+ {
88
+ constant: "place.stream.metadata.contentRights#cc-by-nc_4__0",
89
+ label: "CC BY-NC 4.0",
90
+ },
91
+ {
92
+ constant: "place.stream.metadata.contentRights#cc-by-nc-sa_4__0",
93
+ label: "CC BY-NC-SA 4.0",
94
+ },
95
+ {
96
+ constant: "place.stream.metadata.contentRights#cc-by-nd_4__0",
97
+ label: "CC BY-ND 4.0",
98
+ },
99
+ {
100
+ constant: "place.stream.metadata.contentRights#cc-by-nc-nd_4__0",
101
+ label: "CC BY-NC-ND 4.0",
102
+ },
103
+ ];
104
+ const options = licenseConstants.map(({ constant, label }) => {
105
+ // Extract the key from the constant by splitting on '#'
106
+ const key = constant.split("#")[1];
107
+ const def = contentRightsSchema.defs[key];
108
+ const description = def?.description || `Description for ${label}`;
109
+ return {
110
+ value: constant,
111
+ label: label,
112
+ description: description,
113
+ };
114
+ });
115
+ // Add custom license option
116
+ options.push({
117
+ value: "custom",
118
+ label: "Custom License",
119
+ description: "Custom license. Define your own terms for how others can use, adapt, or share your content.",
120
+ });
121
+ return options;
122
+ })();
123
+ // License URL labels for C2PA manifests
124
+ exports.LICENSE_URL_LABELS = {
125
+ "http://creativecommons.org/publicdomain/zero/1.0/": "CC0 - Public Domain 1.0",
126
+ "http://creativecommons.org/licenses/by/4.0/": "CC BY - Attribution 4.0",
127
+ "http://creativecommons.org/licenses/by-sa/4.0/": "CC BY-SA - Attribution ShareAlike 4.0",
128
+ "http://creativecommons.org/licenses/by-nc/4.0/": "CC BY-NC - Attribution NonCommercial 4.0",
129
+ "http://creativecommons.org/licenses/by-nc-sa/4.0/": "CC BY-NC-SA - Attribution NonCommercial ShareAlike 4.0",
130
+ "http://creativecommons.org/licenses/by-nd/4.0/": "CC BY-ND - Attribution NoDerivatives 4.0",
131
+ "http://creativecommons.org/licenses/by-nc-nd/4.0/": "CC BY-NC-ND - Attribution NonCommercial NoDerivatives 4.0",
132
+ "All rights reserved": "All Rights Reserved",
133
+ };
134
+ // C2PA warning labels for content warnings
135
+ exports.C2PA_WARNING_LABELS = {
136
+ "cwarn:death": "Death",
137
+ "cwarn:drugUse": "Drug Use",
138
+ "cwarn:fantasyViolence": "Fantasy Violence",
139
+ "cwarn:flashingLights": "Flashing Lights",
140
+ "cwarn:language": "Language",
141
+ "cwarn:nudity": "Nudity",
142
+ "cwarn:PII": "Personally Identifiable Information",
143
+ "cwarn:sexuality": "Sexuality",
144
+ "cwarn:suffering": "Upsetting or Disturbing",
145
+ "cwarn:violence": "Violence",
146
+ // Also support lexicon constants for backward compatibility
147
+ "place.stream.metadata.contentWarnings#death": "Death",
148
+ "place.stream.metadata.contentWarnings#drugUse": "Drug Use",
149
+ "place.stream.metadata.contentWarnings#fantasyViolence": "Fantasy Violence",
150
+ "place.stream.metadata.contentWarnings#flashingLights": "Flashing Lights",
151
+ "place.stream.metadata.contentWarnings#language": "Language",
152
+ "place.stream.metadata.contentWarnings#nudity": "Nudity",
153
+ "place.stream.metadata.contentWarnings#PII": "Personally Identifiable Information",
154
+ "place.stream.metadata.contentWarnings#sexuality": "Sexuality",
155
+ "place.stream.metadata.contentWarnings#suffering": "Upsetting or Disturbing",
156
+ "place.stream.metadata.contentWarnings#violence": "Violence",
157
+ };
@@ -166,12 +166,14 @@ function generateThemeColorsFromPalette(palette, isDark) {
166
166
  mutedForeground: isDark ? palette[400] : palette[500],
167
167
  accent: isDark ? palette[800] : palette[100],
168
168
  accentForeground: isDark ? palette[50] : palette[900],
169
- destructive: react_native_1.Platform.OS === "ios" ? tokens_1.colors.ios.systemRed : tokens_1.colors.destructive[500],
169
+ destructive: tokens_1.colors.destructive[700],
170
170
  destructiveForeground: tokens_1.colors.white,
171
- success: react_native_1.Platform.OS === "ios" ? tokens_1.colors.ios.systemGreen : tokens_1.colors.success[500],
171
+ success: tokens_1.colors.success[700],
172
172
  successForeground: tokens_1.colors.white,
173
- warning: react_native_1.Platform.OS === "ios" ? tokens_1.colors.ios.systemOrange : tokens_1.colors.warning[500],
173
+ warning: tokens_1.colors.warning[700],
174
174
  warningForeground: tokens_1.colors.white,
175
+ info: tokens_1.colors.blue[700],
176
+ infoForeground: isDark ? palette[50] : palette[900],
175
177
  border: isDark ? palette[500] + "30" : palette[200] + "30",
176
178
  input: isDark ? palette[800] : palette[200],
177
179
  ring: react_native_1.Platform.OS === "ios" ? tokens_1.colors.ios.systemBlue : tokens_1.colors.primary[500],
@@ -580,52 +580,61 @@ exports.typography = {
580
580
  },
581
581
  },
582
582
  // Universal typography scale
583
+ // Atkinson's center is weird so the marginBottom is there to correct it?
583
584
  universal: {
584
585
  xs: {
585
586
  fontSize: 12,
586
587
  lineHeight: 16,
588
+ marginBottom: -0.7,
587
589
  fontWeight: "400",
588
590
  fontFamily: "AtkinsonHyperlegibleNext-Regular",
589
591
  },
590
592
  sm: {
591
593
  fontSize: 14,
592
594
  lineHeight: 20,
595
+ marginBottom: -1,
593
596
  fontWeight: "400",
594
597
  fontFamily: "AtkinsonHyperlegibleNext-Regular",
595
598
  },
596
599
  base: {
597
600
  fontSize: 16,
598
601
  lineHeight: 24,
602
+ marginBottom: -1.2,
599
603
  fontWeight: "400",
600
604
  fontFamily: "AtkinsonHyperlegibleNext-Regular",
601
605
  },
602
606
  lg: {
603
607
  fontSize: 18,
604
608
  lineHeight: 28,
609
+ marginBottom: -1.5,
605
610
  fontWeight: "400",
606
611
  fontFamily: "AtkinsonHyperlegibleNext-Regular",
607
612
  },
608
613
  xl: {
609
614
  fontSize: 20,
610
615
  lineHeight: 28,
616
+ marginBottom: -1.75,
611
617
  fontWeight: "500",
612
618
  fontFamily: "AtkinsonHyperlegibleNext-Medium",
613
619
  },
614
620
  "2xl": {
615
621
  fontSize: 24,
616
622
  lineHeight: 32,
623
+ marginBottom: -2,
617
624
  fontWeight: "600",
618
625
  fontFamily: "AtkinsonHyperlegibleNext-SemiBold",
619
626
  },
620
627
  "3xl": {
621
628
  fontSize: 30,
622
629
  lineHeight: 36,
630
+ marginBottom: -2.5,
623
631
  fontWeight: "700",
624
632
  fontFamily: "AtkinsonHyperlegibleNext-Bold",
625
633
  },
626
634
  "4xl": {
627
635
  fontSize: 36,
628
636
  lineHeight: 40,
637
+ marginBottom: -3,
629
638
  fontWeight: "700",
630
639
  fontFamily: "AtkinsonHyperlegibleNext-ExtraBold",
631
640
  },
@@ -1,21 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StreamplaceProvider = StreamplaceProvider;
4
+ exports.ChatProfileCreator = ChatProfileCreator;
4
5
  const tslib_1 = require("tslib");
5
6
  const jsx_runtime_1 = require("react/jsx-runtime");
6
7
  const react_1 = require("react");
7
- const streamplace_store_1 = require("../streamplace-store/streamplace-store");
8
+ const streamplace_store_1 = require("../streamplace-store");
9
+ const streamplace_store_2 = require("../streamplace-store/streamplace-store");
8
10
  const context_1 = require("./context");
9
11
  const poller_1 = tslib_1.__importDefault(require("./poller"));
10
12
  function StreamplaceProvider({ children, url, oauthSession, }) {
11
- console.log("session in provider is", oauthSession);
12
13
  // todo: handle url changes?
13
- const store = (0, react_1.useRef)((0, streamplace_store_1.makeStreamplaceStore)({ url })).current;
14
+ const store = (0, react_1.useRef)((0, streamplace_store_2.makeStreamplaceStore)({ url })).current;
14
15
  (0, react_1.useEffect)(() => {
15
16
  store.setState({ url });
16
17
  }, [url]);
17
18
  (0, react_1.useEffect)(() => {
18
19
  store.setState({ oauthSession });
19
20
  }, [oauthSession]);
20
- return ((0, jsx_runtime_1.jsx)(context_1.StreamplaceContext.Provider, { value: { store: store }, children: (0, jsx_runtime_1.jsx)(poller_1.default, { children: children }) }));
21
+ return ((0, jsx_runtime_1.jsx)(context_1.StreamplaceContext.Provider, { value: { store: store }, children: (0, jsx_runtime_1.jsx)(ChatProfileCreator, { oauthSession: oauthSession, children: (0, jsx_runtime_1.jsx)(poller_1.default, { children: children }) }) }));
22
+ }
23
+ function ChatProfileCreator({ oauthSession, children, }) {
24
+ const getChatProfile = (0, streamplace_store_1.useGetChatProfile)();
25
+ (0, react_1.useEffect)(() => {
26
+ if (oauthSession) {
27
+ getChatProfile();
28
+ }
29
+ }, [oauthSession]);
30
+ return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
21
31
  }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useGetContentMetadata = exports.useSaveContentMetadata = void 0;
4
+ const streamplace_store_1 = require("./streamplace-store");
5
+ const xrpc_1 = require("./xrpc");
6
+ const useSaveContentMetadata = () => {
7
+ const pdsAgent = (0, xrpc_1.usePDSAgent)();
8
+ const did = (0, streamplace_store_1.useDID)();
9
+ const setContentMetadata = (0, streamplace_store_1.useSetContentMetadata)();
10
+ return async (params) => {
11
+ if (!pdsAgent || !did) {
12
+ throw new Error("No PDS agent or DID available");
13
+ }
14
+ const metadataRecord = {
15
+ $type: "place.stream.metadata.configuration",
16
+ createdAt: new Date().toISOString(),
17
+ ...(params.contentWarnings &&
18
+ params.contentWarnings.length > 0 && {
19
+ contentWarnings: { warnings: params.contentWarnings },
20
+ }),
21
+ ...(params.distributionPolicy &&
22
+ params.distributionPolicy.deleteAfter && {
23
+ distributionPolicy: params.distributionPolicy,
24
+ }),
25
+ ...(params.contentRights &&
26
+ Object.keys(params.contentRights).length > 0 && {
27
+ contentRights: params.contentRights,
28
+ }),
29
+ };
30
+ const rkey = params.rkey || "self";
31
+ try {
32
+ // Try to update existing record first
33
+ const result = await pdsAgent.com.atproto.repo.putRecord({
34
+ repo: did,
35
+ collection: "place.stream.metadata.configuration",
36
+ rkey,
37
+ record: metadataRecord,
38
+ });
39
+ const contentMetadata = {
40
+ record: metadataRecord,
41
+ uri: result.data.uri,
42
+ cid: result.data.cid || "",
43
+ rkey,
44
+ };
45
+ setContentMetadata(contentMetadata);
46
+ return contentMetadata;
47
+ }
48
+ catch (error) {
49
+ // If record doesn't exist, create it
50
+ if (error instanceof Error &&
51
+ (error.message?.includes("not found") ||
52
+ error.message?.includes("RecordNotFound") ||
53
+ error.message?.includes("mst: not found") ||
54
+ error?.status === 404)) {
55
+ const createResult = await pdsAgent.com.atproto.repo.createRecord({
56
+ repo: did,
57
+ collection: "place.stream.metadata.configuration",
58
+ rkey,
59
+ record: metadataRecord,
60
+ });
61
+ const contentMetadata = {
62
+ record: metadataRecord,
63
+ uri: createResult.data.uri,
64
+ cid: createResult.data.cid || "",
65
+ rkey,
66
+ };
67
+ setContentMetadata(contentMetadata);
68
+ return contentMetadata;
69
+ }
70
+ throw error;
71
+ }
72
+ };
73
+ };
74
+ exports.useSaveContentMetadata = useSaveContentMetadata;
75
+ // Simple get function
76
+ const useGetContentMetadata = () => {
77
+ const pdsAgent = (0, xrpc_1.usePDSAgent)();
78
+ const did = (0, streamplace_store_1.useDID)();
79
+ const setContentMetadata = (0, streamplace_store_1.useSetContentMetadata)();
80
+ return async (params) => {
81
+ if (!pdsAgent) {
82
+ throw new Error("No PDS agent available");
83
+ }
84
+ const targetDid = params?.userDid || did;
85
+ if (!targetDid) {
86
+ throw new Error("No DID provided or user not authenticated");
87
+ }
88
+ try {
89
+ const result = await pdsAgent.com.atproto.repo.getRecord({
90
+ repo: targetDid,
91
+ collection: "place.stream.metadata.configuration",
92
+ rkey: params?.rkey || "self",
93
+ });
94
+ if (!result.success) {
95
+ throw new Error("Failed to get content metadata record");
96
+ }
97
+ const contentMetadata = {
98
+ record: result.data.value,
99
+ uri: result.data.uri,
100
+ cid: result.data.cid || "",
101
+ };
102
+ setContentMetadata(contentMetadata);
103
+ return contentMetadata;
104
+ }
105
+ catch (error) {
106
+ // Handle record not found - this is normal for new users
107
+ if (error instanceof Error &&
108
+ (error.message?.includes("not found") ||
109
+ error.message?.includes("RecordNotFound") ||
110
+ error.message?.includes("mst: not found") ||
111
+ error?.status === 404)) {
112
+ return null;
113
+ }
114
+ throw error;
115
+ }
116
+ };
117
+ };
118
+ exports.useGetContentMetadata = useGetContentMetadata;