@marktiderman/genesis-native 0.1.0 → 0.3.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.
- package/README.md +354 -10
- package/dist/block-C5-noMhB.d.ts +223 -0
- package/dist/blocks-a1YQ1Elf.d.ts +1540 -0
- package/dist/chunk-65P7RU4V.js +49 -0
- package/dist/chunk-65P7RU4V.js.map +1 -0
- package/dist/chunk-6BT4PTGH.js +37 -0
- package/dist/chunk-6BT4PTGH.js.map +1 -0
- package/dist/chunk-75YP72G6.js +374 -0
- package/dist/chunk-75YP72G6.js.map +1 -0
- package/dist/chunk-NGYNYJPL.js +90 -0
- package/dist/chunk-NGYNYJPL.js.map +1 -0
- package/dist/chunk-VKTIHNAV.js +95 -0
- package/dist/chunk-VKTIHNAV.js.map +1 -0
- package/dist/{chunk-MMTPWUWI.js → chunk-VTJDIKFC.js} +9 -6
- package/dist/chunk-VTJDIKFC.js.map +1 -0
- package/dist/chunk-XE7LC7K6.js +29 -0
- package/dist/chunk-XE7LC7K6.js.map +1 -0
- package/dist/dev-warnings.d.ts +34 -0
- package/dist/dev-warnings.js +15 -0
- package/dist/dev-warnings.js.map +1 -0
- package/dist/devtools.d.ts +144 -0
- package/dist/devtools.js +390 -0
- package/dist/devtools.js.map +1 -0
- package/dist/index.d.ts +12 -368
- package/dist/index.js +88 -191
- package/dist/index.js.map +1 -1
- package/dist/observability.d.ts +170 -0
- package/dist/observability.js +123 -0
- package/dist/observability.js.map +1 -0
- package/dist/persist.d.ts +1 -1
- package/dist/persist.js +1 -1
- package/dist/push.d.ts +169 -0
- package/dist/push.js +996 -0
- package/dist/push.js.map +1 -0
- package/dist/{query-DhH3lLFa.d.ts → query-DUmVAfsF.d.ts} +11 -6
- package/dist/updates.d.ts +8 -1
- package/dist/updates.js +44 -69
- package/dist/updates.js.map +1 -1
- package/package.json +222 -5
- package/src/app.tsx +491 -0
- package/src/auth.tsx +176 -0
- package/src/blocks.tsx +144 -0
- package/src/boot.tsx +188 -0
- package/src/dev-warnings.ts +43 -0
- package/src/devtools/block.tsx +488 -0
- package/src/devtools/gestures.ts +107 -0
- package/src/devtools/index.ts +22 -0
- package/src/devtools/info.ts +45 -0
- package/src/devtools/slots.ts +21 -0
- package/src/errors.tsx +195 -0
- package/src/held-link.ts +90 -0
- package/src/hydration-gate.ts +88 -0
- package/src/index.ts +83 -0
- package/src/links.ts +140 -0
- package/src/nativewind.d.ts +41 -0
- package/src/observability/block.tsx +300 -0
- package/src/observability/events.ts +89 -0
- package/src/observability/index.ts +44 -0
- package/src/observability/scrub.ts +166 -0
- package/src/observability/sentry.ts +222 -0
- package/src/observability/sink.ts +147 -0
- package/src/persist.ts +83 -0
- package/src/push/backend.ts +129 -0
- package/src/push/block.tsx +545 -0
- package/src/push/index.ts +102 -0
- package/src/push/modules.ts +111 -0
- package/src/push/permission.ts +191 -0
- package/src/push/preferences.ts +136 -0
- package/src/push/quiet-hours.ts +71 -0
- package/src/push/registration.ts +189 -0
- package/src/push/routing.ts +27 -0
- package/src/push/screens.tsx +46 -0
- package/src/push/settings.tsx +378 -0
- package/src/query.ts +100 -0
- package/src/updates/block.tsx +442 -0
- package/src/updates/channels.ts +131 -0
- package/src/updates/checker.ts +190 -0
- package/src/updates/index.ts +87 -0
- package/src/updates/modules.ts +64 -0
- package/src/updates/policy.ts +314 -0
- package/src/updates/screens.tsx +159 -0
- package/src/updates/signature.ts +80 -0
- package/src/updates/store.ts +33 -0
- package/src/updates/version.ts +39 -0
- package/src/updates/whats-new.ts +122 -0
- package/dist/block-Dh5ny06W.d.ts +0 -535
- package/dist/chunk-MMTPWUWI.js.map +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { scrubRecord, scrubEvent, scrubString } from './chunk-75YP72G6.js';
|
|
2
|
+
export { FILTERED, OBSERVABILITY_BLOCK_ID, ObservabilityProvider, checkEvent, consoleSink, createObservability, defineEvents, isSecretKey, observeSink, scrubBreadcrumb, scrubEvent, scrubRecord, scrubString, scrubUrl, scrubValue, scrubbedError, useObservability, useRecentActivity } from './chunk-75YP72G6.js';
|
|
3
|
+
import './chunk-NGYNYJPL.js';
|
|
4
|
+
|
|
5
|
+
// src/observability/sentry.ts
|
|
6
|
+
var isDev = () => typeof __DEV__ !== "undefined" && __DEV__;
|
|
7
|
+
function sentryRelease(signature, applicationId) {
|
|
8
|
+
const version = signature?.version;
|
|
9
|
+
const build = signature?.build;
|
|
10
|
+
if (!version || !build || !applicationId) return {};
|
|
11
|
+
return { release: `${applicationId}@${version}+${build}`, dist: build };
|
|
12
|
+
}
|
|
13
|
+
function signatureTags(signature) {
|
|
14
|
+
if (!signature) return {};
|
|
15
|
+
return {
|
|
16
|
+
"update.launch": signature.launch,
|
|
17
|
+
"update.id": signature.launch === "update" ? signature.updateId ?? "unknown" : signature.launch,
|
|
18
|
+
"update.channel": signature.requestedChannel ?? signature.channel ?? (signature.launch === "off" ? "none" : "unknown"),
|
|
19
|
+
"update.runtime": signature.runtimeVersion ?? "unknown",
|
|
20
|
+
...signature.emergency ? { "update.emergency": "true" } : {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function sentryEnvironment(channel) {
|
|
24
|
+
if (!channel || channel === "production") return "production";
|
|
25
|
+
if (channel === "development") return "development";
|
|
26
|
+
if (channel === "preview" || /^pr-\d+$/.test(channel)) return "preview";
|
|
27
|
+
return "production";
|
|
28
|
+
}
|
|
29
|
+
function withoutTouchLabels(crumb) {
|
|
30
|
+
if (crumb.category !== "touch" || !crumb.data || typeof crumb.data !== "object") return crumb;
|
|
31
|
+
const data = crumb.data;
|
|
32
|
+
const path = Array.isArray(data.path) ? data.path.map((p) => p && typeof p === "object" ? { name: p.name } : p) : void 0;
|
|
33
|
+
const first = path?.[0];
|
|
34
|
+
return { ...crumb, message: `Touch event within element: ${typeof first?.name === "string" ? first.name : "unknown"}`, data: { ...data, ...path ? { path } : {} } };
|
|
35
|
+
}
|
|
36
|
+
function chain(ours, theirs) {
|
|
37
|
+
return (value, hint) => {
|
|
38
|
+
const scrubbed = ours(value);
|
|
39
|
+
if (scrubbed === null) return null;
|
|
40
|
+
return typeof theirs === "function" ? theirs(scrubbed, hint) : scrubbed;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function sentrySink(sentry, options) {
|
|
44
|
+
const { dsn, signature, applicationId, scrub = true } = options;
|
|
45
|
+
if (!dsn) {
|
|
46
|
+
if (!isDev()) (options.onMissingDsn ?? (() => console.warn("[observability] EXPO_PUBLIC_SENTRY_DSN is not set: errors are not reported to Sentry.")))();
|
|
47
|
+
return { name: "sentry (no DSN)" };
|
|
48
|
+
}
|
|
49
|
+
const environment = options.environment ?? (isDev() ? "development" : sentryEnvironment(signature?.requestedChannel ?? signature?.channel));
|
|
50
|
+
if (!sentry.getClient()) {
|
|
51
|
+
const extra = options.init ?? {};
|
|
52
|
+
const router = options.expoRouter ?? true;
|
|
53
|
+
const integrations = [
|
|
54
|
+
...router && sentry.expoRouterIntegration ? [sentry.expoRouterIntegration({ enableTimeToInitialDisplay: typeof router === "object" ? router.enableTimeToInitialDisplay : true })] : [],
|
|
55
|
+
...options.integrations ?? [],
|
|
56
|
+
...Array.isArray(extra.integrations) ? extra.integrations : []
|
|
57
|
+
];
|
|
58
|
+
const keep = (value) => value;
|
|
59
|
+
const span = (value) => {
|
|
60
|
+
const scrubbed = scrubRecord(value);
|
|
61
|
+
return scrubbed ?? { ...value, description: void 0, data: {} };
|
|
62
|
+
};
|
|
63
|
+
sentry.init({
|
|
64
|
+
sendDefaultPii: false,
|
|
65
|
+
attachScreenshot: false,
|
|
66
|
+
attachViewHierarchy: false,
|
|
67
|
+
reportAccessibilityIdentifier: false,
|
|
68
|
+
tracesSampleRate: options.tracesSampleRate ?? (environment === "production" ? 0.2 : 1),
|
|
69
|
+
...extra,
|
|
70
|
+
dsn,
|
|
71
|
+
environment,
|
|
72
|
+
...sentryRelease(signature, applicationId),
|
|
73
|
+
integrations,
|
|
74
|
+
beforeSend: chain(scrub ? scrubEvent : keep, extra.beforeSend),
|
|
75
|
+
beforeSendTransaction: chain(scrub ? scrubEvent : keep, extra.beforeSendTransaction),
|
|
76
|
+
beforeBreadcrumb: chain((crumb) => scrub ? scrubRecord(withoutTouchLabels(crumb)) : crumb, extra.beforeBreadcrumb),
|
|
77
|
+
beforeSendLog: chain(scrub ? scrubRecord : keep, extra.beforeSendLog),
|
|
78
|
+
beforeSendMetric: chain(scrub ? scrubRecord : keep, extra.beforeSendMetric),
|
|
79
|
+
beforeSendSpan: (value) => {
|
|
80
|
+
const scrubbed = scrub ? span(value) : value;
|
|
81
|
+
return typeof extra.beforeSendSpan === "function" ? extra.beforeSendSpan(scrubbed) : scrubbed;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
for (const [key, value] of Object.entries(signatureTags(signature))) sentry.setTag(key, value);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
name: "sentry",
|
|
88
|
+
// Sentry deduplicates by error object, and `beforeSend` scrubs: it always gets the original.
|
|
89
|
+
scrubsErrors: true,
|
|
90
|
+
captureError(error, context) {
|
|
91
|
+
sentry.captureException(error, {
|
|
92
|
+
// Unhandled when the app could not go on, so release health counts it as a crash.
|
|
93
|
+
mechanism: { handled: !context.fatal, type: `genesis.${context.source}` },
|
|
94
|
+
captureContext: {
|
|
95
|
+
level: context.fatal ? "fatal" : "error",
|
|
96
|
+
tags: { "genesis.source": context.source, ...context.route ? { route: context.route } : {} },
|
|
97
|
+
...context.componentStack ? { contexts: { react: { componentStack: scrub ? scrubString(context.componentStack) : context.componentStack } } } : {}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
breadcrumb(crumb) {
|
|
102
|
+
if (crumb.category === "navigation" && (options.expoRouter ?? true)) return;
|
|
103
|
+
sentry.addBreadcrumb({
|
|
104
|
+
category: crumb.category,
|
|
105
|
+
message: crumb.message,
|
|
106
|
+
level: crumb.level ?? "info",
|
|
107
|
+
data: crumb.data,
|
|
108
|
+
...crumb.timestamp ? { timestamp: crumb.timestamp / 1e3 } : {}
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
setUser: (id) => sentry.setUser(id ? { id } : null),
|
|
112
|
+
event(name, props) {
|
|
113
|
+
sentry.addBreadcrumb({ category: "event", message: name, level: "info", data: props });
|
|
114
|
+
sentry.metrics?.count(name, 1, { attributes: props });
|
|
115
|
+
},
|
|
116
|
+
timing: (name, ms, tags) => sentry.metrics?.distribution(name, ms, { unit: "millisecond", attributes: tags }),
|
|
117
|
+
wrap: (root) => sentry.wrap(root)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { sentryRelease, sentrySink, signatureTags };
|
|
122
|
+
//# sourceMappingURL=observability.js.map
|
|
123
|
+
//# sourceMappingURL=observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/observability/sentry.ts"],"names":[],"mappings":"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","file":"observability.js","sourcesContent":["/**\n * `sentrySink(Sentry, options)`: Sentry through the observability seam.\n * `@sentry/react-native` is an optional peer, passed in rather than\n * imported (`import * as Sentry from \"@sentry/react-native\"`), so an app\n * without it never bundles it.\n *\n * Calling it runs `Sentry.init` at once, so call it at module scope (where\n * `createObservability` is built, before the root layout renders): errors\n * thrown while the app's modules load and the shell's first render are then\n * caught. A second call in the same process (Fast Refresh) reuses the client.\n *\n * What it sets up, on Expo SDK 58 with @sentry/react-native 8:\n * - `expoRouterIntegration` (navigation spans, time to initial display);\n * - release `<applicationId>@<version>+<build>` and dist `<build>` from the\n * version signature (Sentry's own format, so release health lines up),\n * with the update id, channel, runtime version and launch as tags;\n * - the PII scrubber on every event, transaction, span, breadcrumb and log\n * (`beforeSend`, `beforeSendTransaction`, `beforeSendSpan`,\n * `beforeBreadcrumb`, `beforeSendLog`), and the user as an id only;\n * - no default PII, screenshots, view hierarchy or accessibility labels, and\n * touch breadcrumbs without the touched element's label (labels hold names);\n * - fatal errors marked unhandled, so release health counts them as crashes.\n *\n * Native crashes (sentry-cocoa, sentry-android) are built on the device's\n * native side and don't pass through these JavaScript hooks.\n *\n * Errors: the shell (`GenesisNativeApp`) reports every error it catches\n * through `captureError`. Sentry's own global handler stays on for errors\n * before the shell mounts; when both see one error object, Sentry's\n * deduplication (`__sentry_captured__`) sends it once.\n */\nimport type { ComponentType } from \"react\";\nimport type { VersionSignature } from \"../updates/signature\";\nimport { scrubEvent, scrubRecord, scrubString } from \"./scrub\";\nimport type { ObservabilitySink } from \"./sink\";\n\ntype Options = Record<string, unknown>;\ntype Hook<T> = (value: T, hint?: unknown) => T | null | PromiseLike<T | null>;\n\n/**\n * `@sentry/react-native`'s namespace: the calls this sink makes. Method\n * syntax on purpose, so the real namespace (with wider option types) fits.\n */\nexport interface SentryLike {\n init(options: Options): unknown;\n getClient(): unknown;\n wrap<P extends Record<string, unknown>>(root: ComponentType<P>): ComponentType<P>;\n captureException(error: unknown, context?: Options): string;\n addBreadcrumb(breadcrumb: Options): void;\n setUser(user: { id: string } | null): void;\n setTag(key: string, value: string): void;\n expoRouterIntegration?(options?: { enableTimeToInitialDisplay?: boolean }): unknown;\n metrics?: {\n distribution(name: string, value: number, options?: Options): void;\n count(name: string, value?: number, options?: Options): void;\n };\n}\n\nexport interface SentrySinkOptions {\n /** `process.env.EXPO_PUBLIC_SENTRY_DSN`. Empty or missing: Sentry is not started and the sink does nothing. */\n dsn: string | undefined | null;\n /** Default `development` in `__DEV__`, else from the signature's channel: `production`, `preview` (`preview` and `pr-*`), `development`, else `production`. */\n environment?: string;\n /** The version signature (`versionSignature(…)` from `/updates`, or the updates block's `signature`): release, dist and update tags. */\n signature?: VersionSignature;\n /** `Application.applicationId` (expo-application): the release's prefix. */\n applicationId?: string | null;\n /** Default 0.2 in production and 1 elsewhere. */\n tracesSampleRate?: number;\n /** Navigation spans and time to initial display through Expo Router. Default true. */\n expoRouter?: boolean | { enableTimeToInitialDisplay?: boolean };\n /** More integrations (replay, profiling). Masking is yours to set on them. */\n integrations?: readonly unknown[];\n /**\n * Other `Sentry.init` options. The scrubbing hooks run first and yours\n * after, on the scrubbed value; `sendDefaultPii` and the screenshot,\n * view-hierarchy and accessibility options can be set here on purpose.\n */\n init?: Options;\n /** False turns the scrubber off (not recommended; it is also the only thing reducing the user to an id). Default true. */\n scrub?: boolean;\n /** Called instead of `console.warn` when the DSN is missing outside development. */\n onMissingDsn?: () => void;\n}\n\ndeclare const __DEV__: boolean | undefined;\nconst isDev = () => typeof __DEV__ !== \"undefined\" && __DEV__;\n\n/** Sentry's release format: `<applicationId>@<version>+<build>`, with `dist` the build; `undefined` parts when unknown. */\nexport function sentryRelease(signature: VersionSignature | undefined, applicationId?: string | null): { release?: string; dist?: string } {\n const version = signature?.version;\n const build = signature?.build;\n if (!version || !build || !applicationId) return {};\n return { release: `${applicationId}@${version}+${build}`, dist: build };\n}\n\n/** The tags each event carries from the signature. Unknown values are written `unknown`, never left out. */\nexport function signatureTags(signature: VersionSignature | undefined): Record<string, string> {\n if (!signature) return {};\n return {\n \"update.launch\": signature.launch,\n \"update.id\": signature.launch === \"update\" ? (signature.updateId ?? \"unknown\") : signature.launch,\n \"update.channel\": signature.requestedChannel ?? signature.channel ?? (signature.launch === \"off\" ? \"none\" : \"unknown\"),\n \"update.runtime\": signature.runtimeVersion ?? \"unknown\",\n ...(signature.emergency ? { \"update.emergency\": \"true\" } : {}),\n };\n}\n\n/** One Sentry environment per kind of build, not one per channel (`pr-42` is `preview`). */\nexport function sentryEnvironment(channel: string | null | undefined): string {\n if (!channel || channel === \"production\") return \"production\";\n if (channel === \"development\") return \"development\";\n if (channel === \"preview\" || /^pr-\\d+$/.test(channel)) return \"preview\";\n return \"production\";\n}\n\n/** A touch breadcrumb with the touched elements' names only: their labels (accessibility labels, test ids) can hold names. */\nexport function withoutTouchLabels<T extends { category?: unknown; message?: unknown; data?: unknown }>(crumb: T): T {\n if (crumb.category !== \"touch\" || !crumb.data || typeof crumb.data !== \"object\") return crumb;\n const data = crumb.data as { path?: unknown };\n const path = Array.isArray(data.path) ? data.path.map((p) => (p && typeof p === \"object\" ? { name: (p as { name?: unknown }).name } : p)) : undefined;\n const first = path?.[0] as { name?: unknown } | undefined;\n return { ...crumb, message: `Touch event within element: ${typeof first?.name === \"string\" ? first.name : \"unknown\"}`, data: { ...data, ...(path ? { path } : {}) } };\n}\n\nfunction chain<T>(ours: (value: T) => T | null, theirs: unknown): Hook<T> {\n return (value, hint) => {\n const scrubbed = ours(value);\n if (scrubbed === null) return null;\n return typeof theirs === \"function\" ? (theirs as Hook<T>)(scrubbed, hint) : scrubbed;\n };\n}\n\n/**\n * Start Sentry and return a sink for it. Without a DSN it starts nothing and\n * returns a sink that does nothing (a warning outside development says so).\n *\n * @stability Beta\n */\nexport function sentrySink(sentry: SentryLike, options: SentrySinkOptions): ObservabilitySink {\n const { dsn, signature, applicationId, scrub = true } = options;\n if (!dsn) {\n if (!isDev()) (options.onMissingDsn ?? (() => console.warn(\"[observability] EXPO_PUBLIC_SENTRY_DSN is not set: errors are not reported to Sentry.\")))();\n return { name: \"sentry (no DSN)\" };\n }\n const environment = options.environment ?? (isDev() ? \"development\" : sentryEnvironment(signature?.requestedChannel ?? signature?.channel));\n // Fast Refresh runs this module again: a second init would stack integrations on the live client.\n if (!sentry.getClient()) {\n const extra = options.init ?? {};\n const router = options.expoRouter ?? true;\n const integrations = [\n ...(router && sentry.expoRouterIntegration\n ? [sentry.expoRouterIntegration({ enableTimeToInitialDisplay: typeof router === \"object\" ? router.enableTimeToInitialDisplay : true })]\n : []),\n ...(options.integrations ?? []),\n ...(Array.isArray(extra.integrations) ? extra.integrations : []),\n ];\n const keep = <T>(value: T) => value;\n const span = (value: Options): Options => {\n const scrubbed = scrubRecord(value);\n // A span can't be dropped here: fail closed by sending it without its description and data.\n return scrubbed ?? { ...value, description: undefined, data: {} };\n };\n sentry.init({\n sendDefaultPii: false,\n attachScreenshot: false,\n attachViewHierarchy: false,\n reportAccessibilityIdentifier: false,\n tracesSampleRate: options.tracesSampleRate ?? (environment === \"production\" ? 0.2 : 1),\n ...extra,\n dsn,\n environment,\n ...sentryRelease(signature, applicationId),\n integrations,\n beforeSend: chain(scrub ? scrubEvent : keep, extra.beforeSend),\n beforeSendTransaction: chain(scrub ? scrubEvent : keep, extra.beforeSendTransaction),\n beforeBreadcrumb: chain<Options>((crumb) => (scrub ? scrubRecord(withoutTouchLabels(crumb)) : crumb), extra.beforeBreadcrumb),\n beforeSendLog: chain(scrub ? scrubRecord : keep, extra.beforeSendLog),\n beforeSendMetric: chain(scrub ? scrubRecord : keep, extra.beforeSendMetric),\n beforeSendSpan: (value: Options) => {\n const scrubbed = scrub ? span(value) : value;\n return typeof extra.beforeSendSpan === \"function\" ? (extra.beforeSendSpan as (s: Options) => Options)(scrubbed) : scrubbed;\n },\n });\n for (const [key, value] of Object.entries(signatureTags(signature))) sentry.setTag(key, value);\n }\n\n return {\n name: \"sentry\",\n // Sentry deduplicates by error object, and `beforeSend` scrubs: it always gets the original.\n scrubsErrors: true,\n captureError(error, context) {\n sentry.captureException(error, {\n // Unhandled when the app could not go on, so release health counts it as a crash.\n mechanism: { handled: !context.fatal, type: `genesis.${context.source}` },\n captureContext: {\n level: context.fatal ? \"fatal\" : \"error\",\n tags: { \"genesis.source\": context.source, ...(context.route ? { route: context.route } : {}) },\n ...(context.componentStack ? { contexts: { react: { componentStack: scrub ? scrubString(context.componentStack) : context.componentStack } } } : {}),\n },\n });\n },\n breadcrumb(crumb) {\n // Sentry's Expo Router integration records navigation itself.\n if (crumb.category === \"navigation\" && (options.expoRouter ?? true)) return;\n sentry.addBreadcrumb({\n category: crumb.category,\n message: crumb.message,\n level: crumb.level ?? \"info\",\n data: crumb.data,\n ...(crumb.timestamp ? { timestamp: crumb.timestamp / 1000 } : {}),\n });\n },\n setUser: (id) => sentry.setUser(id ? { id } : null),\n event(name, props) {\n sentry.addBreadcrumb({ category: \"event\", message: name, level: \"info\", data: props });\n sentry.metrics?.count(name, 1, { attributes: props });\n },\n timing: (name, ms, tags) => sentry.metrics?.distribution(name, ms, { unit: \"millisecond\", attributes: tags }),\n wrap: (root) => sentry.wrap(root),\n };\n}\n"]}
|
package/dist/persist.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryClient } from '@tanstack/react-query';
|
|
2
|
-
import { A as AsyncStorageLike,
|
|
2
|
+
import { A as AsyncStorageLike, b as QueryPersistence } from './query-DUmVAfsF.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@marktiderman/genesis-native/persist`: save chosen queries to async storage
|
package/dist/persist.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DAY_MS } from './chunk-
|
|
1
|
+
import { DAY_MS } from './chunk-VTJDIKFC.js';
|
|
2
2
|
import { defaultShouldDehydrateQuery } from '@tanstack/react-query';
|
|
3
3
|
import { persistQueryClientSubscribe, persistQueryClientRestore } from '@tanstack/query-persist-client-core';
|
|
4
4
|
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
package/dist/push.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { a9 as PushPermissionStatus, aa as NotificationLike, ab as NotificationResponseLike, u as LinkOptions, ac as QuietHours } from './blocks-a1YQ1Elf.js';
|
|
2
|
+
export { ad as ChannelImportance, ae as ChannelInputLike, af as DEFAULT_PREFERENCES, ag as NotificationBehaviorLike, ah as NotificationCategory, ai as NotificationPreferences, aj as NotificationsModuleLike, ak as PermissionRequestLike, al as PermissionState, am as PermissionStatusLike, an as PermissionStore, ao as PreferencesState, ap as PreferencesStatus, aq as PreferencesStore, ar as PromptOptions, as as PromptState, at as PromptStore, au as PushAppStateLike, av as PushBackend, aw as PushBackendError, ax as PushBlock, ay as PushChannel, az as PushErrorSource, aA as PushOnError, aB as PushOptions, aC as PushPromptProps, aD as PushPromptSheet, aE as PushProvider, aF as PushRoot, aG as PushRootProps, aH as PushSlots, aI as PushStorageLike, aJ as PushSupabaseLike, aK as Registration, aL as RegistrationState, aM as RegistrationStatus, aN as SubscriptionLike, aO as canPush, aP as createPermissionStore, aQ as createPreferencesStore, aR as createPromptStore, aS as createPush, aT as createRegistration, aU as statusOf, aV as supabasePushBackend, aW as useBadge, aX as useNotificationPreferences, aY as useOptionalPush, aZ as usePush, a_ as usePushPermissionState, a$ as usePushPrompt, b0 as usePushRegistration, b1 as useSuppressNotifications, b2 as validPreferences } from './blocks-a1YQ1Elf.js';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { Slots, SlotPropsFor } from '@marktiderman/genesis-core/slots';
|
|
6
|
+
import { SettingsPageProps, SettingsPageRow } from '@marktiderman/genesis-ui-native/layouts';
|
|
7
|
+
import '@marktiderman/genesis-features/blocks';
|
|
8
|
+
import '@tanstack/react-query';
|
|
9
|
+
import '@marktiderman/genesis-design-system';
|
|
10
|
+
import '@marktiderman/genesis-core/provider';
|
|
11
|
+
import '@marktiderman/genesis-ui-native/components';
|
|
12
|
+
import './query-DUmVAfsF.js';
|
|
13
|
+
|
|
14
|
+
interface NotificationSettingsCopy {
|
|
15
|
+
permissionSection: string;
|
|
16
|
+
allow: string;
|
|
17
|
+
status: Record<PushPermissionStatus, string>;
|
|
18
|
+
turnOn: string;
|
|
19
|
+
openSettings: string;
|
|
20
|
+
noProjectId: string;
|
|
21
|
+
noToken: string;
|
|
22
|
+
registerFailed: string;
|
|
23
|
+
categoriesSection: string;
|
|
24
|
+
categoriesFootnote: string;
|
|
25
|
+
quietHoursSection: string;
|
|
26
|
+
quietHours: string;
|
|
27
|
+
quietHoursOnNow: string;
|
|
28
|
+
from: string;
|
|
29
|
+
to: string;
|
|
30
|
+
timeZone: string;
|
|
31
|
+
useDeviceTimeZone: string;
|
|
32
|
+
noTimeZone: string;
|
|
33
|
+
quietHoursFootnote: string;
|
|
34
|
+
privacySection: string;
|
|
35
|
+
showPreviews: string;
|
|
36
|
+
previewsFootnote: string;
|
|
37
|
+
saveFailed: string;
|
|
38
|
+
loadFailed: string;
|
|
39
|
+
}
|
|
40
|
+
declare const notificationSettingsCopy: NotificationSettingsCopy;
|
|
41
|
+
/** The permission part's props: what `usePushPermission()` returns. */
|
|
42
|
+
interface PermissionPartProps {
|
|
43
|
+
status: PushPermissionStatus;
|
|
44
|
+
requesting: boolean;
|
|
45
|
+
/** Shows the system prompt (a tap is the person's intent, so no soft prompt first). */
|
|
46
|
+
request: () => void;
|
|
47
|
+
/** Opens the app's page in Settings, once the system won't ask again. */
|
|
48
|
+
openSettings: (() => void) | null;
|
|
49
|
+
/** Why this phone isn't registered, in the copy's words, or null. */
|
|
50
|
+
problem: string | null;
|
|
51
|
+
copy: NotificationSettingsCopy;
|
|
52
|
+
}
|
|
53
|
+
interface CategoryRow {
|
|
54
|
+
id: string;
|
|
55
|
+
title: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
on: boolean;
|
|
58
|
+
}
|
|
59
|
+
interface CategoriesPartProps {
|
|
60
|
+
/** The saved settings aren't loaded (yet): nothing can change, so nothing overwrites them. */
|
|
61
|
+
disabled: boolean;
|
|
62
|
+
categories: CategoryRow[];
|
|
63
|
+
setOn: (id: string, on: boolean) => void;
|
|
64
|
+
saving: boolean;
|
|
65
|
+
copy: NotificationSettingsCopy;
|
|
66
|
+
}
|
|
67
|
+
interface QuietHoursPartProps {
|
|
68
|
+
/** The saved settings aren't loaded (yet): nothing can change, so nothing overwrites them. */
|
|
69
|
+
disabled: boolean;
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
start: string;
|
|
72
|
+
end: string;
|
|
73
|
+
timeZone: string | null;
|
|
74
|
+
/** This phone's zone, when it differs from the saved one (it travelled). */
|
|
75
|
+
deviceTimeZone: string | null;
|
|
76
|
+
/** In quiet hours right now (shown only; the server decides). */
|
|
77
|
+
activeNow: boolean;
|
|
78
|
+
setEnabled: (on: boolean) => void;
|
|
79
|
+
setStart: (clock: string) => void;
|
|
80
|
+
setEnd: (clock: string) => void;
|
|
81
|
+
adoptDeviceTimeZone: () => void;
|
|
82
|
+
saving: boolean;
|
|
83
|
+
copy: NotificationSettingsCopy;
|
|
84
|
+
}
|
|
85
|
+
interface PrivacyPartProps {
|
|
86
|
+
/** The saved settings aren't loaded (yet): nothing can change, so nothing overwrites them. */
|
|
87
|
+
disabled: boolean;
|
|
88
|
+
hidePreviews: boolean;
|
|
89
|
+
setHidePreviews: (hide: boolean) => void;
|
|
90
|
+
saving: boolean;
|
|
91
|
+
copy: NotificationSettingsCopy;
|
|
92
|
+
}
|
|
93
|
+
type NotificationSettingsSlots = {
|
|
94
|
+
permission: PermissionPartProps;
|
|
95
|
+
categories: CategoriesPartProps;
|
|
96
|
+
quietHours: QuietHoursPartProps;
|
|
97
|
+
privacy: PrivacyPartProps;
|
|
98
|
+
};
|
|
99
|
+
/** The permission part (rung 4). */
|
|
100
|
+
declare function usePushPermission(copy?: NotificationSettingsCopy): PermissionPartProps;
|
|
101
|
+
/** The categories part (rung 4). */
|
|
102
|
+
declare function useNotificationCategories(copy?: NotificationSettingsCopy): CategoriesPartProps;
|
|
103
|
+
/** The quiet-hours part (rung 4). */
|
|
104
|
+
declare function useQuietHours(copy?: NotificationSettingsCopy): QuietHoursPartProps;
|
|
105
|
+
/** The privacy part (rung 4). */
|
|
106
|
+
declare function usePrivacyPreviews(copy?: NotificationSettingsCopy): PrivacyPartProps;
|
|
107
|
+
/** The permission part's default rows. */
|
|
108
|
+
declare function permissionRows(p: PermissionPartProps): SettingsPageRow[];
|
|
109
|
+
/** The categories part's default rows. */
|
|
110
|
+
declare function categoryRows(p: CategoriesPartProps): SettingsPageRow[];
|
|
111
|
+
/** The quiet-hours part's default rows. */
|
|
112
|
+
declare function quietHoursRows(p: QuietHoursPartProps): SettingsPageRow[];
|
|
113
|
+
/** The privacy part's default rows. */
|
|
114
|
+
declare function privacyRows(p: PrivacyPartProps): SettingsPageRow[];
|
|
115
|
+
interface NotificationSettingsProps {
|
|
116
|
+
/** Your words: any of `notificationSettingsCopy`'s, replaced. */
|
|
117
|
+
copy?: Partial<NotificationSettingsCopy>;
|
|
118
|
+
/** Replace a part (rendered in its section) or drop its section (`null`). */
|
|
119
|
+
slots?: Slots<NotificationSettingsSlots>;
|
|
120
|
+
/** More props for a part, merged over what the screen passes. */
|
|
121
|
+
slotProps?: SlotPropsFor<NotificationSettingsSlots>;
|
|
122
|
+
/** Passed to SettingsPage (its own `slots` and `slotProps` reach rows and headers). */
|
|
123
|
+
page?: Omit<SettingsPageProps, "sections" | "children">;
|
|
124
|
+
/** Above the first section. */
|
|
125
|
+
children?: ReactNode;
|
|
126
|
+
testID?: string;
|
|
127
|
+
}
|
|
128
|
+
/** The notification preferences screen. Needs the push block (in GenesisNativeApp's `blocks`, or a `PushProvider`). */
|
|
129
|
+
declare function NotificationSettings({ copy: overrides, slots, slotProps, page, children, testID }: NotificationSettingsProps): react.JSX.Element;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Where a tapped notification goes. The sender puts an app path in
|
|
133
|
+
* `data.url` (`/messages/42`); it goes through the same `normalizeLink` as
|
|
134
|
+
* every deep link, so a path the app doesn't know opens `/` and an ignored
|
|
135
|
+
* one goes nowhere. Without link options, only a plain app path is followed.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
/** The data a notification carries (`content.data`), or `{}`. */
|
|
139
|
+
declare function notificationData(notification: NotificationLike): Record<string, unknown>;
|
|
140
|
+
/** The app path a tap should open, or null. */
|
|
141
|
+
declare function pathForResponse(response: NotificationResponseLike, links?: LinkOptions): string | null;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Quiet hours on the phone: only for showing them ("on now, until 07:00").
|
|
145
|
+
* Whether a push waits is decided on the server (migration 0005's
|
|
146
|
+
* genesis_push_status), in the person's saved time zone, so a phone with a
|
|
147
|
+
* wrong clock or in another zone can't change it.
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/** Minutes since midnight for `"HH:MM"`, or null. */
|
|
151
|
+
declare function parseClock(value: string): number | null;
|
|
152
|
+
/** `"HH:MM"` for minutes since midnight (wrapping a day). */
|
|
153
|
+
declare function formatClock(minutes: number): string;
|
|
154
|
+
/** `"HH:MM"` for a `Date`'s local time (what a time picker hands back). */
|
|
155
|
+
declare function clockOf(date: Date): string;
|
|
156
|
+
/** Today at `"HH:MM"` local, for a time picker's value. */
|
|
157
|
+
declare function dateAt(clock: string, today?: Date): Date;
|
|
158
|
+
/** This phone's IANA time zone, or null when the JavaScript engine can't say. */
|
|
159
|
+
declare function deviceTimeZone(): string | null;
|
|
160
|
+
/** Minutes since midnight at `at` in `timeZone`, or null for a zone the engine doesn't know. */
|
|
161
|
+
declare function minutesIn(timeZone: string, at: Date): number | null;
|
|
162
|
+
/**
|
|
163
|
+
* Are quiet hours on at `at`? The same rule as the server: the start is
|
|
164
|
+
* inclusive, the end exclusive, a start after the end runs past midnight, a
|
|
165
|
+
* start equal to the end is no quiet hours, and an unknown zone is never quiet.
|
|
166
|
+
*/
|
|
167
|
+
declare function isQuietAt(quiet: QuietHours, at?: Date): boolean;
|
|
168
|
+
|
|
169
|
+
export { type CategoriesPartProps, type CategoryRow, NotificationLike, NotificationResponseLike, NotificationSettings, type NotificationSettingsCopy, type NotificationSettingsProps, type NotificationSettingsSlots, type PermissionPartProps, type PrivacyPartProps, PushPermissionStatus, QuietHours, type QuietHoursPartProps, categoryRows, clockOf, dateAt, deviceTimeZone, formatClock, isQuietAt, minutesIn, notificationData, notificationSettingsCopy, parseClock, pathForResponse, permissionRows, privacyRows, quietHoursRows, useNotificationCategories, usePrivacyPreviews, usePushPermission, useQuietHours };
|