@getcirrus/pds 0.10.5 → 0.11.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/dist/cli.js +1163 -447
- package/dist/index.d.ts +6 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -26
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -30,14 +30,6 @@ declare class SqliteRepoStorage extends ReadableBlockstore implements RepoStorag
|
|
|
30
30
|
* Get the current revision string.
|
|
31
31
|
*/
|
|
32
32
|
getRev(): Promise<string | null>;
|
|
33
|
-
/**
|
|
34
|
-
* Get the current sequence number for firehose events.
|
|
35
|
-
*/
|
|
36
|
-
getSeq(): Promise<number>;
|
|
37
|
-
/**
|
|
38
|
-
* Increment and return the next sequence number.
|
|
39
|
-
*/
|
|
40
|
-
nextSeq(): Promise<number>;
|
|
41
33
|
/**
|
|
42
34
|
* Get the raw bytes for a block by CID.
|
|
43
35
|
*/
|
|
@@ -226,6 +218,7 @@ declare class SqliteOAuthStorage implements OAuthStorage {
|
|
|
226
218
|
* Initialize the OAuth database schema. Should be called once on DO startup.
|
|
227
219
|
*/
|
|
228
220
|
initSchema(): void;
|
|
221
|
+
private migrateClientTable;
|
|
229
222
|
/**
|
|
230
223
|
* Clean up expired entries. Should be called periodically.
|
|
231
224
|
*/
|
|
@@ -648,7 +641,11 @@ declare class AccountDurableObject extends DurableObject<PDSEnv> {
|
|
|
648
641
|
* RPC method: Firehose status - returns subscriber count and latest sequence
|
|
649
642
|
*/
|
|
650
643
|
rpcGetFirehoseStatus(): Promise<{
|
|
651
|
-
subscribers:
|
|
644
|
+
subscribers: Array<{
|
|
645
|
+
connectedAt: number;
|
|
646
|
+
cursor: number;
|
|
647
|
+
ip: string | null;
|
|
648
|
+
}>;
|
|
652
649
|
latestSeq: number | null;
|
|
653
650
|
}>;
|
|
654
651
|
/** Save an authorization code */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/storage.ts","../src/oauth-storage.ts","../src/blobs.ts","../src/types.ts","../src/account-do.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;cAUa,iBAAA,SACJ,kBAAA,YACG;EAFC,QAAA,GAAA;EAIa,WAAA,CAAA,GAAA,EAAA,UAAA;EAwGA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/storage.ts","../src/oauth-storage.ts","../src/blobs.ts","../src/types.ts","../src/account-do.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;cAUa,iBAAA,SACJ,kBAAA,YACG;EAFC,QAAA,GAAA;EAIa,WAAA,CAAA,GAAA,EAAA,UAAA;EAwGA;;;;EAwBS,UAAA,CAAA,aAAA,CAAA,EAAA,OAAA,CAAA,EAAA,IAAA;EAAR;;;EAwBJ,OAAA,CAAA,CAAA,EAhDL,OAgDK,CAhDG,GAgDH,GAAA,IAAA,CAAA;EAA0B;;;EAmB5B,MAAA,CAAA,CAAA,EAtDJ,OAsDI,CAAA,MAAA,GAAA,IAAA,CAAA;EAAY;;;EAYc,QAAA,CAAA,GAAA,EAvD1B,GAuD0B,CAAA,EAvDpB,OAuDoB,CAvDZ,UAuDY,GAAA,IAAA,CAAA;EAoBxB;;;EAWiB,GAAA,CAAA,GAAA,EAxExB,GAwEwB,CAAA,EAxElB,OAwEkB,CAAA,OAAA,CAAA;EAmClB;;;EA8BG,SAAA,CAAA,IAAA,EA/HF,GA+HE,EAAA,CAAA,EA/HM,OA+HN,CAAA;IAkBsB,MAAA,EAjJE,QAiJF;IAQ3B,OAAA,EAzJgD,GAyJhD,EAAA;EAUe,CAAA,CAAA;EAuItB;;;EAmGI,QAAA,CAAA,GAAA,EA1XI,GA0XJ,EAAA,KAAA,EA1XgB,UA0XhB,EAAA,GAAA,EAAA,MAAA,CAAA,EA1X0C,OA0X1C,CAAA,IAAA,CAAA;EAxiBR;;;kBA0Lc,wBAAwB;;;ACvL/C;EAC0B,UAAA,CAAA,GAAA,ED0MH,GC1MG,EAAA,GAAA,EAAA,MAAA,CAAA,ED0MgB,OC1MhB,CAAA,IAAA,CAAA;EAuHc;;;EAgBN,WAAA,CAAA,MAAA,ED8EP,UC9EO,CAAA,ED8EM,OC9EN,CAAA,IAAA,CAAA;EA8BG;;;EAyBiB,WAAA,CAAA,CAAA,ED0DhC,OC1DgC,CAAA,MAAA,CAAA;EAAR;;;EA6DL,OAAA,CAAA,CAAA,EDOvB,OCPuB,CAAA,IAAA,CAAA;EAOJ;;;EAyBO,WAAA,CAAA,CAAA,EDftB,OCesB,CAAA,MAAA,CAAA;EAAR;;;EA4CO,cAAA,CAAA,CAAA,EDjDlB,OCiDkB,CAAA,OAAA,EAAA,CAAA;EAAR;;;EAxUQ,cAAA,CAAA,WAAA,EAAA,OAAA,EAAA,CAAA,EDySI,OCzSJ,CAAA,IAAA,CAAA;EAAY;;;eDiTnC;EEzTH;;;8BFmUkB;EGlTvB;AAiBZ;;EAkBU,QAAA,CAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAED;;;;;;ACjBT;EAAwD,cAAA,CAAA,CAAA,EAAA,MAAA,EAAA;EAUtC;;;EA6GW,aAAA,CAAA,UAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAR;;;EAgBK,cAAA,CAAA,CAAA,EAAA,OAAA;EAAR;;;EAqBG,aAAA,CAAA,SAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAQA;;;EAyCX,cAAI,CAAA,SAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA;EAFV;;;EA8EA,iBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAiFA;;;EAiKO,iBAAA,CAAA,GAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAFP;;;EAkOiC,cAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EA+BzB;;;EAkCgC,kBAAA,CAAA,CAAA,EAAA,MAAA;EA2EhB;;;EAyBe,kBAAA,CAAA,CAAA,EAAA,MAAA;EAAR;;;EAwHa,gBAAA,CAAA,KAAA,CAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA;IAqCzC,KAAA,EJxoBM,KIwoBN,CAAA;MACc,GAAA,EAAA,MAAA;MASd,SAAA,EAAA,MAAA;IAWuB,CAAA,CAAA;IAAkB,MAAA,CAAA,EAAA,MAAA;EAOpB,CAAA;EASsB;;;EAwB3B,iBAAA,CAAA,CAAA,EAAA,IAAA;EAQM;;;EA4BH,WAAA,CAAA,YAAA,EAAA,MAAA,EAAA,SAAA,EJvrBb,UIurBa,EAAA,OAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAYM;;;EAmB5B,UAAA,CAAA,YAAA,EAAA,MAAA,CAAA,EAAA;IAawB,YAAA,EAAA,MAAA;IAkCiB,SAAA,EJlvBhC,UIkvBgC;IAkDpB,OAAA,EAAA,MAAA;IASV,IAAA,EAAA,MAAA,GAAA,IAAA;IADgB,SAAA,EAAA,MAAA;IAAO,UAAA,EAAA,MAAA,GAoCM,IAAA;EACxC,CAAA,GAAA,IAAA;EAAO;;;EAcoC,YAAA,CAAA,CAAA,EJj0B9B,KIi0B8B,CAAA;IAQ3C,YAAA,EAAA,MAAA;IAAO,IAAA,EAAA,MAAA,GAAA,IAAA;IAQP,SAAA,EAAA,MAAA;IAAO,UAAA,EAAA,MAAA,GAQqC,IAAA;EAA5C,CAAA,CAAA;EAMwC;;;EAexC,aAAA,CAAA,YAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAO;;;EAiBP,oBAAA,CAAA,YAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAO;;;EAoBiC,WAAA,CAAA,CAAA,EAAA,OAAA;EAY/B;;;EAS+B,gBAAA,CAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAc1C;;;EAqBE,mBAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EAAA;IAMqB,SAAA,EAAA,MAAA;IAWrB,IAAA,EAAA,MAAA,GAAA,IAAA;EAQA,CAAA,GAAA,IAAA;EAMgD;;;EAgBH,oBAAA,CAAA,CAAA,EAAA,IAAA;;;;;;;;;;cH/hDpC,kBAAA,YAA8B;;mBACjB;EDLb;;;EA4GK,UAAA,CAAA,CAAA,EAAA,IAAA;EAaD,QAAA,kBAAA;EAWI;;;EAcL,OAAA,CAAA,CAAA,EAAA,IAAA;EAAM,YAAA,CAAA,IAAA,EAAA,MAAA,EAAA,IAAA,ECtBkB,YDsBlB,CAAA,ECtBiC,ODsBjC,CAAA,IAAA,CAAA;EAUC,WAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EChBW,ODgBX,CChBmB,YDgBnB,GAAA,IAAA,CAAA;EAA0B,cAAA,CAAA,IAAA,EAAA,MAAA,CAAA,ECcZ,ODdY,CAAA,IAAA,CAAA;EAAmB,UAAA,CAAA,IAAA,ECsB5C,SDtB4C,CAAA,ECsBhC,ODtBgC,CAAA,IAAA,CAAA;EAArC,gBAAA,CAAA,WAAA,EAAA,MAAA,CAAA,ECuCe,ODvCf,CCuCuB,SDvCvB,GAAA,IAAA,CAAA;EAmBV,iBAAA,CAAA,YAAA,EAAA,MAAA,CAAA,ECoD2B,ODpD3B,CCoDmC,SDpDnC,GAAA,IAAA,CAAA;EAAY,WAAA,CAAA,WAAA,EAAA,MAAA,CAAA,ECiFQ,ODjFR,CAAA,IAAA,CAAA;EAA0B,eAAA,CAAA,GAAA,EAAA,MAAA,CAAA,ECwFtB,ODxFsB,CAAA,IAAA,CAAA;EAYpC,UAAA,CAAA,QAAA,EAAA,MAAA,EAAA,QAAA,ECoFuB,cDpFvB,CAAA,ECoFwC,ODpFxC,CAAA,IAAA,CAAA;EAAwB,SAAA,CAAA,QAAA,EAAA,MAAA,CAAA,ECqGX,ODrGW,CCqGH,cDrGG,GAAA,IAAA,CAAA;EAoBxB,OAAA,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,ECkHkB,ODlHlB,CAAA,ECkH4B,ODlH5B,CAAA,IAAA,CAAA;EAAmB,MAAA,CAAA,UAAA,EAAA,MAAA,CAAA,EC6HP,OD7HO,CC6HC,OD7HD,GAAA,IAAA,CAAA;EAWf,SAAA,CAAA,UAAA,EAAA,MAAA,CAAA,EC8IW,OD9IX,CAAA,IAAA,CAAA;EAAa,iBAAA,CAAA,KAAA,EAAA,MAAA,CAAA,ECyJC,ODzJD,CAAA,OAAA,CAAA;EAmClB;;;EA8BG,OAAA,CAAA,CAAA,EAAA,IAAA;EAkBsB;;;EAyJlC,qBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAkDA;;;;EAtfD,wBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;;;UENK,OAAA;;;;;;;;;;;;;;;;;;AFIjB;;;;;;;;;;;;AA4JoE,KG/IxD,YAAA,GH+IwD,MAAA,GAAA,IAAA,GAAA,MAAA,GAAA,MAAA,GAAA,KAAA,GAAA,MAAA,GAAA,MAAA,GAAA,MAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA;;;;;AA+B7C,UG7JN,MAAA,CH6JM;EAAwB;EAoBxB,GAAA,EAAA,MAAA;EAAmB;EAWf,MAAA,EAAA,MAAA;EAAa;EAmClB,YAAA,EAAA,MAAA;EAUJ;EAUI,UAAA,EAAA,MAAA;EAUG;EAkBsB,WAAA,EAAA,MAAA;EAQ3B;EAUe,kBAAA,EAAA,MAAA;EAuItB;EAkDA,UAAA,EAAA,MAAA;EAmBA;EA8BI,aAAA,EAAA,MAAA;EAxiBR;EACG,OAAA,EG8CF,sBH9CE,CG8CqB,oBH9CrB,CAAA;EAAW;UGgDd;;;EF9CI;EACa,cAAA,CAAA,EAAA,MAAA;EAuHc;;;;;;;;;;;;;EAmJM,aAAA,CAAA,EE3M7B,YF2M6B;;;;;;;AD/Q9C;;;;;;AAoImC,cInGtB,oBAAA,SAA6B,aJmGP,CInGqB,MJmGrB,CAAA,CAAA;EAAR,QAAA,OAAA;EAcX,QAAA,YAAA;EAAM,QAAA,IAAA;EAUC,QAAA,OAAA;EAA0B,QAAA,SAAA;EAAmB,QAAA,SAAA;EAArC,QAAA,kBAAA;EAmBV,QAAA,eAAA;EAAY,WAAA,CAAA,GAAA,EIpIf,kBJoIe,EAAA,GAAA,EIpIU,MJoIV;EAA0B;;;EAgCpC,QAAA,wBAAA;EAAmB;;;EA8CpB,QAAA,UAAA;EAUJ;;;;EA8CE,KAAA,CAAA,CAAA,EIxMK,OJwML,CAAA,IAAA,CAAA;EAUe;;;EA4MtB,QAAA,qBAAA;EA8BI;;;EAviBM,UAAA,CAAA,CAAA,EIsJF,OJtJE,CIsJM,iBJtJN,CAAA;;;;ECEV,eAAA,CAAA,CAAA,EG4Ja,OH5JM,CG4JE,kBH5JF,CAAA;EACN;;;EAuIgB,OAAA,CAAA,CAAA,EG4BxB,OH5BwB,CG4BhB,IH5BgB,CAAA;EAAR;;;EAsCE,YAAA,CAAA,CAAA,EGFb,OHEa,CAAA,IAAA,CAAA;EAiBkB;;;EAgCN,UAAA,CAAA,CAAA,EGtC3B,OHsC2B,CGtCnB,gBHsCmB,CAAA;EA6BP;;;EAesB,OAAA,CAAA,IAAA,EG1E1C,IH0E0C,CAAA,EG1EnC,OH0EmC,CAAA,IAAA,CAAA;EAiBnB;;;EAiCO,eAAA,CAAA,CAAA,EGrHzB,OHqHyB,CAAA;IAWR,GAAA,EAAA,MAAA;IAAR,WAAA,EAAA,MAAA,EAAA;IA4BG,GAAA,EAAA,MAAA;EAWG,CAAA,CAAA;EA/WE;;;kDGwOvC;;IFhPa,MAAO,EEkPd,GAAA,CAAI,YFlPU,CAAA,GAAA,CAAA;;;;ACiBxB;EAiBiB,cAAM,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IAkBU,KAAA,EAAA,MAAA;IAAvB,MAAA,CAAA,EAAA,MAAA;IAED,OAAA,CAAA,EAAA,OAAA;EAkBQ,CAAA,CAAA,EC2Mb,OD3Ma,CAAA;IAAY,OAAA,EC4MlB,KD5MkB,CAAA;;;;ICnChB,CAAA,CAAA;IAA2C,MAAA,CAAA,EAAA,MAAA;EAUtC,CAAA,CAAA;EAAyB;;;EA6GtB,eAAA,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,GAAA,SAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAkKjB,OAlKiB,CAAA;IAQa,GAAA,EAAA,MAAA;IAAR,GAAA,EAAA,MAAA;IAQA,MAAA,EAAA;MAAR,GAAA,EAAA,MAAA;MAQK,GAAA,EAAA,MAAA;IAaM,CAAA;EAAR,CAAA,CAAA;EAQA;;;EAyCX,eAAI,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,CAAA,EA6JV,OA7JU,CAAA;IAFV,MAAA,EAAA;MAoCO,GAAA,EAAA,MAAA;MADP,GAAA,EAAA,MAAA;IA2CA,CAAA;EAiFA,CAAA,GAAA,IAAA,CAAA;EA+DA;;;EAgGA,YAAA,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAhGA,OAgGA,CAAA;IAoKuB,GAAA,EAAA,MAAA;IA8DkB,GAAA,EAAA,MAAA;IAAR,MAAA,EAAA;MA+BzB,GAAA,EAAA,MAAA;MAAR,GAAA,EAAA,MAAA;IAkC2B,CAAA;IAAa,gBAAA,EAAA,MAAA;EA2EhB,CAAA,CAAA;EAAuC;;;EAyBhC,cAAA,CAAA,MAAA,EA7YzB,KA6YyB,CAAA;IAwHG,KAAA,EAAA,MAAA;IAAkB,UAAA,EAAA,MAAA;IAAR,IAAA,CAAA,EAAA,MAAA;IAqCzC,KAAA,CAAA,EAAA,OAAA;EACc,CAAA,CAAA,CAAA,EAriBjB,OAqiBiB,CAAA;IASd,MAAA,EAAA;MAWuB,GAAA,EAAA,MAAA;MAAkB,GAAA,EAAA,MAAA;IAOpB,CAAA;IASsB,OAAA,EAvkBvC,KAukBuC,CAAA;MAQ5B,KAAA,EAAA,MAAA;MAQgB,GAAA,CAAA,EAAA,MAAA;MAQf,GAAA,CAAA,EAAA,MAAA;MAQM,gBAAA,CAAA,EAAA,MAAA;IAQE,CAAA,CAAA;EAYN,CAAA,CAAA;EAQC;;;EAgCjB,gBAAA,CAAA,CAAA,EAjgBkB,OAigBlB,CAAA;IADL,GAAA,EAAA,MAAA;IAawB,IAAA,EAAA,MAAA;IAkCiB,GAAA,EAAA,MAAA;EAkDpB,CAAA,CAAA;EASV;;;EAoCX,QAAA,aAAA;EAAO;;;;EAsBP,YAAA,CAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAtmBiC,OAsmBjC,CAtmByC,UAsmBzC,CAAA;EAAO;;;;;;EA4BoC,iBAAA,CAAA,UAQC,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,CAAA,EA3mB5C,OA2mB4C,CA3mBpC,UA2mBoC,CAAA;EAC5C;;;;;EAiBO,aAAA,CAAA,QAAA,EA3lBoB,UAmmBiB,CAAA,EAnmBJ,OAmmBI,CAAA;IAA5C,GAAA,EAAA,MAAA;IAMqC,GAAA,EAAA,MAAA;IAMG,GAAA,EAAA,MAAA;EAY/B,CAAA,CAAA;EAGT;;;EAoBF,aAAA,CAAA,KAAA,EAvkB0B,UAukB1B,EAAA,QAAA,EAAA,MAAA,CAAA,EAvkByD,OAukBzD,CAvkBiE,OAukBjE,CAAA;EADwB;;;EA4BD,UAAA,CAAA,MAAA,EAAA,MAAA,CAAA,EAzkBU,OAykBV,CAzkBkB,YAykBlB,GAAA,IAAA,CAAA;EAWrB;;;EAoBmD,QAAA,WAAA;EAUxB;;;EAlgDW,QAAA,iBAAA;EAAa;;;;EC+BjD;;;EAAG,QAAA,gBAAA;EAAA;;;;;;;;;;;;;;;iCDy+B6B,UAAU,QAAQ;;;;wBAqCjD,8BACc;;;;sBASd;;;;sBAWuB,kBAAkB;;;;uBAOpB;;;;;;6CASsB;;;;iBAQ5B;;;;;;iCAQgB;;;;kBAQf;;;;wBAQM;;;;0BAQE;;;;oBAYN;;;;qBAQC;;;;2BAYM;;;;2BAQA;;;;wDAW5B;WACK;;;;;;;;;;;uBAYmB;;;;;;;wCAkCiB;;;;;;oBAkDpB;;;;;;0BAQM;iBAChB;;;;;;;;sCADuB,0BAAA,CAoCM,eACxC;;gCAQA,QARO,0BAAA,CAQqC,YAAA;;mCAMR;;sBAAO,0BAAA,CAOH,YACxC;;4CAQA,QARO,0BAAA,CAQqC,SAAA;;8CAQ5C,QARO,0BAAA,CAQqC,SAAA;;uCAMJ;;mCAMJ;;4CAAO,0BAAA,CAQC,iBAC5C;;kCAQA,QARO,0BAAA,CAQqC,cAAA;;uCAArC,0BAAA,CAQiC,UACxC;;iCAQA,QARO,0BAAA,CAQqC,OAAA;;oCAMP;;uCAMG;;kDAY/B,6CAGT;;uCAMwC;;eAE/B;;;;;;;qBAWa,QACxB;;;;;;;0CAY6C;;kEAS3C;;oBAMqB;;2FAWrB;;yCAQA;;;;;+CAMgD;;kDAMG;;;;;;iBAUxB,UAAU,QAAQ;;;;cCn+C3C,KAAG;YAAwB;GAAM,WAAA,CAAA,WAAA"}
|
package/dist/index.js
CHANGED
|
@@ -215,20 +215,6 @@ var SqliteRepoStorage = class extends ReadableBlockstore {
|
|
|
215
215
|
return rows.length > 0 ? rows[0].rev ?? null : null;
|
|
216
216
|
}
|
|
217
217
|
/**
|
|
218
|
-
* Get the current sequence number for firehose events.
|
|
219
|
-
*/
|
|
220
|
-
async getSeq() {
|
|
221
|
-
const rows = this.sql.exec("SELECT seq FROM repo_state WHERE id = 1").toArray();
|
|
222
|
-
return rows.length > 0 ? rows[0].seq ?? 0 : 0;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Increment and return the next sequence number.
|
|
226
|
-
*/
|
|
227
|
-
async nextSeq() {
|
|
228
|
-
this.sql.exec("UPDATE repo_state SET seq = seq + 1 WHERE id = 1");
|
|
229
|
-
return this.getSeq();
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
218
|
* Get the raw bytes for a block by CID.
|
|
233
219
|
*/
|
|
234
220
|
async getBytes(cid) {
|
|
@@ -551,7 +537,6 @@ var SqliteOAuthStorage = class {
|
|
|
551
537
|
*/
|
|
552
538
|
initSchema() {
|
|
553
539
|
this.sql.exec(`
|
|
554
|
-
-- Authorization codes (5 min TTL)
|
|
555
540
|
CREATE TABLE IF NOT EXISTS oauth_auth_codes (
|
|
556
541
|
code TEXT PRIMARY KEY,
|
|
557
542
|
client_id TEXT NOT NULL,
|
|
@@ -565,7 +550,6 @@ var SqliteOAuthStorage = class {
|
|
|
565
550
|
|
|
566
551
|
CREATE INDEX IF NOT EXISTS idx_auth_codes_expires ON oauth_auth_codes(expires_at);
|
|
567
552
|
|
|
568
|
-
-- OAuth tokens
|
|
569
553
|
CREATE TABLE IF NOT EXISTS oauth_tokens (
|
|
570
554
|
access_token TEXT PRIMARY KEY,
|
|
571
555
|
refresh_token TEXT NOT NULL UNIQUE,
|
|
@@ -589,10 +573,12 @@ var SqliteOAuthStorage = class {
|
|
|
589
573
|
redirect_uris TEXT NOT NULL,
|
|
590
574
|
logo_uri TEXT,
|
|
591
575
|
client_uri TEXT,
|
|
576
|
+
token_endpoint_auth_method TEXT NOT NULL DEFAULT 'none',
|
|
577
|
+
jwks TEXT,
|
|
578
|
+
jwks_uri TEXT,
|
|
592
579
|
cached_at INTEGER NOT NULL
|
|
593
580
|
);
|
|
594
581
|
|
|
595
|
-
-- PAR requests (90 sec TTL)
|
|
596
582
|
CREATE TABLE IF NOT EXISTS oauth_par_requests (
|
|
597
583
|
request_uri TEXT PRIMARY KEY,
|
|
598
584
|
client_id TEXT NOT NULL,
|
|
@@ -602,7 +588,6 @@ var SqliteOAuthStorage = class {
|
|
|
602
588
|
|
|
603
589
|
CREATE INDEX IF NOT EXISTS idx_par_expires ON oauth_par_requests(expires_at);
|
|
604
590
|
|
|
605
|
-
-- DPoP nonces for replay prevention (5 min TTL)
|
|
606
591
|
CREATE TABLE IF NOT EXISTS oauth_nonces (
|
|
607
592
|
nonce TEXT PRIMARY KEY,
|
|
608
593
|
created_at INTEGER NOT NULL
|
|
@@ -610,7 +595,6 @@ var SqliteOAuthStorage = class {
|
|
|
610
595
|
|
|
611
596
|
CREATE INDEX IF NOT EXISTS idx_nonces_created ON oauth_nonces(created_at);
|
|
612
597
|
|
|
613
|
-
-- WebAuthn challenges for passkey authentication (2 min TTL)
|
|
614
598
|
CREATE TABLE IF NOT EXISTS oauth_webauthn_challenges (
|
|
615
599
|
challenge TEXT PRIMARY KEY,
|
|
616
600
|
created_at INTEGER NOT NULL
|
|
@@ -618,6 +602,15 @@ var SqliteOAuthStorage = class {
|
|
|
618
602
|
|
|
619
603
|
CREATE INDEX IF NOT EXISTS idx_challenges_created ON oauth_webauthn_challenges(created_at);
|
|
620
604
|
`);
|
|
605
|
+
this.migrateClientTable();
|
|
606
|
+
}
|
|
607
|
+
migrateClientTable() {
|
|
608
|
+
if (!this.sql.exec("PRAGMA table_info(oauth_clients)").toArray().map((r) => r.name).includes("token_endpoint_auth_method")) {
|
|
609
|
+
this.sql.exec("ALTER TABLE oauth_clients ADD COLUMN token_endpoint_auth_method TEXT NOT NULL DEFAULT 'none'");
|
|
610
|
+
this.sql.exec("ALTER TABLE oauth_clients ADD COLUMN jwks TEXT");
|
|
611
|
+
this.sql.exec("ALTER TABLE oauth_clients ADD COLUMN jwks_uri TEXT");
|
|
612
|
+
this.sql.exec("DELETE FROM oauth_clients");
|
|
613
|
+
}
|
|
621
614
|
}
|
|
622
615
|
/**
|
|
623
616
|
* Clean up expired entries. Should be called periodically.
|
|
@@ -712,11 +705,11 @@ var SqliteOAuthStorage = class {
|
|
|
712
705
|
}
|
|
713
706
|
async saveClient(clientId, metadata) {
|
|
714
707
|
this.sql.exec(`INSERT OR REPLACE INTO oauth_clients
|
|
715
|
-
(client_id, client_name, redirect_uris, logo_uri, client_uri, cached_at)
|
|
716
|
-
VALUES (?, ?, ?, ?, ?, ?)`, clientId, metadata.clientName, JSON.stringify(metadata.redirectUris), metadata.logoUri ?? null, metadata.clientUri ?? null, metadata.cachedAt ?? Date.now());
|
|
708
|
+
(client_id, client_name, redirect_uris, logo_uri, client_uri, token_endpoint_auth_method, jwks, jwks_uri, cached_at)
|
|
709
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, clientId, metadata.clientName, JSON.stringify(metadata.redirectUris), metadata.logoUri ?? null, metadata.clientUri ?? null, metadata.tokenEndpointAuthMethod ?? "none", metadata.jwks ? JSON.stringify(metadata.jwks) : null, metadata.jwksUri ?? null, metadata.cachedAt ?? Date.now());
|
|
717
710
|
}
|
|
718
711
|
async getClient(clientId) {
|
|
719
|
-
const rows = this.sql.exec(`SELECT client_id, client_name, redirect_uris, logo_uri, client_uri, cached_at
|
|
712
|
+
const rows = this.sql.exec(`SELECT client_id, client_name, redirect_uris, logo_uri, client_uri, token_endpoint_auth_method, jwks, jwks_uri, cached_at
|
|
720
713
|
FROM oauth_clients WHERE client_id = ?`, clientId).toArray();
|
|
721
714
|
if (rows.length === 0) return null;
|
|
722
715
|
const row = rows[0];
|
|
@@ -726,6 +719,9 @@ var SqliteOAuthStorage = class {
|
|
|
726
719
|
redirectUris: JSON.parse(row.redirect_uris),
|
|
727
720
|
logoUri: row.logo_uri ?? void 0,
|
|
728
721
|
clientUri: row.client_uri ?? void 0,
|
|
722
|
+
tokenEndpointAuthMethod: row.token_endpoint_auth_method ?? "none",
|
|
723
|
+
jwks: row.jwks ? JSON.parse(row.jwks) : void 0,
|
|
724
|
+
jwksUri: row.jwks_uri ?? void 0,
|
|
729
725
|
cachedAt: row.cached_at
|
|
730
726
|
};
|
|
731
727
|
}
|
|
@@ -1606,7 +1602,8 @@ var AccountDurableObject = class extends DurableObject {
|
|
|
1606
1602
|
this.ctx.acceptWebSocket(server);
|
|
1607
1603
|
server.serializeAttachment({
|
|
1608
1604
|
cursor: cursor ?? 0,
|
|
1609
|
-
connectedAt: Date.now()
|
|
1605
|
+
connectedAt: Date.now(),
|
|
1606
|
+
ip: request.headers.get("CF-Connecting-IP") ?? null
|
|
1610
1607
|
});
|
|
1611
1608
|
if (cursor !== null) await this.backfillFirehose(server, cursor);
|
|
1612
1609
|
return new Response(null, {
|
|
@@ -1766,9 +1763,16 @@ var AccountDurableObject = class extends DurableObject {
|
|
|
1766
1763
|
async rpcGetFirehoseStatus() {
|
|
1767
1764
|
const sockets = this.ctx.getWebSockets();
|
|
1768
1765
|
await this.ensureStorageInitialized();
|
|
1769
|
-
const seq =
|
|
1766
|
+
const seq = this.sequencer.getLatestSeq();
|
|
1770
1767
|
return {
|
|
1771
|
-
subscribers: sockets.
|
|
1768
|
+
subscribers: sockets.map((ws) => {
|
|
1769
|
+
const attachment = ws.deserializeAttachment();
|
|
1770
|
+
return {
|
|
1771
|
+
connectedAt: attachment.connectedAt,
|
|
1772
|
+
cursor: attachment.cursor,
|
|
1773
|
+
ip: attachment.ip ?? null
|
|
1774
|
+
};
|
|
1775
|
+
}),
|
|
1772
1776
|
latestSeq: seq || null
|
|
1773
1777
|
};
|
|
1774
1778
|
}
|
|
@@ -4213,9 +4217,20 @@ function renderPasskeyErrorPage(error, description) {
|
|
|
4213
4217
|
</html>`;
|
|
4214
4218
|
}
|
|
4215
4219
|
|
|
4220
|
+
//#endregion
|
|
4221
|
+
//#region src/dashboard.html
|
|
4222
|
+
var dashboard_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>CIRRUS</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n :root {\n --bg: #08090d;\n --panel: #0f1117;\n --border: #1a1d2e;\n --text: #b4bcd0;\n --text-bright: #e8ecf4;\n --accent: #7dd3fc;\n --green: #4ade80;\n --amber: #fbbf24;\n --red: #f87171;\n --dim: #3f4558;\n }\n html,\n body {\n height: 100%;\n background: var(--bg);\n color: var(--text);\n font-family:\n ui-monospace, \"Cascadia Code\", \"Source Code Pro\", Menlo, Consolas,\n \"DejaVu Sans Mono\", monospace;\n overflow: hidden;\n }\n body {\n display: flex;\n flex-direction: column;\n padding: clamp(1rem, 2vw, 2rem);\n gap: clamp(0.75rem, 1.5vw, 1.5rem);\n }\n\n /* Header */\n header {\n display: flex;\n align-items: baseline;\n gap: 1.5rem;\n flex-wrap: wrap;\n }\n .brand {\n font-size: clamp(1.5rem, 3vw, 2.5rem);\n font-weight: 700;\n color: var(--text-bright);\n letter-spacing: 0.15em;\n }\n .server-info {\n display: flex;\n gap: 1.5rem;\n align-items: baseline;\n font-size: clamp(0.9rem, 1.5vw, 1.2rem);\n }\n .hostname {\n color: var(--accent);\n }\n .ver {\n color: var(--dim);\n }\n .identity {\n font-size: clamp(0.8rem, 1.2vw, 1rem);\n color: var(--dim);\n width: 100%;\n }\n .identity .handle {\n color: var(--text);\n }\n\n /* Panels */\n .panels {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: clamp(0.75rem, 1.5vw, 1.5rem);\n }\n .panel {\n background: var(--panel);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: clamp(1rem, 2vw, 1.5rem);\n }\n .panel h2 {\n font-size: clamp(0.7rem, 1vw, 0.85rem);\n letter-spacing: 0.2em;\n color: var(--dim);\n margin-bottom: clamp(0.75rem, 1.5vw, 1.25rem);\n font-weight: 500;\n }\n\n /* Repository panel */\n .record-row {\n display: flex;\n justify-content: space-between;\n padding: 0.3em 0;\n font-size: clamp(0.9rem, 1.5vw, 1.2rem);\n }\n .record-name {\n color: var(--text);\n }\n .record-count {\n color: var(--text-bright);\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n }\n .empty-state {\n color: var(--dim);\n font-style: italic;\n font-size: clamp(0.85rem, 1.3vw, 1.1rem);\n }\n\n /* Federation panel */\n .relay-name {\n font-size: clamp(0.85rem, 1.3vw, 1.1rem);\n color: var(--text);\n margin-bottom: clamp(0.5rem, 1vw, 1rem);\n }\n .sync-status {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n transition: all 0.5s ease;\n }\n .sync-status .status-text {\n font-size: clamp(1.5rem, 3vw, 2.5rem);\n font-weight: 700;\n letter-spacing: 0.1em;\n transition:\n color 0.5s ease,\n text-shadow 0.8s ease;\n }\n .dot {\n width: clamp(10px, 1.2vw, 16px);\n height: clamp(10px, 1.2vw, 16px);\n border-radius: 50%;\n display: inline-block;\n flex-shrink: 0;\n transition:\n background 0.5s ease,\n box-shadow 0.8s ease;\n }\n .sync-status.checking .dot {\n background: var(--dim);\n }\n .sync-status.checking .status-text {\n color: var(--dim);\n }\n .sync-status.unknown .dot {\n background: var(--dim);\n animation: pulse-dim 3s ease-in-out infinite;\n }\n .sync-status.unknown .status-text {\n color: var(--dim);\n }\n .sync-status.behind .dot {\n background: var(--amber);\n animation: pulse 1.5s ease-in-out infinite;\n }\n .sync-status.behind .status-text {\n color: var(--amber);\n }\n .sync-status.synced .dot {\n background: var(--green);\n box-shadow: 0 0 12px var(--green);\n }\n .sync-status.synced .status-text {\n color: var(--green);\n }\n .sync-status.error .dot {\n background: var(--red);\n }\n .sync-status.error .status-text {\n color: var(--red);\n }\n .sync-status.flash .status-text {\n text-shadow:\n 0 0 30px currentColor,\n 0 0 60px currentColor;\n }\n .sync-status.flash .dot {\n box-shadow:\n 0 0 20px currentColor,\n 0 0 40px currentColor;\n }\n .relay-rev {\n font-size: clamp(0.7rem, 1vw, 0.85rem);\n color: var(--dim);\n margin-top: 0.5rem;\n font-variant-numeric: tabular-nums;\n }\n\n /* Events */\n .events-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--panel);\n border: 1px solid var(--border);\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n }\n .events-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: clamp(0.75rem, 1.5vw, 1rem) clamp(1rem, 2vw, 1.5rem);\n border-bottom: 1px solid var(--border);\n flex-shrink: 0;\n }\n .events-header h2 {\n font-size: clamp(0.7rem, 1vw, 0.85rem);\n letter-spacing: 0.2em;\n color: var(--dim);\n font-weight: 500;\n }\n .ws-status {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: clamp(0.7rem, 1vw, 0.85rem);\n color: var(--dim);\n }\n .ws-status.connected .dot {\n background: var(--green);\n animation: pulse 2s ease-in-out infinite;\n }\n .ws-status.connected .ws-label {\n color: var(--green);\n }\n .ws-status.disconnected .dot {\n background: var(--dim);\n }\n .ws-status.error .dot {\n background: var(--red);\n }\n .events-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 clamp(1rem, 2vw, 1.5rem);\n }\n .events-list .empty-state {\n padding: 1rem 0;\n }\n .event {\n display: flex;\n gap: clamp(0.75rem, 1.5vw, 1.5rem);\n padding: 0.4em 0;\n font-size: clamp(0.85rem, 1.3vw, 1.1rem);\n border-bottom: 1px solid rgba(26, 29, 46, 0.5);\n animation: slide-in 0.3s ease-out;\n }\n .event.new {\n background: rgba(125, 211, 252, 0.06);\n transition: background 1.5s ease-out;\n }\n .event-time {\n color: var(--dim);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n }\n .event-seq {\n color: var(--dim);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n min-width: 3em;\n text-align: right;\n }\n .event-action {\n flex-shrink: 0;\n font-weight: 600;\n min-width: 5em;\n }\n .event-action.create {\n color: var(--green);\n }\n .event-action.update {\n color: var(--amber);\n }\n .event-action.delete {\n color: var(--red);\n }\n .event-path {\n color: var(--text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n }\n /* Animations */\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 0.5;\n }\n 50% {\n opacity: 1;\n }\n }\n @keyframes pulse-dim {\n 0%,\n 100% {\n opacity: 0.3;\n }\n 50% {\n opacity: 0.6;\n }\n }\n @keyframes slide-in {\n from {\n opacity: 0;\n transform: translateX(20px);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n\n /* Scrollbar */\n .events-list::-webkit-scrollbar {\n width: 4px;\n }\n .events-list::-webkit-scrollbar-track {\n background: transparent;\n }\n .events-list::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 2px;\n }\n </style>\n </head>\n <body>\n <header>\n <div class=\"brand\">☁️ CIRRUS</div>\n <div class=\"server-info\">\n <span class=\"hostname\" id=\"cfg-hostname\"></span>\n <span class=\"ver\" id=\"cfg-version\"></span>\n </div>\n <div class=\"identity\">\n <span class=\"handle\" id=\"cfg-handle\"></span>\n <span>·</span>\n <span id=\"cfg-did\"></span>\n </div>\n </header>\n\n <section class=\"panels\">\n <div class=\"panel\">\n <h2>REPOSITORY</h2>\n <div id=\"records\"><span class=\"empty-state\">Loading…</span></div>\n </div>\n <div class=\"panel\">\n <h2>FEDERATION</h2>\n <div class=\"relay-name\">bsky.network</div>\n <div class=\"sync-status checking\" id=\"sync-status\">\n <span class=\"dot\"></span>\n <span class=\"status-text\">CHECKING</span>\n </div>\n <div class=\"relay-rev\" id=\"relay-rev\"></div>\n </div>\n </section>\n\n <section class=\"events-container\">\n <div class=\"events-header\">\n <h2>EVENTS</h2>\n <div class=\"ws-status disconnected\" id=\"ws-status\">\n <span class=\"dot\"></span>\n <span class=\"ws-label\">disconnected</span>\n </div>\n </div>\n <div class=\"events-list\" id=\"events\">\n <div class=\"empty-state\">Waiting for events…</div>\n </div>\n </section>\n\n <script>\n {\n const CONFIG = window.__CIRRUS_CONFIG || {};\n const BASE = window.location.origin;\n const RELAY = \"https://bsky.network\";\n const DID = CONFIG.did || \"\";\n const MAX_EVENTS = 100;\n let pdsRev = null;\n let currentSyncStatus = null;\n let reconnectTimer = null;\n\n const $ = (id) => document.getElementById(id);\n\n // -- Populate config into DOM --\n const applyConfig = () => {\n document.title = `CIRRUS \\u00b7 ${CONFIG.hostname || \"\"}`;\n $(\"cfg-hostname\").textContent = CONFIG.hostname || \"\";\n $(\"cfg-version\").textContent = CONFIG.version\n ? `v${CONFIG.version}`\n : \"\";\n $(\"cfg-handle\").textContent = CONFIG.handle\n ? `@${CONFIG.handle}`\n : \"\";\n $(\"cfg-did\").textContent = CONFIG.did || \"\";\n };\n\n // -- Minimal CBOR decoder for firehose frames --\n const decodeCBOR = (d, o) => {\n const view = new DataView(d.buffer, d.byteOffset, d.byteLength);\n const major = d[o] >> 5;\n const additional = d[o] & 0x1f;\n\n const readLen = (off, add) => {\n if (add < 24) return [add, off + 1];\n if (add === 24) return [d[off + 1], off + 2];\n if (add === 25) return [view.getUint16(off + 1), off + 3];\n if (add === 26) return [view.getUint32(off + 1), off + 5];\n if (add === 27)\n return [\n view.getUint32(off + 1) * 0x100000000 + view.getUint32(off + 5),\n off + 9,\n ];\n return [0, off + 1];\n };\n\n switch (major) {\n case 0:\n return readLen(o, additional);\n case 1: {\n const [n, p] = readLen(o, additional);\n return [-1 - n, p];\n }\n case 2: {\n const [n, p] = readLen(o, additional);\n return [d.slice(p, p + n), p + n];\n }\n case 3: {\n const [n, p] = readLen(o, additional);\n return [new TextDecoder().decode(d.subarray(p, p + n)), p + n];\n }\n case 4: {\n let [count, pos] = readLen(o, additional);\n const arr = [];\n for (let i = 0; i < count; i++) {\n const [val, next] = decodeCBOR(d, pos);\n arr.push(val);\n pos = next;\n }\n return [arr, pos];\n }\n case 5: {\n let [count, pos] = readLen(o, additional);\n const obj = {};\n for (let i = 0; i < count; i++) {\n const [key, kNext] = decodeCBOR(d, pos);\n const [val, vNext] = decodeCBOR(d, kNext);\n obj[key] = val;\n pos = vNext;\n }\n return [obj, pos];\n }\n case 6: {\n const [, p] = readLen(o, additional);\n return decodeCBOR(d, p);\n }\n case 7: {\n if (additional === 20) return [false, o + 1];\n if (additional === 21) return [true, o + 1];\n if (additional === 22) return [null, o + 1];\n if (additional === 23) return [undefined, o + 1];\n if (additional === 25) return [null, o + 3];\n if (additional === 26) return [view.getFloat32(o + 1), o + 5];\n if (additional === 27) return [view.getFloat64(o + 1), o + 9];\n return [null, o + 1];\n }\n }\n return [null, o + 1];\n };\n\n const parseFirehoseMessage = (buffer) => {\n try {\n const d = new Uint8Array(buffer);\n const [header, bodyOff] = decodeCBOR(d, 0);\n if (!header || header.op !== 1 || header.t !== \"#commit\")\n return null;\n const [body] = decodeCBOR(d, bodyOff);\n if (!body) return null;\n return {\n seq: body.seq,\n repo: body.repo,\n rev: body.rev,\n ops: (body.ops || []).map((op) => ({\n action: op.action,\n path: op.path,\n })),\n };\n } catch {\n return null;\n }\n };\n\n // -- Friendly collection names --\n const COLLECTION_NAMES = {\n \"app.bsky.feed.post\": \"posts\",\n \"app.bsky.feed.like\": \"likes\",\n \"app.bsky.graph.follow\": \"follows\",\n \"app.bsky.feed.repost\": \"reposts\",\n \"app.bsky.actor.profile\": \"profile\",\n \"app.bsky.graph.block\": \"blocks\",\n \"app.bsky.graph.list\": \"lists\",\n \"app.bsky.graph.listitem\": \"list items\",\n \"app.bsky.feed.generator\": \"feeds\",\n \"app.bsky.feed.threadgate\": \"threadgates\",\n \"app.bsky.graph.starterpack\": \"starter packs\",\n };\n\n const friendlyName = (collection) =>\n COLLECTION_NAMES[collection] || collection.split(\".\").pop();\n\n const animateNumber = (el, target) => {\n let current = parseInt(el.textContent) || 0;\n if (current === target) return;\n const diff = target - current;\n const steps = Math.min(Math.abs(diff), 20);\n const stepSize = diff / steps;\n let step = 0;\n const tick = () => {\n step++;\n if (step >= steps) {\n el.textContent = target;\n return;\n }\n el.textContent = Math.round(current + stepSize * step);\n requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n };\n\n // -- Data fetching --\n const fetchRepoData = async () => {\n try {\n const reposRes = await fetch(\n `${BASE}/xrpc/com.atproto.sync.listRepos`,\n );\n const reposData = await reposRes.json();\n const repo = reposData.repos?.[0];\n if (repo) pdsRev = repo.rev;\n\n const descRes = await fetch(\n `${BASE}/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(DID)}`,\n );\n const desc = await descRes.json();\n const collections = desc.collections || [];\n\n if (collections.length === 0) {\n $(\"records\").innerHTML =\n '<span class=\"empty-state\">No records yet</span>';\n return;\n }\n\n const results = await Promise.all(\n collections.map(async (col) => {\n const res = await fetch(\n `${BASE}/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(DID)}&collection=${encodeURIComponent(col)}&limit=100`,\n );\n const data = await res.json();\n return {\n collection: col,\n count: data.records?.length || 0,\n hasMore: !!data.cursor,\n };\n }),\n );\n\n const container = $(\"records\");\n for (const r of results) {\n const id = `rec-${r.collection.replaceAll(\".\", \"-\")}`;\n const existing = $(id);\n if (existing) {\n const countEl = existing.querySelector(\".record-count\");\n animateNumber(countEl, r.count);\n if (r.hasMore) countEl.textContent = `${r.count}+`;\n } else {\n if (container.querySelector(\".empty-state\"))\n container.innerHTML = \"\";\n const row = document.createElement(\"div\");\n row.className = \"record-row\";\n row.id = id;\n row.innerHTML = `<span class=\"record-name\">${friendlyName(r.collection)}</span><span class=\"record-count\">${r.count}${r.hasMore ? \"+\" : \"\"}</span>`;\n container.appendChild(row);\n }\n }\n } catch (e) {\n console.error(\"Failed to fetch repo data:\", e);\n }\n };\n\n const fetchRelaySync = async () => {\n if (!pdsRev) return;\n try {\n const res = await fetch(\n `${RELAY}/xrpc/com.atproto.sync.getLatestCommit?did=${encodeURIComponent(DID)}`,\n );\n if (res.status === 404) {\n setSyncStatus(\"unknown\");\n return;\n }\n const data = await res.json();\n setSyncStatus(data.rev === pdsRev ? \"synced\" : \"behind\", data.rev);\n } catch {\n setSyncStatus(\"error\");\n }\n };\n\n // -- Sync status display --\n const setSyncStatus = (status, rev) => {\n if (status === currentSyncStatus) return;\n const el = $(\"sync-status\");\n const prevStatus = currentSyncStatus;\n\n el.className = `sync-status ${status}`;\n el.querySelector(\".status-text\").textContent = status.toUpperCase();\n $(\"relay-rev\").textContent = rev ? `rev: ${rev.slice(0, 12)}` : \"\";\n\n if (prevStatus && prevStatus !== status) {\n el.classList.add(\"flash\");\n setTimeout(() => el.classList.remove(\"flash\"), 1200);\n }\n currentSyncStatus = status;\n };\n\n // -- Event stream --\n const addEvent = (seq, action, path) => {\n const container = $(\"events\");\n container.querySelector(\".empty-state\")?.remove();\n\n const el = document.createElement(\"div\");\n el.className = \"event new\";\n const time = new Date().toLocaleTimeString(\"en-GB\", {\n hour12: false,\n });\n el.innerHTML =\n `<span class=\"event-time\">${time}</span>` +\n `<span class=\"event-seq\">#${seq}</span>` +\n `<span class=\"event-action ${action}\">${action.toUpperCase()}</span>` +\n `<span class=\"event-path\">${path}</span>`;\n container.prepend(el);\n setTimeout(() => el.classList.remove(\"new\"), 1500);\n while (container.children.length > MAX_EVENTS) {\n container.lastChild.remove();\n }\n };\n\n // -- WebSocket --\n const setWsStatus = (status) => {\n const el = $(\"ws-status\");\n el.className = `ws-status ${status}`;\n el.querySelector(\".ws-label\").textContent = status;\n };\n\n const connectFirehose = () => {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n const proto = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const ws = new WebSocket(\n `${proto}//${location.host}/xrpc/com.atproto.sync.subscribeRepos`,\n );\n ws.binaryType = \"arraybuffer\";\n\n ws.onopen = () => setWsStatus(\"connected\");\n ws.onmessage = (e) => {\n const commit = parseFirehoseMessage(e.data);\n if (!commit) return;\n for (const op of commit.ops) {\n addEvent(commit.seq, op.action, op.path);\n }\n };\n ws.onclose = () => {\n setWsStatus(\"disconnected\");\n reconnectTimer = setTimeout(connectFirehose, 3000);\n };\n ws.onerror = () => setWsStatus(\"error\");\n };\n\n // -- Init --\n const init = () => {\n applyConfig();\n fetchRepoData();\n fetchRelaySync();\n connectFirehose();\n\n setInterval(fetchRelaySync, 5000);\n setInterval(fetchRepoData, 30000);\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n }\n <\/script>\n </body>\n</html>\n";
|
|
4223
|
+
|
|
4224
|
+
//#endregion
|
|
4225
|
+
//#region src/dashboard.ts
|
|
4226
|
+
function renderDashboard(config) {
|
|
4227
|
+
const configScript = `<script>window.__CIRRUS_CONFIG=${JSON.stringify(config)};<\/script>`;
|
|
4228
|
+
return dashboard_default.replace("</head>", configScript + "\n</head>");
|
|
4229
|
+
}
|
|
4230
|
+
|
|
4216
4231
|
//#endregion
|
|
4217
4232
|
//#region package.json
|
|
4218
|
-
var version = "0.
|
|
4233
|
+
var version = "0.11.0";
|
|
4219
4234
|
|
|
4220
4235
|
//#endregion
|
|
4221
4236
|
//#region src/index.ts
|
|
@@ -4346,6 +4361,14 @@ body {
|
|
|
4346
4361
|
</html>`;
|
|
4347
4362
|
return c.html(html);
|
|
4348
4363
|
});
|
|
4364
|
+
app.get("/status", (c) => {
|
|
4365
|
+
return c.html(renderDashboard({
|
|
4366
|
+
hostname: c.env.PDS_HOSTNAME,
|
|
4367
|
+
handle: c.env.HANDLE,
|
|
4368
|
+
did: c.env.DID,
|
|
4369
|
+
version
|
|
4370
|
+
}));
|
|
4371
|
+
});
|
|
4349
4372
|
app.get("/xrpc/com.atproto.sync.getRepo", (c) => getRepo(c, getAccountDO(c.env)));
|
|
4350
4373
|
app.get("/xrpc/com.atproto.sync.getRepoStatus", (c) => getRepoStatus(c, getAccountDO(c.env)));
|
|
4351
4374
|
app.get("/xrpc/com.atproto.sync.getBlocks", (c) => getBlocks(c, getAccountDO(c.env)));
|