@opengeni/react-native 5.5.2-canary.40973241992001 → 5.5.2-canary.41014426654001
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.
- package/dist/{chunk-FOLTBO7D.js → chunk-6D7LKJOZ.js} +3 -82
- package/dist/chunk-6D7LKJOZ.js.map +1 -0
- package/dist/{chunk-KDQ56G4C.js → chunk-AS7A2J6K.js} +570 -194
- package/dist/chunk-AS7A2J6K.js.map +1 -0
- package/dist/index.js +77 -2
- package/dist/index.js.map +1 -1
- package/dist/meetings/index.js +2 -2
- package/dist/timeline/composer-state.d.ts +2 -4
- package/dist/timeline/decisions.d.ts +7 -1
- package/dist/timeline/index.js +2 -2
- package/dist/timeline/mcp-question.d.ts +25 -0
- package/dist/timeline/reading-position.d.ts +10 -0
- package/dist/timeline/session-screen.d.ts +3 -0
- package/dist/timeline/turn.d.ts +1 -1
- package/dist/use-native-session.d.ts +1 -0
- package/package.json +5 -5
- package/src/timeline/composer-state.ts +3 -6
- package/src/timeline/decisions.tsx +127 -21
- package/src/timeline/inbox.tsx +54 -4
- package/src/timeline/mcp-question.tsx +287 -0
- package/src/timeline/message-timeline.tsx +106 -49
- package/src/timeline/reading-position.ts +13 -0
- package/src/timeline/session-screen.tsx +20 -5
- package/src/timeline/turn.tsx +22 -18
- package/src/use-native-session.ts +2 -0
- package/dist/chunk-FOLTBO7D.js.map +0 -1
- package/dist/chunk-KDQ56G4C.js.map +0 -1
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { useNativeTimelineTheme } from './chunk-4IFOWV3O.js';
|
|
2
|
-
import { resolvePreset, MODE_FRAMES } from 'thinking-orbs/engine';
|
|
3
|
-
import { useMemo, useState, useEffect } from 'react';
|
|
4
|
-
import { AppState, AccessibilityInfo } from 'react-native';
|
|
5
|
-
import Svg, { Line, Circle } from 'react-native-svg';
|
|
6
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
1
|
// src/timeline/secret-field-model.ts
|
|
9
2
|
function secretCanGenerate(spec) {
|
|
10
3
|
return Boolean(spec?.allowGenerate) && spec?.itemType !== "card" && spec?.itemType !== "identity" && spec?.itemType !== "ssh_key";
|
|
@@ -192,79 +185,7 @@ function humanInputAnswerLines(answers, response, saved, multiple) {
|
|
|
192
185
|
};
|
|
193
186
|
});
|
|
194
187
|
}
|
|
195
|
-
var FRAME_MS = 33;
|
|
196
|
-
function ink(white, alpha, dark) {
|
|
197
|
-
const level = Math.round((dark ? 1 - Math.min(1, Math.max(0, white)) : white) * 255);
|
|
198
|
-
return `rgba(${level},${level},${level},${alpha ?? 1})`;
|
|
199
|
-
}
|
|
200
|
-
function ThinkingOrb({
|
|
201
|
-
state = "searching",
|
|
202
|
-
size = 64,
|
|
203
|
-
speed = 0.8,
|
|
204
|
-
displaySize
|
|
205
|
-
}) {
|
|
206
|
-
const theme = useNativeTimelineTheme();
|
|
207
|
-
const dark = theme.scheme === "dark";
|
|
208
|
-
const preset = useMemo(() => resolvePreset(state, size), [state, size]);
|
|
209
|
-
const [time, setTime] = useState(0.6);
|
|
210
|
-
const [reduceMotion, setReduceMotion] = useState(false);
|
|
211
|
-
const [active, setActive] = useState(AppState.currentState === "active");
|
|
212
|
-
useEffect(() => {
|
|
213
|
-
void AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
|
|
214
|
-
const motion = AccessibilityInfo.addEventListener("reduceMotionChanged", setReduceMotion);
|
|
215
|
-
const app = AppState.addEventListener("change", (next) => setActive(next === "active"));
|
|
216
|
-
return () => {
|
|
217
|
-
motion.remove();
|
|
218
|
-
app.remove();
|
|
219
|
-
};
|
|
220
|
-
}, []);
|
|
221
|
-
useEffect(() => {
|
|
222
|
-
if (reduceMotion || !active) return;
|
|
223
|
-
const started = Date.now();
|
|
224
|
-
const timer = setInterval(() => setTime((Date.now() - started) / 1e3), FRAME_MS);
|
|
225
|
-
return () => clearInterval(timer);
|
|
226
|
-
}, [active, reduceMotion]);
|
|
227
|
-
const frame = MODE_FRAMES[preset.mode](
|
|
228
|
-
size,
|
|
229
|
-
reduceMotion ? 0.6 : time * preset.speed * speed,
|
|
230
|
-
preset.opts
|
|
231
|
-
);
|
|
232
|
-
return /* @__PURE__ */ jsxs(
|
|
233
|
-
Svg,
|
|
234
|
-
{
|
|
235
|
-
width: displaySize ?? size,
|
|
236
|
-
height: displaySize ?? size,
|
|
237
|
-
viewBox: `0 0 ${size} ${size}`,
|
|
238
|
-
accessibilityElementsHidden: true,
|
|
239
|
-
importantForAccessibility: "no",
|
|
240
|
-
children: [
|
|
241
|
-
frame.lines.map((line, index) => /* @__PURE__ */ jsx(
|
|
242
|
-
Line,
|
|
243
|
-
{
|
|
244
|
-
x1: line.x1,
|
|
245
|
-
y1: line.y1,
|
|
246
|
-
x2: line.x2,
|
|
247
|
-
y2: line.y2,
|
|
248
|
-
stroke: ink(line.white, line.a, dark),
|
|
249
|
-
strokeWidth: line.w
|
|
250
|
-
},
|
|
251
|
-
`l${index}`
|
|
252
|
-
)),
|
|
253
|
-
frame.dots.map((dot, index) => /* @__PURE__ */ jsx(
|
|
254
|
-
Circle,
|
|
255
|
-
{
|
|
256
|
-
cx: dot.x,
|
|
257
|
-
cy: dot.y,
|
|
258
|
-
r: dot.r,
|
|
259
|
-
fill: ink(dot.white, dot.a, dark)
|
|
260
|
-
},
|
|
261
|
-
`d${index}`
|
|
262
|
-
))
|
|
263
|
-
]
|
|
264
|
-
}
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
188
|
|
|
268
|
-
export { SECRET_SAVE_TO_OPTIONS,
|
|
269
|
-
//# sourceMappingURL=chunk-
|
|
270
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
export { SECRET_SAVE_TO_OPTIONS, defaultSecretFieldMessages, humanInputAnswerLines, initialSecretDraft, isSecretQuestion, secretCanGenerate, secretInputTraits, secretPatternMismatch, secretSubmission, secretUsernameTraits };
|
|
190
|
+
//# sourceMappingURL=chunk-6D7LKJOZ.js.map
|
|
191
|
+
//# sourceMappingURL=chunk-6D7LKJOZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/timeline/secret-field-model.ts"],"names":[],"mappings":"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","file":"chunk-6D7LKJOZ.js","sourcesContent":["import type {\n GeneratePasswordSpec,\n HumanInputAnswer,\n HumanInputQuestion,\n HumanInputResponse,\n HumanInputSecretAnswer,\n HumanInputSecretAnswerResult,\n HumanInputSecretSaveTo,\n HumanInputSecretSpec,\n} from \"@opengeni/sdk\";\nimport { type OpenGeniText } from \"@opengeni/react/messages\";\n\n/* ----------------------------------------------------------------------------\n Pure rules for the native secret question: which keyboard and autofill\n traits the field gets, what a submission sends, and how a saved answer\n reads. No React Native imports, so the rules are unit-tested under bun.\n -------------------------------------------------------------------------- */\n\n/**\n * - `current-password` / `new-password`: the OS password manager fills or\n * suggests a password.\n * - `one-time-code`: a code the person just received (number pad, SMS autofill).\n * - `setup-key`: a TOTP seed (`fieldKind: \"totp\"` stores the seed, not a code).\n * - `off`: an API key, token or note; no autofill.\n */\nexport type SecretInputMode =\n | \"current-password\"\n | \"new-password\"\n | \"one-time-code\"\n | \"setup-key\"\n | \"off\";\n\n/**\n * Generate is offered when the agent allows it, never for a card, an identity\n * or an SSH private key (whose key pairs come from secret_save).\n */\nexport function secretCanGenerate(spec: HumanInputSecretSpec | null | undefined): boolean {\n return (\n Boolean(spec?.allowGenerate) &&\n spec?.itemType !== \"card\" &&\n spec?.itemType !== \"identity\" &&\n spec?.itemType !== \"ssh_key\"\n );\n}\n\nexport function secretInputMode(spec: HumanInputSecretSpec | null | undefined): SecretInputMode {\n const autocomplete = spec?.autocomplete;\n if (autocomplete === \"one-time-code\") return \"one-time-code\";\n if (autocomplete === \"new-password\") return \"new-password\";\n if (autocomplete === \"current-password\") return \"current-password\";\n if (autocomplete === \"off\") return spec?.fieldKind === \"totp\" ? \"setup-key\" : \"off\";\n if (spec?.fieldKind === \"totp\") return \"setup-key\";\n // Card numbers, ID numbers and private keys are no website password.\n if (spec?.itemType === \"card\" || spec?.itemType === \"identity\" || spec?.itemType === \"ssh_key\")\n return \"off\";\n if (spec?.allowGenerate) return \"new-password\";\n if (spec?.itemType === \"api_key\" || spec?.itemType === \"note\") return \"off\";\n return \"current-password\";\n}\n\n/** The `TextInput` props that make the field secure and autofill-aware. */\nexport type SecretInputTraits = {\n mode: SecretInputMode;\n secureTextEntry: true;\n autoCorrect: false;\n autoCapitalize: \"none\";\n spellCheck: false;\n /** iOS. */\n textContentType: \"password\" | \"newPassword\" | \"oneTimeCode\" | \"none\";\n /** Android autofill hint (RN maps it to the platform constant). */\n autoComplete: \"password\" | \"password-new\" | \"sms-otp\" | \"off\";\n /** Android. */\n importantForAutofill: \"yes\" | \"no\";\n keyboardType: \"default\" | \"number-pad\";\n /** iOS strong-password rules, from the question's generator spec. */\n passwordRules?: string | undefined;\n};\n\nexport function secretInputTraits(\n spec: HumanInputSecretSpec | null | undefined,\n): SecretInputTraits {\n const mode = secretInputMode(spec);\n const base = {\n mode,\n secureTextEntry: true,\n autoCorrect: false,\n autoCapitalize: \"none\",\n spellCheck: false,\n } as const;\n switch (mode) {\n case \"current-password\":\n return {\n ...base,\n textContentType: \"password\",\n autoComplete: \"password\",\n importantForAutofill: \"yes\",\n keyboardType: \"default\",\n };\n case \"new-password\": {\n const passwordRules = spec?.generate ? applePasswordRules(spec.generate) : undefined;\n return {\n ...base,\n textContentType: \"newPassword\",\n autoComplete: \"password-new\",\n importantForAutofill: \"yes\",\n keyboardType: \"default\",\n ...(passwordRules ? { passwordRules } : {}),\n };\n }\n case \"one-time-code\":\n return {\n ...base,\n textContentType: \"oneTimeCode\",\n autoComplete: \"sms-otp\",\n importantForAutofill: \"yes\",\n keyboardType: \"number-pad\",\n };\n case \"setup-key\":\n case \"off\":\n return {\n ...base,\n textContentType: \"none\",\n autoComplete: \"off\",\n importantForAutofill: \"no\",\n keyboardType: \"default\",\n };\n }\n}\n\n/** The username field paired with the password, so the OS saves them together. */\nexport const secretUsernameTraits = {\n textContentType: \"username\",\n autoComplete: \"username\",\n importantForAutofill: \"yes\",\n autoCorrect: false,\n autoCapitalize: \"none\",\n spellCheck: false,\n} as const;\n\n/**\n * Apple password-rules markup for the iOS strong-password suggestion, from the\n * same spec the server generates with (defaults as in `@opengeni/contracts`).\n */\nexport function applePasswordRules(spec: GeneratePasswordSpec): string {\n const rules: string[] = [];\n const lower = spec.lowercase ?? true;\n const upper = spec.uppercase ?? true;\n const digits = spec.digits ?? true;\n const symbols = spec.symbols ?? true;\n const requireEach = spec.requireEachClass ?? true;\n // In the rules grammar a hyphen is literal only first in a class, and \"]\"\n // or a quote cannot appear at all.\n const rawSymbols = spec.symbolSet ?? \"!#%+-.:=?@_\";\n const symbolSet = (rawSymbols.includes(\"-\") ? \"-\" : \"\") + rawSymbols.replace(/[-\\]\"]/gu, \"\");\n const classes = [\n lower ? \"lower\" : null,\n upper ? \"upper\" : null,\n digits ? \"digit\" : null,\n symbols && symbolSet ? `[${symbolSet}]` : null,\n ].filter((entry): entry is string => entry !== null);\n if (requireEach) for (const entry of classes) rules.push(`required: ${entry};`);\n else rules.push(`allowed: ${classes.join(\", \")};`);\n rules.push(`minlength: ${spec.length ?? 24};`);\n return rules.join(\" \");\n}\n\n/** What the person picked for one secret question. The value itself lives in a ref. */\nexport type SecretDraft = {\n generate: boolean;\n username: string;\n saveTo: HumanInputSecretSaveTo;\n};\n\nexport const SECRET_SAVE_TO_OPTIONS: readonly HumanInputSecretSaveTo[] = [\n \"user\",\n \"task\",\n \"workspace\",\n];\n\nexport function initialSecretDraft(spec: HumanInputSecretSpec | null | undefined): SecretDraft {\n return {\n generate: false,\n username: spec?.username?.value ?? \"\",\n saveTo: spec?.saveTo ?? \"user\",\n };\n}\n\nexport function isSecretQuestion(question: Pick<HumanInputQuestion, \"kind\">): boolean {\n return question.kind === \"secret\";\n}\n\n/**\n * The secret half of a submission. Each answered secret question sends an\n * empty `answers` entry and its value (or a generate spec) only in\n * `secretAnswers`, which the API strips before anything is stored.\n */\nexport function secretSubmission(\n questions: readonly HumanInputQuestion[],\n drafts: Readonly<Record<string, SecretDraft | undefined>>,\n values: Readonly<Record<string, string | undefined>>,\n requiredMessage: string,\n): {\n answers: HumanInputAnswer[];\n secretAnswers: HumanInputSecretAnswer[];\n errors: Record<string, string>;\n} {\n const answers: HumanInputAnswer[] = [];\n const secretAnswers: HumanInputSecretAnswer[] = [];\n const errors: Record<string, string> = {};\n for (const question of questions) {\n if (!isSecretQuestion(question)) continue;\n const spec = question.secret;\n const draft = drafts[question.id] ?? initialSecretDraft(spec);\n const value = values[question.id] ?? \"\";\n const supplied = draft.generate || value.length > 0;\n if (!supplied) {\n if (question.required) errors[question.id] = requiredMessage;\n continue;\n }\n const username = draft.username.trim();\n answers.push({ questionId: question.id, values: [] });\n secretAnswers.push({\n questionId: question.id,\n ...(draft.generate ? { generate: spec?.generate ?? {} } : { value }),\n ...(spec?.username && username ? { username } : {}),\n saveTo: draft.saveTo,\n });\n }\n return { answers, secretAnswers, errors };\n}\n\n/**\n * A soft check against the question's `pattern` (anchored, like the HTML\n * attribute). Never blocks; an invalid pattern never warns.\n */\nexport function secretPatternMismatch(pattern: string | null | undefined, value: string): boolean {\n if (!pattern || value.length === 0) return false;\n let expression: RegExp;\n try {\n expression = new RegExp(`^(?:${pattern})$`, \"u\");\n } catch {\n return false;\n }\n return !expression.test(value);\n}\n\nexport type SecretFieldMessages = {\n saveTo: string;\n saveToOption: Record<HumanInputSecretSaveTo, string>;\n vaultHint: (vault: string) => string;\n show: string;\n hide: string;\n generate: string;\n generated: string;\n undo: string;\n looksLike: (example: string) => string;\n patternWarning: string;\n placeholder: Record<SecretInputMode, string>;\n saved: (vaultName: string, itemName: string) => string;\n};\n\nexport const defaultSecretFieldMessages = (t: OpenGeniText): SecretFieldMessages => ({\n saveTo: t(\"native.timeline.secretFieldModel.saveTo\"),\n saveToOption: {\n user: t(\"native.timeline.secretFieldModel.onlyMe\"),\n task: t(\"native.timeline.secretFieldModel.thisTask\"),\n workspace: t(\"native.timeline.secretFieldModel.workspace\"),\n },\n vaultHint: (vault) => t(\"native.timeline.secretFieldModel.savesToTheVaultVault\", { vault }),\n show: t(\"native.timeline.secretFieldModel.showSecret\"),\n hide: t(\"native.timeline.secretFieldModel.hideSecret\"),\n generate: t(\"native.timeline.secretFieldModel.generate\"),\n generated: t(\"native.timeline.secretFieldModel.aStrongPasswordWillBe\"),\n undo: t(\"native.timeline.secretFieldModel.undo\"),\n looksLike: (example) => t(\"native.timeline.secretFieldModel.looksLikeExample\", { example }),\n patternWarning: t(\"native.timeline.secretFieldModel.thisDoesnTMatchThe\"),\n placeholder: {\n \"current-password\": t(\"native.timeline.secretFieldModel.password\"),\n \"new-password\": t(\"native.timeline.secretFieldModel.newPassword\"),\n \"one-time-code\": t(\"native.timeline.secretFieldModel.code\"),\n \"setup-key\": t(\"native.timeline.secretFieldModel.setupKeyOrOtpauthLink\"),\n off: t(\"native.timeline.secretFieldModel.value\"),\n },\n saved: (vaultName, itemName) =>\n t(\"native.timeline.secretFieldModel.savedToVaultnameItemname\", { vaultName, itemName }),\n});\n\n/** The answered chip: where the value went, never the value. */\nexport function secretSavedLabel(\n t: OpenGeniText,\n result: Pick<HumanInputSecretAnswerResult, \"vaultName\" | \"itemName\">,\n messages: Pick<SecretFieldMessages, \"saved\"> = defaultSecretFieldMessages(t),\n): string {\n return messages.saved(result.vaultName, result.itemName);\n}\n\n/**\n * The lines of a settled answer bubble. A secret answer reads as where it was\n * saved (\"Saved to Private › GitHub\"); its value never reaches the timeline.\n */\nexport function humanInputAnswerLines(\n answers: readonly { questionId: string; label: string; values: readonly string[] }[],\n response: HumanInputResponse,\n saved: (vaultName: string, itemName: string) => string,\n multiple: boolean,\n): { questionId: string; text: string; secret: boolean }[] {\n const secrets = new Map(\n response.outcome === \"answered\"\n ? response.answers.flatMap((answer) =>\n answer.secret ? [[answer.questionId, answer.secret] as const] : [],\n )\n : [],\n );\n return answers.map((answer) => {\n const prefix = multiple ? `${answer.label}: ` : \"\";\n const secret = secrets.get(answer.questionId);\n return secret\n ? {\n questionId: answer.questionId,\n text: `${prefix}${saved(secret.vaultName, secret.itemName)}`,\n secret: true,\n }\n : {\n questionId: answer.questionId,\n text: `${prefix}${answer.values.join(\", \")}`,\n secret: false,\n };\n });\n}\n"]}
|