gristlabs

Stars and mentions

Last 30 days, Oct 4 – Nov 2

GitHub stars127
mentions4
036912Oct 4Oct 18Nov 2
UTC days · repositories gristlabs owns4 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-23

npm77.4K
019.3K38.7K58K77.4KOct 4Oct 18Nov 2
Oct 30npm: 1/3 packages observed

Across 3 known packages in repositories gristlabs owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

gristlabs’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside gristlabs’s account where gristlabs opened or reviewed pull requests in the past 365 days.

Who noticed gristlabs

Everyone who starred or forked gristlabs’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

4posts
Nov 30 posts
  1. Grist: 232 page titles, 2,189 body matches, no fingerprint, and a spreadsheet that holds the workflow Grist: 232 page titles, 2,189 body matches, no fingerprint, and a spreadsheet that holds the workflow Spreadsheets survive in organisations because they are the fastest way to model a process that nobody has written down yet. Grist takes that idea and adds a database underneath: a self-hosted, open-source tool where a spreadsheet-shaped interface reads and writes a structured store, with access rules attached to rows and columns rather than to a whole file. ZoomEye measurements taken on 26 October 2026 show how small its public footprint is, and what the small number means. The four queries Every query ran against ZoomEye with sub_type="all" and pagesize=1, so totals describe matched assets rather than retrieved records. | Query | Matches | | --- | ---: | | title="Grist" | 232 | | http.body="Grist" | 2,189 | | app="Grist" | 0 | | port=8484 | 1 | The title count of 232 is the tightest figure available: pages whose heading names the product. The body count is roughly nine times larger and includes documentation, tutorials, and responses that mention the name without being the product. The two remaining rows are the instructive ones. There is no application fingerprint, so app="Grist" measures nothing about the population. And the default port query returns a single match across the whole index, which is a strong signal that almost nobody exposes this tool by its documented port on a public address. Why a low port count is the interesting result For most products discussed in this series, the port query returns millions of matches and illustrates how a shared port number becomes meaningless. Grist inverts that. A default port with one match means the deployment pattern is local or internal by default: a container behind a reverse proxy, a synced address, or an install reached through a tunnel rather than published. That pattern is worth naming because it is what good software defaults look like. The developer documents a port, the container listens on it, and the operator puts an authenticated proxy in front. The consequence is that an internet measurement cannot see the population at all, which is the intended outcome. It also means the 232 title matches are the entire visible surface, and that surface is probably documentation mirrors, demo instances, and a handful of deliberately public deployments. What the tool stores Grist's data model is a set of documents, each holding tables whose columns are typed. Attachments live alongside, and access rules can be written as formulas that evaluate against the current user's attributes. Those rules are the security boundary, and they are written by the same people who build the workflow. Three properties follow from that design. A document is a business process. Whatever a team tracked in a spreadsheet — inventory, approvals, timesheets, supplier lists — becomes a table with permissions. The content is operational, not incidental. The access rules are code. A formula-based rule that resolves a user's email against a table column is a legitimate design, and it is also an authorisation decision expressed in a syntax that has no compiler and no tests unless someone writes them. Attachments are files. Any document that stores images, contracts, or exports is a file store reachable through the application, and the storage location matters for backup and access review alike. The decisions that determine exposure Authentication method comes first. A Grist instance can be configured for single sign-on or for local accounts, and the difference decides whether deprovisioning an employee immediately removes access. An instance with local accounts accumulates identities that nobody deletes. Sharing model comes second. A document can be shared by link or restricted to named users, and a link that was generated for a vendor in March is still a working credential in October unless someone revoked it. The sharing list of each document is a reviewable object, and it is the most useful thing to audit. Public signup comes third. A self-hosted instance that permits self-registration is an open tenant on infrastructure the organisation pays for. The setting is a single configuration value and its default deserves checking rather than assuming. A short review plan - Enumerate documents and their sharing scope, sorted by last modification rather than creation, because the recent ones are live processes. - Review access-rule formulas as code: which user attribute each rule trusts, and whether that attribute can be changed by the user. - Confirm that self-registration is disabled on instances reachable beyond a trusted network. - Confirm the storage location for attachments and apply the same access policy as the document store. - Verify that deprovisioning a user in the identity provider removes their access without a manual step. What the measurement supports On 26 October 2026, ZoomEye matched 232 pages titled Grist, 2,189 responses containing the name, no application fingerprint, and a single host on the documented port. Those numbers describe a tool whose deployments are mostly invisible to internet measurement, and that invisibility is a design outcome rather than an accident. The risk in a tool like this is not reachability. It is the authorisation model, and it lives inside documents that no external query can see. References - Grist help centre: support.getgrist.com - Grist source repository: gristlabs/grist-core - ZoomEye search platform: zoomeye.ai Measurement note Queries: title="Grist", http.body="Grist", app="Grist", port=8484. Executed 26 October 2026, sub_type="all", pagesize=1, global scope. Counts describe matching assets, not confirmed vulnerabilities or exploitation.

  2. api-contract-check — библиотека для генерации валидаторов из TS-кода и проверки API-запросов Продолжаю делиться выложенными в OpenSource библиотеками, которые использую в работе. В этот раз речь пойдет о наиболее универсальном, на мой взгляд, подходе для валидации приходящих с бэкенда данных: в клиентской части пишутся обычные DTO-модели на TypeScript, а валидаторы создаются автоматически. Вот ссылки на документацию на русском и английском, а в статье я сравню различные подходы к валидации. Зачем нужна валидация API В большинстве проектов, которые видел, валидация не производилась вообще — вызовы XHR / fetch выполнялись в componentDidMount / useEffect или аналогах для других фреймворков. Это становилось крупнейшей точкой отказа из-за ручных ошибок, внезапного изменения контрактов со стороны бэкенда или просто несогласованности, когда бэкенд обещает string, но присылает null или поле и вовсе отсутствует. В обратную сторону это тоже работает — фронтенд может отправлять некорректные или неиспользуемые бэкендом поля. Интеграция со внешними системами в целом требует валидации для стабильности, иначе поиск рассогласований будет долгим и дорогим, так как ошибки могут всплыть в совершенно неожиданных местах, а не в точке запроса за данными. Поэтому было создано несколько подходов, которые решали вышеперечисленные проблемы. Подход 1: генерация из OpenAPI схем В крупных энтерпрайз-проектах мелочиться не стали. Бэкенд генерировал OpenAPI схемы (например, для отображения в Swagger) и из них либо создавались только TS-типы (минимальный подход), либо создавались готовые эндпоинты для вызова запросов за данными (условно, api.getUser уже типизирован и вызывает fetch на нужную точку) с опциональным встраиванием runtime-валидаторов. Этот подход у многих применяется до сих пор, но количество недостатков слишком велико: сгенерированная схема может по факту расходиться с тем, что присылает бэкенд. На практике это происходит часто и зависит от используемых фреймворков на бэкенде. Например, при param?: string может прийти null вместо отсутствующего параметра, либо из-за сложности устройства типов на бэкенде схема получается неполной версионирование становится очень сложным. Например, для задачи в новой ветке бэкендер опубликовал npm-пакет "@api-spec": "123.3.1877-feature-123", однако в dev-ветку уже вмерджены изменения от других разработчиков, что может вызывать конфликты. Нужны постоянные rebase, перегенерация, переустановка зависимостей, иногда — отдельные инстансы Swagger для тестировщиков. При большом потоке изменений и при использовании нескольких бэкендов, которые генерируют разные npm-пакеты вроде "@api-spec-payments"/"@api-spec-geo", эту рутину приходится выполнять несколько раз в день, а затраты на инфраструктуру растут фронтенд и бэкенд не могут работать над задачей параллельно — обязательно должен сначала быть реализован (хотя бы на моках) бэкенд, чтобы сгенерировать новый пакет. Либо все скатывается в ручной обмен спецификациями в чате, со всей сопутствующей непрозрачностью и отставанием от мастер-веток фронтенд может использовать только 1 свойство, а бэкенд присылает 100 (возможно, это легаси, техдолг или ориентация на разных фронтенд-потребителей). Сгенерированный по OpenAPI клиент не очищает лишнее — он не знает, чем пользуется конкретный фронтенд, соответственно нужна либо ручная выборка нужных данных, либо в состояние приложения попадают лишние данные, занимающие процессорное время и память в большинстве подходов генерируется монолитный API-клиент, в котором не будет работать tree-shaking или lazy loading. Если на главной странице нужен только 1 эндпоинт — загрузятся и все остальные, а если в конкретном проекте используется только часть эндпоинтов — то ненужные все равно попадут в бандл Все, что делает сгенерированный по OpenAPI JS-клиент, — проверяет, что он сгенерирован по этой спецификации. В нем нет знания о нуждах фронтенда-потребителя или гарантии соответствия данным, реально возвращаемым бэкендом. Учитывая большие требования к организационным моментам и инфраструктуре, этот подход довольно неэффективен. Подход 2: ручное описание схемы на фронтенде Если проект перерос MVP, но не дорос до энтерпрайза, то, как правило, используют ручной подход. В OSS огромное количество библиотек для валидации, которые в основном проектировались для форм, но могут применяться и для API. Например, при использовании Zod / Valibot схемы выглядят так: import * as z from 'zod'; const userSchema = z.object({ id: z.string(), name: z.string(), age: z.number().optional(), }); type TypeUser = z.infer<typeof userSchema>;sourcecraft.dev В целом пользоваться этим подходом довольно удобно, но есть и нюансы: не все библиотеки очищают лишние параметры и логируют лишнее размер библиотек, как правило, намного больше, чем необходимо для проверки API-контрактов в проекте теперь существуют типы, написанные вручную и выведенные из валидаторов с помощью infer, что может создавать путаницу вывод типов из схемы увеличивает время прохождения typecheck-проверок, а также ненадежно работает в IDE написать схему вручную все равно немного сложнее и дольше, чем TS-тип Проблемы здесь не выглядят серьезными, но лучше все же использовать специально созданные для валидации API инструменты. Подход 3: генерация валидаторов из TS-типов Это не новый подход — в OSS давно существуют ts-interface-builder и typia. Одни библиотеки создают отдельные файлы с валидаторами, другие — непосредственно модифицируют код с помощью плагина для бандлера. Однако функционал не всегда соответствует именно нуждам проверки API-запросов в плане очистки лишних параметров, логирования, набора поддерживаемых конструкций TS AST и размера. А также итоговые схемы не всегда сериализуемы, то есть их будет сложно использовать с альтернативными библиотеками проверки или выводить в документацию. Здесь и вступает в игру api-contract-check — специализированная библиотека именно для валидации API-запросов. Один из ее модулей работает в пайплайне сборки, создавая схемы для валидации из TS-типов: import path from 'node:path'; import { createValidators } from '@arfa-tools/generator/api-contract-check/builder'; const { result, deps } = createValidators( [path.resolve('src/api/getUser.ts')], { tsconfigPath: 'tsconfig.json', requestDeclaration: 'TypeRequest', responseDeclaration: 'TypeResponse', getDegraded: (names) => console.log(names), } ); // { request: { id: 'string' }, response: { name: 'string' } } console.log(result[0].schema)sourcecraft.dev Итоговая схема — это обычный JS-объект, с которым можно работать как угодно: сериализовать через JSON.stringify и сохранить в отдельный файл, который будет лениво загружаться при вызове преобразовать в схему для Zod / аналога использовать непосредственно в коде вызова вместо отдельных файлов выводить в документацию и тому подобное В любом случае — это уже работа с обычным JS-объектом. Всю сложную работу по резолвингу импортов, сбору типов и конвертации TS AST в JS api-contract-check уже выполнил. Для работы с AST используется довольно производительный алгоритм — syntax interpreter, который по бенчмаркам производительнее ts.createProgram / oxc-parser / SWC и для файла с графом из 100 импортов выполняется за ~2 мс (вне зависимости от того, «холодный» это запуск или «горячий»). Второй модуль работает в рантайме, выполняя валидацию и очистку, при этом весит меньше 1 килобайта в сжатом виде. Если внешний интерфейс для вызова API сделать таким: import type { TypeRequest, TypeResponse } from './api/getUser'; import { validator } from './validators/api/getUser'; const user = await request<TypeRequest, TypeResponse>({ url: '/api/getUser', request: { id: 'user-1' }, validator, });sourcecraft.dev то внутри request достаточно вызвать соответствующие функции для валидации: import { check, type TypeRootSchema } from '@arfa-tools/generator/api-contract-check/checker'; async function request<TRequest, TResponse>({ url, validator, request }: { url: string; request: TRequest; validator: TypeRootSchema; }): Promise<TResponse> { const requestErrors = check({ schema: validator, type: 'request', value: request, getExtraneous: console.warn }); if (requestErrors) { throw new Error(Request validation failed:\n${requestErrors.join('\n')}); } const response = await (await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(request), })).json(); const responseErrors = check({ schema: validator, type: 'response', value: response, getExtraneous: console.warn }); if (responseErrors) { throw new Error(Response validation failed:\n${responseErrors.join('\n')}); } return response as TResponse; }sourcecraft.dev Все лишнее будет очищено и залогировано, а необходимое — проверено на соответствие TS-типам. Скорость работы валидации высокая — это просто проход по объекту со сравнением, но typia, разумеется, будет немного быстрее, так как не использует схемы. Если вы решили преобразовывать схемы для сторонних валидаторов, то нужно использовать их встроенные методы. Почему третий подход наиболее универсален При проверке именно API-запросов практически нет смысла проверять формат email или длину строк, поэтому схемам достаточно обеспечивать соответствие данных TS-типам, так как детальные проверки выполняются на бэкенде и на уровне БД. При этом в формах как раз можно использовать Zod-like валидаторы для оптимистичной проверки (хотя на моей практике было достаточно вручную написанных проверок без сторонних библиотек). Самое важное, что в третьем подходе остается единственный источник правды — нативный TS-тип только с нужными конкретному фронтенду полями, а приведение реальных данных в соответствие и поиск расхождений автоматизированы, находятся в request-функции и не дают некорректным данным попадать в приложение, вызывая непредсказуемые ошибки. Есть, разумеется, и недостаток — необходимо вручную синхронизировать типы в проекте с OpenAPI или бэкендерами, но это не блокирует параллельную разработку фронтенда и бэкенда, не создает существенных конфликтов при мердже и не требует большой инфраструктуры, как в первом подходе. При этом схема подходит и для небольших проектов, добавляя минимум ручной работы и позволяя отлавливать ошибки синхронизации на раннем этапе. api-contract-check входит в состав ARFA Generator через PluginValidators, упрощая интеграцию в процесс сборки, но можно использовать и отдельно для кастомных пайплайнов — например, в подходе с генерацией из OpenAPI библиотека может создавать схемы валидации, так как поддерживает in-memory резолвинг без физически сохраненных файлов. На этом все, остальное можно посмотреть в репозитории и документации, а я пойду оформлять в OpenSource другие свои библиотеки — осталось еще много интересных и много лет используемых, при этом не теряющих актуальности.

  3. 表格越做越复杂,数据还总对不上? Grist 把表格和关系型数据库结合,支持关联视图和 Python 公式。 整理报名信息很合适。 gristlabs/grist-core #Spreadsheet #NoCode #浇朋友

    1 like · 63 views
  4. Reverse proxy and TLS are not part of the grist docker image itself but there are examples on github.com/gristlabs/grist-core/tree/main/docker-…

Trending awards, every completed day and week
Gold
11st place finishes
Silver
02nd place finishes
Bronze
03rd place finishes
Awarded repositories
1Owned by gristlabs now

Repositories

Ordered by gold, then silver, then bronze.

  1. grist-coreBest: 1st by stars, 906 stars100

Every award

Top-three finishes of these repositories in completed trending days and weeks, newest first.

  1. #1 by starsDaily trending
    906 stars
    grist-core

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.