@atproto/pds 0.5.26 → 0.5.27

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atproto/pds
2
2
 
3
+ ## 0.5.27
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5360](https://github.com/bluesky-social/atproto/pull/5360) [`098cdd7`](https://github.com/bluesky-social/atproto/commit/098cdd7dcf11fc0421278dd768f286ee80399e4f) Thanks [@blackmichael](https://github.com/blackmichael)! - Prevent blob uploads from stalling when MIME detection finishes before the other request-stream consumers.
8
+
9
+ - [#5359](https://github.com/bluesky-social/atproto/pull/5359) [`aadb103`](https://github.com/bluesky-social/atproto/commit/aadb10349497d7c6b6ce5641dbbb1fd940dd5b12) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Remove timing races from WebSocket, background indexing, firehose, and Ozone materialized-view tests.
10
+
11
+ - Updated dependencies []:
12
+ - @atproto/oauth-provider@0.22.1
13
+ - @atproto/xrpc-server@0.12.3
14
+ - @atproto-labs/xrpc-utils@0.1.16
15
+
3
16
  ## 0.5.26
4
17
 
5
18
  ### Patch Changes
@@ -264,8 +264,8 @@ async function mimeTypeFromStream(blobStream) {
264
264
  return fileType?.mime;
265
265
  }
266
266
  finally {
267
- // @NOTE Should not be needed
268
- blobStream.destroy();
267
+ // @NOTE Draining avoids a Node pipe cleanup bug that can pause other clones.
268
+ blobStream.resume();
269
269
  }
270
270
  }
271
271
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"transactor.js","sourceRoot":"","sources":["../../../src/actor-store/blob/transactor.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from 'node:crypto'\nimport type stream from 'node:stream'\nimport * as FileTypeModule from 'file-type'\nconst FileType = ((m) => m.default ?? m)(FileTypeModule)\nconst { fromStream: fileTypeFromStream } = FileType\nimport PQueue from 'p-queue'\nimport { SECOND, cloneStream, streamSize } from '@atproto/common'\nimport {\n type BlobRef,\n type Cid,\n type TypedBlobRef,\n cidForRawHash,\n getBlobCidString,\n parseCid,\n} from '@atproto/lex-data'\nimport { BlobNotFoundError, type BlobStore, WriteOpAction } from '@atproto/repo'\nimport { type AtUri, currentDatetimeString } from '@atproto/syntax'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport type { BackgroundQueue } from '../../background.js'\nimport type { com } from '../../lexicons/index.js'\nimport { blobStoreLogger as log } from '../../logger.js'\nimport type { PreparedWrite } from '../../repo/types.js'\nimport type { ActorDb, Blob as BlobTable } from '../db/index.js'\nimport { BlobReader } from './reader.js'\n\nexport type BlobMetadata = {\n tempKey: string\n size: number\n cid: Cid\n mimeType: string\n}\n\nexport class BlobTransactor extends BlobReader {\n constructor(\n public db: ActorDb,\n public blobstore: BlobStore,\n public backgroundQueue: BackgroundQueue,\n ) {\n super(db, blobstore)\n }\n\n async insertBlobs(recordUri: string, blobs: Iterable<BlobRef>) {\n const values = Array.from(blobs, (blob) => ({\n recordUri,\n blobCid: getBlobCidString(blob),\n }))\n\n if (values.length) {\n await this.db.db\n .insertInto('record_blob')\n .values(values)\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n }\n\n async uploadBlobAndGetMetadata(\n userSuggestedMime: string,\n blobStream: stream.Readable,\n ): Promise<BlobMetadata> {\n const [tempKey, size, sha256, sniffedMime] = await Promise.all([\n this.blobstore.putTemp(cloneStream(blobStream)),\n streamSize(cloneStream(blobStream)),\n sha256Stream(cloneStream(blobStream)),\n mimeTypeFromStream(cloneStream(blobStream)),\n ])\n\n return {\n tempKey,\n size,\n cid: cidForRawHash(sha256),\n mimeType: sniffedMime || userSuggestedMime,\n }\n }\n\n async trackUntetheredBlob(metadata: BlobMetadata): Promise<TypedBlobRef> {\n const { tempKey, size, cid, mimeType } = metadata\n const cidStr = cid.toString()\n\n const found = await this.db.db\n .selectFrom('blob')\n .selectAll()\n .where('cid', '=', cidStr)\n .executeTakeFirst()\n if (found?.takedownRef) {\n throw new InvalidRequestError('Blob has been takendown, cannot re-upload')\n }\n\n await this.db.db\n .insertInto('blob')\n .values({\n cid: cidStr,\n mimeType,\n size,\n tempKey,\n createdAt: currentDatetimeString(),\n })\n .onConflict((oc) =>\n oc\n .column('cid')\n .doUpdateSet({ tempKey })\n .where('blob.tempKey', 'is not', null),\n )\n .execute()\n\n return {\n $type: 'blob',\n ref: cid,\n mimeType,\n size,\n }\n }\n\n async processWriteBlobs(rev: string, writes: PreparedWrite[]) {\n await this.deleteDereferencedBlobs(writes)\n\n const ac = new AbortController()\n\n // Limit the number of parallel requests made to the BlobStore by using a\n // a queue with concurrency management.\n type Task = () => Promise<void>\n const tasks: Task[] = []\n\n for (const write of writes) {\n if (isCreate(write) || isUpdate(write)) {\n for (const blob of write.blobs) {\n tasks.push(async () => {\n if (ac.signal.aborted) return\n await this.associateBlob(blob, write.uri)\n await this.verifyBlobAndMakePermanent(blob, ac.signal)\n })\n }\n }\n }\n\n try {\n const queue = new PQueue({\n concurrency: 20,\n // The blob store should already limit the time of every operation. We\n // add a timeout here as an extra precaution.\n timeout: 60 * SECOND,\n throwOnTimeout: true,\n })\n\n // Will reject as soon as any task fails, causing the \"finally\" block\n // below to run, aborting every other pending tasks.\n await queue.addAll(tasks)\n } finally {\n ac.abort()\n }\n }\n\n async updateBlobTakedownStatus(\n cid: Cid,\n takedown: com.atproto.admin.defs.StatusAttr,\n ) {\n const takedownRef = takedown.applied\n ? (takedown.ref ?? currentDatetimeString())\n : null\n await this.db.db\n .updateTable('blob')\n .set({ takedownRef })\n .where('cid', '=', cid.toString())\n .executeTakeFirst()\n\n try {\n // @NOTE find a way to not perform i/o operations during the transaction\n // (typically by using a state in the \"blob\" table, and another process to\n // handle the actual i/o)\n if (takedown.applied) {\n await this.blobstore.quarantine(cid)\n } else {\n await this.blobstore.unquarantine(cid)\n }\n } catch (err) {\n if (!(err instanceof BlobNotFoundError)) {\n log.error(\n { err, cid: cid.toString() },\n 'could not update blob takedown status',\n )\n\n throw err\n }\n }\n }\n\n async deleteDereferencedBlobs(\n writes: PreparedWrite[],\n skipBlobStore?: boolean,\n ) {\n const deletes = writes.filter(isDelete)\n const updates = writes.filter(isUpdate)\n const uris = [...deletes, ...updates].map((w) => w.uri.toString())\n if (uris.length === 0) return\n\n const deletedRepoBlobs = await this.db.db\n .deleteFrom('record_blob')\n .where('recordUri', 'in', uris)\n .returning('blobCid')\n .execute()\n if (deletedRepoBlobs.length === 0) return\n\n const deletedRepoBlobCids = deletedRepoBlobs.map((row) => row.blobCid)\n const duplicateCids = await this.db.db\n .selectFrom('record_blob')\n .where('blobCid', 'in', deletedRepoBlobCids)\n .select('blobCid')\n .execute()\n\n const newBlobCids = writes\n .filter((w) => isUpdate(w) || isCreate(w))\n .flatMap((w) => w.blobs.map((b) => b.ref.toString()))\n\n const cidsToKeep = [\n ...newBlobCids,\n ...duplicateCids.map((row) => row.blobCid),\n ]\n\n const cidsToDelete = deletedRepoBlobCids.filter(\n (cid) => !cidsToKeep.includes(cid),\n )\n if (cidsToDelete.length === 0) return\n\n await this.db.db\n .deleteFrom('blob')\n .where('cid', 'in', cidsToDelete)\n .execute()\n\n if (!skipBlobStore) {\n this.db.onCommit(() => {\n this.backgroundQueue.add(async () => {\n try {\n const cids = cidsToDelete.map((cid) => parseCid(cid))\n await this.blobstore.deleteMany(cids)\n } catch (err) {\n log.error(\n { err, cids: cidsToDelete },\n 'could not delete blobs from blobstore',\n )\n }\n })\n })\n }\n }\n\n async verifyBlobAndMakePermanent(\n blob: TypedBlobRef,\n signal?: AbortSignal,\n ): Promise<void> {\n const found = await this.db.db\n .selectFrom('blob')\n .select(['tempKey', 'size', 'mimeType'])\n .where('cid', '=', blob.ref.toString())\n .where('takedownRef', 'is', null)\n .executeTakeFirst()\n\n signal?.throwIfAborted()\n\n if (!found) {\n throw new InvalidRequestError(\n `Could not find blob: ${blob.ref.toString()}`,\n 'BlobNotFound',\n )\n }\n\n if (found.tempKey) {\n verifyBlob(blob, found)\n\n // @NOTE it is less than ideal to perform async (i/o) operations during a\n // transaction. Especially since there have been instances of the actor-db\n // being locked, requiring to kick the processes.\n\n // The better solution would be to update the blob state in the database\n // (e.g. \"makeItPermanent\") and to process those updates outside of the\n // transaction.\n\n await this.blobstore\n .makePermanent(found.tempKey, blob.ref)\n .catch((err) => {\n log.error(\n { err, cid: blob.ref.toString() },\n 'could not make blob permanent',\n )\n\n throw err\n })\n\n signal?.throwIfAborted()\n\n await this.db.db\n .updateTable('blob')\n .set({ tempKey: null })\n .where('tempKey', '=', found.tempKey)\n .execute()\n }\n }\n\n async insertBlobMetadata(blob: TypedBlobRef): Promise<void> {\n await this.db.db\n .insertInto('blob')\n .values({\n cid: blob.ref.toString(),\n mimeType: blob.mimeType,\n size: blob.size,\n createdAt: currentDatetimeString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n\n async associateBlob(blob: TypedBlobRef, recordUri: AtUri): Promise<void> {\n await this.db.db\n .insertInto('record_blob')\n .values({\n blobCid: blob.ref.toString(),\n recordUri: recordUri.toString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n}\n\nexport class CidNotFound extends Error {\n cid: Cid\n constructor(cid: Cid) {\n super(`cid not found: ${cid.toString()}`)\n this.cid = cid\n }\n}\n\nasync function sha256Stream(toHash: stream.Readable): Promise<Uint8Array> {\n const hash = crypto.createHash('sha256')\n try {\n for await (const chunk of toHash) {\n hash.write(chunk)\n }\n } catch (err) {\n hash.end()\n throw err\n }\n hash.end()\n return hash.read()\n}\n\nasync function mimeTypeFromStream(\n blobStream: stream.Readable,\n): Promise<string | undefined> {\n try {\n const fileType = await fileTypeFromStream(blobStream)\n return fileType?.mime\n } finally {\n // @NOTE Should not be needed\n blobStream.destroy()\n }\n}\n\n/**\n * Ensures that the blob referenced in the record matches the stored blob.\n */\nfunction verifyBlob(\n blob: TypedBlobRef,\n found: Pick<BlobTable, 'size' | 'mimeType'>,\n) {\n if (blob.mimeType !== found.mimeType) {\n throw new InvalidRequestError(\n `Referenced Mimetype does not match stored blob. Expected: ${found.mimeType}, Got: ${blob.mimeType}`,\n 'InvalidMimeType',\n )\n }\n\n if (blob.size !== found.size) {\n throw new InvalidRequestError(\n `Referenced Size does not match stored blob. Expected: ${found.size}, Got: ${blob.size}`,\n 'InvalidSize',\n )\n }\n}\n\nfunction isCreate(write: PreparedWrite) {\n return write.action === WriteOpAction.Create\n}\nfunction isUpdate(write: PreparedWrite) {\n return write.action === WriteOpAction.Update\n}\nfunction isDelete(write: PreparedWrite) {\n return write.action === WriteOpAction.Delete\n}\n"]}
1
+ {"version":3,"file":"transactor.js","sourceRoot":"","sources":["../../../src/actor-store/blob/transactor.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from 'node:crypto'\nimport type stream from 'node:stream'\nimport * as FileTypeModule from 'file-type'\nconst FileType = ((m) => m.default ?? m)(FileTypeModule)\nconst { fromStream: fileTypeFromStream } = FileType\nimport PQueue from 'p-queue'\nimport { SECOND, cloneStream, streamSize } from '@atproto/common'\nimport {\n type BlobRef,\n type Cid,\n type TypedBlobRef,\n cidForRawHash,\n getBlobCidString,\n parseCid,\n} from '@atproto/lex-data'\nimport { BlobNotFoundError, type BlobStore, WriteOpAction } from '@atproto/repo'\nimport { type AtUri, currentDatetimeString } from '@atproto/syntax'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport type { BackgroundQueue } from '../../background.js'\nimport type { com } from '../../lexicons/index.js'\nimport { blobStoreLogger as log } from '../../logger.js'\nimport type { PreparedWrite } from '../../repo/types.js'\nimport type { ActorDb, Blob as BlobTable } from '../db/index.js'\nimport { BlobReader } from './reader.js'\n\nexport type BlobMetadata = {\n tempKey: string\n size: number\n cid: Cid\n mimeType: string\n}\n\nexport class BlobTransactor extends BlobReader {\n constructor(\n public db: ActorDb,\n public blobstore: BlobStore,\n public backgroundQueue: BackgroundQueue,\n ) {\n super(db, blobstore)\n }\n\n async insertBlobs(recordUri: string, blobs: Iterable<BlobRef>) {\n const values = Array.from(blobs, (blob) => ({\n recordUri,\n blobCid: getBlobCidString(blob),\n }))\n\n if (values.length) {\n await this.db.db\n .insertInto('record_blob')\n .values(values)\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n }\n\n async uploadBlobAndGetMetadata(\n userSuggestedMime: string,\n blobStream: stream.Readable,\n ): Promise<BlobMetadata> {\n const [tempKey, size, sha256, sniffedMime] = await Promise.all([\n this.blobstore.putTemp(cloneStream(blobStream)),\n streamSize(cloneStream(blobStream)),\n sha256Stream(cloneStream(blobStream)),\n mimeTypeFromStream(cloneStream(blobStream)),\n ])\n\n return {\n tempKey,\n size,\n cid: cidForRawHash(sha256),\n mimeType: sniffedMime || userSuggestedMime,\n }\n }\n\n async trackUntetheredBlob(metadata: BlobMetadata): Promise<TypedBlobRef> {\n const { tempKey, size, cid, mimeType } = metadata\n const cidStr = cid.toString()\n\n const found = await this.db.db\n .selectFrom('blob')\n .selectAll()\n .where('cid', '=', cidStr)\n .executeTakeFirst()\n if (found?.takedownRef) {\n throw new InvalidRequestError('Blob has been takendown, cannot re-upload')\n }\n\n await this.db.db\n .insertInto('blob')\n .values({\n cid: cidStr,\n mimeType,\n size,\n tempKey,\n createdAt: currentDatetimeString(),\n })\n .onConflict((oc) =>\n oc\n .column('cid')\n .doUpdateSet({ tempKey })\n .where('blob.tempKey', 'is not', null),\n )\n .execute()\n\n return {\n $type: 'blob',\n ref: cid,\n mimeType,\n size,\n }\n }\n\n async processWriteBlobs(rev: string, writes: PreparedWrite[]) {\n await this.deleteDereferencedBlobs(writes)\n\n const ac = new AbortController()\n\n // Limit the number of parallel requests made to the BlobStore by using a\n // a queue with concurrency management.\n type Task = () => Promise<void>\n const tasks: Task[] = []\n\n for (const write of writes) {\n if (isCreate(write) || isUpdate(write)) {\n for (const blob of write.blobs) {\n tasks.push(async () => {\n if (ac.signal.aborted) return\n await this.associateBlob(blob, write.uri)\n await this.verifyBlobAndMakePermanent(blob, ac.signal)\n })\n }\n }\n }\n\n try {\n const queue = new PQueue({\n concurrency: 20,\n // The blob store should already limit the time of every operation. We\n // add a timeout here as an extra precaution.\n timeout: 60 * SECOND,\n throwOnTimeout: true,\n })\n\n // Will reject as soon as any task fails, causing the \"finally\" block\n // below to run, aborting every other pending tasks.\n await queue.addAll(tasks)\n } finally {\n ac.abort()\n }\n }\n\n async updateBlobTakedownStatus(\n cid: Cid,\n takedown: com.atproto.admin.defs.StatusAttr,\n ) {\n const takedownRef = takedown.applied\n ? (takedown.ref ?? currentDatetimeString())\n : null\n await this.db.db\n .updateTable('blob')\n .set({ takedownRef })\n .where('cid', '=', cid.toString())\n .executeTakeFirst()\n\n try {\n // @NOTE find a way to not perform i/o operations during the transaction\n // (typically by using a state in the \"blob\" table, and another process to\n // handle the actual i/o)\n if (takedown.applied) {\n await this.blobstore.quarantine(cid)\n } else {\n await this.blobstore.unquarantine(cid)\n }\n } catch (err) {\n if (!(err instanceof BlobNotFoundError)) {\n log.error(\n { err, cid: cid.toString() },\n 'could not update blob takedown status',\n )\n\n throw err\n }\n }\n }\n\n async deleteDereferencedBlobs(\n writes: PreparedWrite[],\n skipBlobStore?: boolean,\n ) {\n const deletes = writes.filter(isDelete)\n const updates = writes.filter(isUpdate)\n const uris = [...deletes, ...updates].map((w) => w.uri.toString())\n if (uris.length === 0) return\n\n const deletedRepoBlobs = await this.db.db\n .deleteFrom('record_blob')\n .where('recordUri', 'in', uris)\n .returning('blobCid')\n .execute()\n if (deletedRepoBlobs.length === 0) return\n\n const deletedRepoBlobCids = deletedRepoBlobs.map((row) => row.blobCid)\n const duplicateCids = await this.db.db\n .selectFrom('record_blob')\n .where('blobCid', 'in', deletedRepoBlobCids)\n .select('blobCid')\n .execute()\n\n const newBlobCids = writes\n .filter((w) => isUpdate(w) || isCreate(w))\n .flatMap((w) => w.blobs.map((b) => b.ref.toString()))\n\n const cidsToKeep = [\n ...newBlobCids,\n ...duplicateCids.map((row) => row.blobCid),\n ]\n\n const cidsToDelete = deletedRepoBlobCids.filter(\n (cid) => !cidsToKeep.includes(cid),\n )\n if (cidsToDelete.length === 0) return\n\n await this.db.db\n .deleteFrom('blob')\n .where('cid', 'in', cidsToDelete)\n .execute()\n\n if (!skipBlobStore) {\n this.db.onCommit(() => {\n this.backgroundQueue.add(async () => {\n try {\n const cids = cidsToDelete.map((cid) => parseCid(cid))\n await this.blobstore.deleteMany(cids)\n } catch (err) {\n log.error(\n { err, cids: cidsToDelete },\n 'could not delete blobs from blobstore',\n )\n }\n })\n })\n }\n }\n\n async verifyBlobAndMakePermanent(\n blob: TypedBlobRef,\n signal?: AbortSignal,\n ): Promise<void> {\n const found = await this.db.db\n .selectFrom('blob')\n .select(['tempKey', 'size', 'mimeType'])\n .where('cid', '=', blob.ref.toString())\n .where('takedownRef', 'is', null)\n .executeTakeFirst()\n\n signal?.throwIfAborted()\n\n if (!found) {\n throw new InvalidRequestError(\n `Could not find blob: ${blob.ref.toString()}`,\n 'BlobNotFound',\n )\n }\n\n if (found.tempKey) {\n verifyBlob(blob, found)\n\n // @NOTE it is less than ideal to perform async (i/o) operations during a\n // transaction. Especially since there have been instances of the actor-db\n // being locked, requiring to kick the processes.\n\n // The better solution would be to update the blob state in the database\n // (e.g. \"makeItPermanent\") and to process those updates outside of the\n // transaction.\n\n await this.blobstore\n .makePermanent(found.tempKey, blob.ref)\n .catch((err) => {\n log.error(\n { err, cid: blob.ref.toString() },\n 'could not make blob permanent',\n )\n\n throw err\n })\n\n signal?.throwIfAborted()\n\n await this.db.db\n .updateTable('blob')\n .set({ tempKey: null })\n .where('tempKey', '=', found.tempKey)\n .execute()\n }\n }\n\n async insertBlobMetadata(blob: TypedBlobRef): Promise<void> {\n await this.db.db\n .insertInto('blob')\n .values({\n cid: blob.ref.toString(),\n mimeType: blob.mimeType,\n size: blob.size,\n createdAt: currentDatetimeString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n\n async associateBlob(blob: TypedBlobRef, recordUri: AtUri): Promise<void> {\n await this.db.db\n .insertInto('record_blob')\n .values({\n blobCid: blob.ref.toString(),\n recordUri: recordUri.toString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n}\n\nexport class CidNotFound extends Error {\n cid: Cid\n constructor(cid: Cid) {\n super(`cid not found: ${cid.toString()}`)\n this.cid = cid\n }\n}\n\nasync function sha256Stream(toHash: stream.Readable): Promise<Uint8Array> {\n const hash = crypto.createHash('sha256')\n try {\n for await (const chunk of toHash) {\n hash.write(chunk)\n }\n } catch (err) {\n hash.end()\n throw err\n }\n hash.end()\n return hash.read()\n}\n\nasync function mimeTypeFromStream(\n blobStream: stream.Readable,\n): Promise<string | undefined> {\n try {\n const fileType = await fileTypeFromStream(blobStream)\n return fileType?.mime\n } finally {\n // @NOTE Draining avoids a Node pipe cleanup bug that can pause other clones.\n blobStream.resume()\n }\n}\n\n/**\n * Ensures that the blob referenced in the record matches the stored blob.\n */\nfunction verifyBlob(\n blob: TypedBlobRef,\n found: Pick<BlobTable, 'size' | 'mimeType'>,\n) {\n if (blob.mimeType !== found.mimeType) {\n throw new InvalidRequestError(\n `Referenced Mimetype does not match stored blob. Expected: ${found.mimeType}, Got: ${blob.mimeType}`,\n 'InvalidMimeType',\n )\n }\n\n if (blob.size !== found.size) {\n throw new InvalidRequestError(\n `Referenced Size does not match stored blob. Expected: ${found.size}, Got: ${blob.size}`,\n 'InvalidSize',\n )\n }\n}\n\nfunction isCreate(write: PreparedWrite) {\n return write.action === WriteOpAction.Create\n}\nfunction isUpdate(write: PreparedWrite) {\n return write.action === WriteOpAction.Update\n}\nfunction isDelete(write: PreparedWrite) {\n return write.action === WriteOpAction.Delete\n}\n"]}
@@ -6,7 +6,7 @@ export { $nsid };
6
6
  type Main = {
7
7
  $type?: 'app.bsky.embed.video';
8
8
  /**
9
- * The mp4 video file. May be up to 100mb, formerly limited to 50mb.
9
+ * The mp4 video file. May be up to 300mb, formerly limited to 100mb.
10
10
  */
11
11
  video: l.BlobRef;
12
12
  captions?: Caption[];
@@ -7,7 +7,7 @@ const $nsid = 'app.bsky.embed.video';
7
7
  export { $nsid };
8
8
  const main = /*#__PURE__*/ l.typedObject($nsid, 'main',
9
9
  /*#__PURE__*/ l.object({
10
- video: /*#__PURE__*/ l.blob({ accept: ['video/mp4'], maxSize: 100000000 }),
10
+ video: /*#__PURE__*/ l.blob({ accept: ['video/mp4'], maxSize: 300000000 }),
11
11
  captions: /*#__PURE__*/ l.optional(
12
12
  /*#__PURE__*/ l.array(
13
13
  /*#__PURE__*/ l.ref((() => caption)), { maxLength: 20 })),
@@ -1 +1 @@
1
- {"version":3,"file":"video.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/embed/video.defs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAChC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAE3C,MAAM,KAAK,GAAG,sBAAsB,CAAA;AAIpC,OAAO,EAAE,KAAK,EAAE,CAAA;AAyBhB,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CACtC,KAAK,EACL,MAAM;AACN,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC1E,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IAChC,aAAa,CAAC,CAAC,CAAC,KAAK;IACnB,aAAa,CAAC,CAAC,CAAC,GAAG,CAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAQ,CAAC,EACpD,EAAE,SAAS,EAAE,EAAE,EAAE,CAClB,CACF;IACD,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IAC3B,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CACjE;IACD,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACnC,aAAa,CAAC,CAAC,CAAC,GAAG,CACjB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,CAAQ,CACrC,CACF;IACD,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACpC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAuC,CAC9D;CACF,CAAC,CACH,CAAA;AAED,OAAO,EAAE,IAAI,EAAE,CAAA;AAEf,MAAM,KAAK,GAAG,KAAK,CAAA;AAInB,OAAO,EAAE,KAAK,EAAE,CAAA;AAEhB,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC/D,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzD,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzD,MAAM,CAAC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC7D,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACjE,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAUvE,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CACzC,KAAK,EACL,SAAS;AACT,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IACrB,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACpD,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;CACrE,CAAC,CACH,CAAA;AAED,OAAO,EAAE,OAAO,EAAE,CAAA;AAkBlB,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CACtC,KAAK,EACL,MAAM;AACN,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IACrB,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC9C,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACjC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAC1C;IACD,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IAC3B,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CACjE;IACD,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACnC,aAAa,CAAC,CAAC,CAAC,GAAG,CACjB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,CAAQ,CACrC,CACF;IACD,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACpC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAuC,CAC9D;CACF,CAAC,CACH,CAAA;AAED,OAAO,EAAE,IAAI,EAAE,CAAA","sourcesContent":["/*\n * THIS FILE WAS GENERATED BY \"@atproto/lex\". DO NOT EDIT.\n */\n\nimport { l } from '@atproto/lex'\nimport * as EmbedDefs from './defs.defs.js'\n\nconst $nsid = 'app.bsky.embed.video'\n\ntype $nsid = typeof $nsid\n\nexport { $nsid }\n\ntype Main = {\n $type?: 'app.bsky.embed.video'\n\n /**\n * The mp4 video file. May be up to 100mb, formerly limited to 50mb.\n */\n video: l.BlobRef\n captions?: Caption[]\n\n /**\n * Alt text description of the video, for accessibility.\n */\n alt?: string\n aspectRatio?: EmbedDefs.AspectRatio\n\n /**\n * A hint to the client about how to present the video.\n */\n presentation?: 'default' | 'gif' | l.UnknownString\n}\n\nexport type { Main }\n\nconst main = /*#__PURE__*/ l.typedObject<Main>(\n $nsid,\n 'main',\n /*#__PURE__*/ l.object({\n video: /*#__PURE__*/ l.blob({ accept: ['video/mp4'], maxSize: 100000000 }),\n captions: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.array(\n /*#__PURE__*/ l.ref<Caption>((() => caption) as any),\n { maxLength: 20 },\n ),\n ),\n alt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ maxGraphemes: 1000, maxLength: 10000 }),\n ),\n aspectRatio: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.ref<EmbedDefs.AspectRatio>(\n (() => EmbedDefs.aspectRatio) as any,\n ),\n ),\n presentation: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string<{ knownValues: ['default', 'gif'] }>(),\n ),\n }),\n)\n\nexport { main }\n\nconst $type = $nsid\n\ntype $type = typeof $type\n\nexport { $type }\n\nexport const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main)\nexport const $build = /*#__PURE__*/ main.build.bind(main)\nexport const $assert = /*#__PURE__*/ main.assert.bind(main)\nexport const $check = /*#__PURE__*/ main.check.bind(main)\nexport const $cast = /*#__PURE__*/ main.cast.bind(main)\nexport const $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main)\nexport const $matches = /*#__PURE__*/ main.matches.bind(main)\nexport const $parse = /*#__PURE__*/ main.parse.bind(main)\nexport const $safeParse = /*#__PURE__*/ main.safeParse.bind(main)\nexport const $validate = /*#__PURE__*/ main.validate.bind(main)\nexport const $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main)\n\ntype Caption = {\n $type?: 'app.bsky.embed.video#caption'\n lang: l.LanguageString\n file: l.BlobRef\n}\n\nexport type { Caption }\n\nconst caption = /*#__PURE__*/ l.typedObject<Caption>(\n $nsid,\n 'caption',\n /*#__PURE__*/ l.object({\n lang: /*#__PURE__*/ l.string({ format: 'language' }),\n file: /*#__PURE__*/ l.blob({ accept: ['text/vtt'], maxSize: 20000 }),\n }),\n)\n\nexport { caption }\n\ntype View = {\n $type?: 'app.bsky.embed.video#view'\n cid: l.CidString\n playlist: l.UriString\n thumbnail?: l.UriString\n alt?: string\n aspectRatio?: EmbedDefs.AspectRatio\n\n /**\n * A hint to the client about how to present the video.\n */\n presentation?: 'default' | 'gif' | l.UnknownString\n}\n\nexport type { View }\n\nconst view = /*#__PURE__*/ l.typedObject<View>(\n $nsid,\n 'view',\n /*#__PURE__*/ l.object({\n cid: /*#__PURE__*/ l.string({ format: 'cid' }),\n playlist: /*#__PURE__*/ l.string({ format: 'uri' }),\n thumbnail: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ format: 'uri' }),\n ),\n alt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ maxGraphemes: 1000, maxLength: 10000 }),\n ),\n aspectRatio: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.ref<EmbedDefs.AspectRatio>(\n (() => EmbedDefs.aspectRatio) as any,\n ),\n ),\n presentation: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string<{ knownValues: ['default', 'gif'] }>(),\n ),\n }),\n)\n\nexport { view }\n"]}
1
+ {"version":3,"file":"video.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/embed/video.defs.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * THIS FILE WAS GENERATED BY \"@atproto/lex\". DO NOT EDIT.\n */\n\nimport { l } from '@atproto/lex'\nimport * as EmbedDefs from './defs.defs.js'\n\nconst $nsid = 'app.bsky.embed.video'\n\ntype $nsid = typeof $nsid\n\nexport { $nsid }\n\ntype Main = {\n $type?: 'app.bsky.embed.video'\n\n /**\n * The mp4 video file. May be up to 300mb, formerly limited to 100mb.\n */\n video: l.BlobRef\n captions?: Caption[]\n\n /**\n * Alt text description of the video, for accessibility.\n */\n alt?: string\n aspectRatio?: EmbedDefs.AspectRatio\n\n /**\n * A hint to the client about how to present the video.\n */\n presentation?: 'default' | 'gif' | l.UnknownString\n}\n\nexport type { Main }\n\nconst main = /*#__PURE__*/ l.typedObject<Main>(\n $nsid,\n 'main',\n /*#__PURE__*/ l.object({\n video: /*#__PURE__*/ l.blob({ accept: ['video/mp4'], maxSize: 300000000 }),\n captions: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.array(\n /*#__PURE__*/ l.ref<Caption>((() => caption) as any),\n { maxLength: 20 },\n ),\n ),\n alt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ maxGraphemes: 1000, maxLength: 10000 }),\n ),\n aspectRatio: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.ref<EmbedDefs.AspectRatio>(\n (() => EmbedDefs.aspectRatio) as any,\n ),\n ),\n presentation: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string<{ knownValues: ['default', 'gif'] }>(),\n ),\n }),\n)\n\nexport { main }\n\nconst $type = $nsid\n\ntype $type = typeof $type\n\nexport { $type }\n\nexport const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main)\nexport const $build = /*#__PURE__*/ main.build.bind(main)\nexport const $assert = /*#__PURE__*/ main.assert.bind(main)\nexport const $check = /*#__PURE__*/ main.check.bind(main)\nexport const $cast = /*#__PURE__*/ main.cast.bind(main)\nexport const $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main)\nexport const $matches = /*#__PURE__*/ main.matches.bind(main)\nexport const $parse = /*#__PURE__*/ main.parse.bind(main)\nexport const $safeParse = /*#__PURE__*/ main.safeParse.bind(main)\nexport const $validate = /*#__PURE__*/ main.validate.bind(main)\nexport const $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main)\n\ntype Caption = {\n $type?: 'app.bsky.embed.video#caption'\n lang: l.LanguageString\n file: l.BlobRef\n}\n\nexport type { Caption }\n\nconst caption = /*#__PURE__*/ l.typedObject<Caption>(\n $nsid,\n 'caption',\n /*#__PURE__*/ l.object({\n lang: /*#__PURE__*/ l.string({ format: 'language' }),\n file: /*#__PURE__*/ l.blob({ accept: ['text/vtt'], maxSize: 20000 }),\n }),\n)\n\nexport { caption }\n\ntype View = {\n $type?: 'app.bsky.embed.video#view'\n cid: l.CidString\n playlist: l.UriString\n thumbnail?: l.UriString\n alt?: string\n aspectRatio?: EmbedDefs.AspectRatio\n\n /**\n * A hint to the client about how to present the video.\n */\n presentation?: 'default' | 'gif' | l.UnknownString\n}\n\nexport type { View }\n\nconst view = /*#__PURE__*/ l.typedObject<View>(\n $nsid,\n 'view',\n /*#__PURE__*/ l.object({\n cid: /*#__PURE__*/ l.string({ format: 'cid' }),\n playlist: /*#__PURE__*/ l.string({ format: 'uri' }),\n thumbnail: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ format: 'uri' }),\n ),\n alt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ maxGraphemes: 1000, maxLength: 10000 }),\n ),\n aspectRatio: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.ref<EmbedDefs.AspectRatio>(\n (() => EmbedDefs.aspectRatio) as any,\n ),\n ),\n presentation: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string<{ knownValues: ['default', 'gif'] }>(),\n ),\n }),\n)\n\nexport { view }\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/pds",
3
- "version": "0.5.26",
3
+ "version": "0.5.27",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
6
6
  "keywords": [
@@ -73,25 +73,25 @@
73
73
  "uint8arrays": "^5.0.0",
74
74
  "undici": "^8.5.0",
75
75
  "zod": "^3.23.8",
76
- "@atproto-labs/fetch-node": "^0.3.7",
77
76
  "@atproto-labs/simple-store": "^0.5.1",
78
77
  "@atproto-labs/simple-store-memory": "^0.2.6",
78
+ "@atproto-labs/fetch-node": "^0.3.7",
79
79
  "@atproto-labs/simple-store-redis": "^0.1.6",
80
+ "@atproto-labs/xrpc-utils": "^0.1.16",
80
81
  "@atproto/aws": "^0.3.12",
81
82
  "@atproto/common": "^0.7.6",
82
- "@atproto-labs/xrpc-utils": "^0.1.15",
83
- "@atproto/did": "^0.5.4",
84
- "@atproto/lex": "^0.3.5",
85
83
  "@atproto/crypto": "^0.5.4",
84
+ "@atproto/did": "^0.5.4",
86
85
  "@atproto/identity": "^0.5.9",
86
+ "@atproto/lex": "^0.3.5",
87
87
  "@atproto/lex-cbor": "^0.1.6",
88
- "@atproto/lex-json": "^0.1.6",
89
88
  "@atproto/lex-data": "^0.1.7",
89
+ "@atproto/lex-json": "^0.1.6",
90
+ "@atproto/oauth-provider": "^0.22.1",
90
91
  "@atproto/oauth-scopes": "^0.5.9",
91
- "@atproto/oauth-provider": "^0.22.0",
92
+ "@atproto/syntax": "^0.7.4",
92
93
  "@atproto/repo": "^0.10.10",
93
- "@atproto/xrpc-server": "^0.12.2",
94
- "@atproto/syntax": "^0.7.4"
94
+ "@atproto/xrpc-server": "^0.12.3"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@did-plc/server": "^0.0.1",
@@ -107,7 +107,7 @@
107
107
  "jest": "^30.0.0",
108
108
  "puppeteer": "^23.11.1",
109
109
  "ws": "^8.12.0",
110
- "@atproto/api": "^0.20.38",
110
+ "@atproto/api": "^0.20.39",
111
111
  "@atproto/lex-document": "^0.1.9",
112
112
  "@atproto/oauth-client-browser-example": "^0.1.7"
113
113
  },