~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

The space type private repositories are has a lexicon, dev.knotless.space

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:space/lexicon
docs/design/access.md+8−3
@@ -62,9 +62,14 @@ The scope is built from the same constants the records and calls use, so a
new record kind is asked for as soon as it is added. A session from before
then asks again at its next login.
The space scope names every space type. Naming `dev.knotless.space` alone
would make the authorization server resolve that type's lexicon, which is
not published. A PDS without spaces drops the scope it does not know.
The space scope names every space type. An authorization server asked
for a space type by name resolves that type's lexicon as the account
approves, and refuses the login if it cannot. A private repository's
type has one, `dev.knotless.space`, published with knotless's other
lexicons, which lists the collections its space holds. An organization's
space has none: its type, `dev.knotless.org`, is the NSID of the
organization's record, whose lexicon is no space. A PDS without spaces
drops the scope it does not know.
## Private repositories
docs/design/gateway.md+2−2
@@ -62,8 +62,8 @@ record in public, its `orgMember` records in public and in its spaces,
its own space for members, and
making and changing the members of its spaces, never deleting one. Space
types go unnamed
(`space:*`): naming one has the PDS look up its lexicon, which is not
published.
(`space:*`): naming one has the PDS look up its lexicon, and an
organization's space type has none ([Scopes](access.md#scopes)).
`redirect` is left out, since a gateway never renames a repository. The
scope is `atproto repo:dev.knotless.repo repo:dev.knotless.ref
repo:dev.knotless.claim repo:dev.knotless.pack repo:dev.knotless.org
harness/lexicons.mjs+33−1
@@ -59,9 +59,20 @@ try {
}
linted = e.stdout
}
// goat 0.2.6 knows no space lexicon (`"type": "space"`, from the
// permissioned-data alpha) and refuses the whole file, so those files are
// checked below instead, against what the alpha's @atproto/lex-document
// takes. Only that refusal is let go, and only for a file whose main is a
// space: any other finding of it stands.
const spaces = new Set(
files(dir).filter((f) => JSON.parse(readFileSync(f, 'utf8')).defs?.main?.type === 'space').map((f) => relative(root, f)),
)
const unknownSpace = (found) =>
found['lint-name'] === 'schema-json-parse' && found.message === 'unexpected schema type: space' && spaces.has(found['file-path'])
for (const line of linted.split('\n').filter(Boolean)) {
const found = JSON.parse(line)
if (!kept.has(`${found.nsid} ${found['lint-name']}`)) say(found.nsid, `${found['lint-name']}: ${found.message}`)
if (unknownSpace(found)) continue
if (!kept.has(`${found.nsid} ${found['lint-name']}`)) say(found.nsid ?? found['file-path'], `${found['lint-name']}: ${found.message}`)
}
/// Walks every schema in `def`, calling `visit(schema, path)`.
@@ -101,6 +112,22 @@ for (const file of files(dir)) {
}
}
// A space lexicon, as the alpha's lexiconSpaceSchema takes it: a key, a
// name of 1 to 64 characters for consent screens, and its collections,
// each a record lexicon here. It is the file's only def, as goat, which
// skips the file, lints none of it.
const nsids = new Set([...now.values()].filter((d) => d.defs?.main?.type === 'record').map((d) => d.id))
for (const file of spaces) {
const doc = now.get(file)
const at = `${doc.id}#main`
const def = doc.defs.main
if (Object.keys(doc.defs).length > 1) say(doc.id, 'a space lexicon has its main def alone')
if (!/^(any|nsid|tid|literal:.+)$/.test(def.key ?? '')) say(at, 'a space needs a key: any, nsid, tid or literal:<value>')
if (typeof def.name !== 'string' || def.name.length < 1 || def.name.length > 64) say(at, 'a space needs a name of 1 to 64 characters')
if (!Array.isArray(def.collections)) say(at, 'a space lists its collections')
for (const c of def.collections ?? []) if (!nsids.has(c)) say(`${at}.collections`, `${c} is not a record lexicon here`)
}
// What each schema in `base` was, against what it is now.
const shape = (s) => JSON.stringify({ type: s.type, format: s.format, ref: s.ref, refs: s.refs?.slice().sort() })
const loosened = (before, after, path) => {
@@ -164,6 +191,11 @@ if (base) {
const at = `${before.id}#${name}`
if (!after.defs?.[name]) say(at, `removed since ${base}`)
else loosened(def, after.defs[name], at)
// A scope naming a space type alone is granted the collections its
// lexicon lists, so taking one out takes writes from those logins.
if (def.type === 'space')
for (const c of def.collections ?? [])
if (!(after.defs?.[name]?.collections ?? []).includes(c)) say(`${at}.collections`, `${c} was taken out`)
}
}
}
lexicons/dev/knotless/space.jsonnew+31−0
@@ -0,0 +1,31 @@
{
"lexicon": 1,
"id": "dev.knotless.space",
"defs": {
"main": {
"type": "space",
"key": "any",
"name": "Private repository",
"description": "A private repository on knotless, keyed by its name, with its owner as its authority. Its members alone read it. The owner's records of the repository are in their repo in the space, as a public repository's are in their public repo; each member writes their pulls, issues, comments, reactions and labels in theirs, and a runner its checks, so that what is said of the code is as private as the code. An organization's gateway keeps a record there of each of its members, so the repository's readers know who of them pushes to it.",
"collections": [
"dev.knotless.repo",
"dev.knotless.ref",
"dev.knotless.claim",
"dev.knotless.pack",
"dev.knotless.redirect",
"dev.knotless.pull",
"dev.knotless.issue",
"dev.knotless.comment",
"dev.knotless.state",
"dev.knotless.hide",
"dev.knotless.block",
"dev.knotless.queue",
"dev.knotless.label",
"dev.knotless.reaction",
"dev.knotless.check",
"dev.knotless.rerun",
"dev.knotless.orgMember"
]
}
}
}
web/lexicons/README.md+5−0
@@ -3,3 +3,8 @@ as published from bluesky-social/atproto's `lexicons/` at 1cb5b9b80, for
`npm run lex` to make types of beside ours. Only these: `lex install`
would follow every lexicon they name, `tools.ozone` and then `app.bsky`
too. Ours are linted and held to main's by `just lex`; these are not.
`npm run lex` leaves out `dev.knotless.space`, the space type private
repositories are: @atproto/lex 0.4.4 refuses a lexicon of `"type":
"space"`, which the permissioned-data alpha added, and the pages make no
type of a space.
web/package.json+1−1
@@ -4,7 +4,7 @@
"type": "module",
"description": "The web pages knotless-serve shows, drawn from its XRPC queries",
"scripts": {
"lex": "rm -rf .lexicons && mkdir .lexicons && cp -R ../lexicons/. lexicons/. .lexicons/ && lex build --lexicons .lexicons --out src/lib/lexicons --clear --import-ext .ts",
"lex": "rm -rf .lexicons && mkdir .lexicons && cp -R ../lexicons/. lexicons/. .lexicons/ && rm .lexicons/dev/knotless/space.json && lex build --lexicons .lexicons --out src/lib/lexicons --clear --import-ext .ts",
"dev": "npm run lex && vite dev",
"build": "npm run lex && vite build",
"prepare": "svelte-kit sync || echo ''",