Хранилище и настройки
Хранилище
У страницы карточки нет localStorage, indexedDB и cookies — в её песочнице нет источника
(origin), к которому их можно привязать. Вместо них — card.storage: значения JSON, которые
приложение атомарно хранит на диске и которые переживают перезагрузки, усыпление и перезапуски.
Разрешение не нужно.
// This card on the canvas (instance scope).
const draft = await card.storage.get('draft', '') // string, '' when missing
await card.storage.set('draft', `${draft}\nmore`)
await card.storage.set('runs', [{ at: Date.now(), failed: 3 }])
const runs = await card.storage.get<{ at: number; failed: number }[]>('runs') // undefined when missing
await card.storage.delete('draft')
const keys = await card.storage.keys('run:') // keys starting with a prefix
const { bytes, quota } = await card.storage.usage()
render(runs?.length, keys, bytes, quota)
// Shared by every copy of this card, on every canvas (package scope).
await card.storage.package.set('lastSync', Date.now())
card.storage.onChange(({ key, byInstance }) => {
if (key === 'lastSync') render(`updated by card ${byInstance}`)
})| Метод | Результат |
|---|---|
get(key) | Значение или undefined. |
get(key, fallback) | Значение или fallback. Результат типизирован по запасному значению. |
set(key, value) | Сохраняет любое значение JSON. |
delete(key) | |
keys(prefix?) | string[] |
clear() | Удаляет все ключи этой области. |
usage() | { bytes, quota, keys } |
onChange(handler) | Другая копия этой карточки записала ключ пакета: { scope, key, byInstance }. |
Те же методы есть у card.storage.package.
Лимиты: ключи до 256 символов, значения до 1 МБ, не больше 10 000 ключей; 5 МБ на карточку,
20 МБ на пакет. Превышение — QUOTA_EXCEEDED. Запись доходит до диска примерно за четверть секунды и
сбрасывается при выходе из приложения.
Что с ним происходит: хранилище карточки удаляется вместе с карточкой. Хранилище пакета
переживает удаление пакета, если пользователь не отметит Also delete its saved data and secrets.
Обновления хранилище не трогают — держите сохранённые структуры читаемыми для новых версий (храните
поле version, если можете их поменять).
Сохраняйтесь до выгрузки: карточку, скрытую какое-то время, усыпляют, и её страница выбрасывается.
Записывайте то, что ещё в памяти, в card.lifecycle.onSuspend.
Настройки
Объявите поля в settings манифеста; приложение нарисует форму (из
⋯ → Settings… карточки или по вызову card.settings.open()), проверит её и сохранит значения.
Ваша карточка их читает:
const command = card.settings.value<string>('command') ?? 'npm test'
const all = card.settings.values // defaults filled in, secrets never included
const hasKey = card.settings.hasSecret('apiKey') // true when the user saved one
card.settings.onChange((snapshot) => {
render(snapshot.values['command'], snapshot.secrets['apiKey'])
})
// Change your own non-secret settings (a toggle in your UI, say). Validated like the form.
await card.settings.set({ compact: true })
// Open the form on the card (only while it is visible).
if (!hasKey) await card.settings.open()
render(command, all)| Член | Что это |
|---|---|
values | Текущие значения, со значениями по умолчанию. Поддерживаются в актуальном виде. |
secrets | Record<key, boolean>: какие секретные настройки заданы. |
value(key) | Одно значение, тип задаёте вы. |
hasSecret(key) | Задана ли секретная настройка. |
get() | Свежий SettingsSnapshot из приложения. |
set(values) | Меняет несекретные настройки; все копии карточки получают settings.changed. Неверные значения — INVALID_PARAMS. Не больше 60 в минуту. |
open() | Открывает форму настроек на карточке. NOT_VISIBLE, если карточки нет на экране. |
onChange(handler) | Пользователь сохранил форму, или set что-то поменял. |
Области. У поля с "scope": "package" одно значение на все копии вашей карточки; остальные —
свои у каждой карточки.
Секреты. Поле secret вводится только в собственном диалоге приложения — в форме настроек его
строка показывает лишь «задан» или «не задан» и открывает этот диалог на всё окно, — и хранится
приложением в зашифрованном виде. Карточка никогда не может его прочитать — ни через values, ни
каким-либо методом. Чтобы им воспользоваться, вставьте {{secret:<key>}} в
заголовок сетевого запроса; приложение подставит значение на выходе,
и только для хостов в интернете, выданных вашей карточке (никогда для localhost). Не делайте
внутри карточки собственное поле «вставьте ваш API-ключ»: тогда утечь ключ сможет уже по вашей вине,
а пользователям сказано, что NeuroSquad никогда не спрашивает ключи внутри карточки.