@atproto/pds 0.5.28 → 0.5.30
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 +55 -0
- package/dist/api/com/atproto/identity/resolveHandle.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/resolveHandle.js +1 -1
- package/dist/api/com/atproto/identity/resolveHandle.js.map +1 -1
- package/dist/auth-verifier.d.ts.map +1 -1
- package/dist/auth-verifier.js +12 -6
- package/dist/auth-verifier.js.map +1 -1
- package/dist/context.d.ts +2 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +6 -0
- package/dist/context.js.map +1 -1
- package/dist/lexicons/app/bsky/actor/status.defs.d.ts +5 -3
- package/dist/lexicons/app/bsky/actor/status.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/actor/status.defs.js +3 -0
- package/dist/lexicons/app/bsky/actor/status.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/embed/video.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/embed/video.defs.js +2 -4
- package/dist/lexicons/app/bsky/embed/video.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/feed/defs.defs.d.ts +84 -42
- package/dist/lexicons/app/bsky/feed/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/feed/defs.defs.js +52 -0
- package/dist/lexicons/app/bsky/feed/defs.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/graph/defs.defs.d.ts +15 -9
- package/dist/lexicons/app/bsky/graph/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/graph/defs.defs.js +9 -0
- package/dist/lexicons/app/bsky/graph/defs.defs.js.map +1 -1
- package/dist/lexicons/com/atproto/moderation/defs.defs.d.ts +35 -21
- package/dist/lexicons/com/atproto/moderation/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/moderation/defs.defs.js +21 -0
- package/dist/lexicons/com/atproto/moderation/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/moderation/defs.defs.d.ts +35 -21
- package/dist/lexicons/tools/ozone/moderation/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/moderation/defs.defs.js +21 -0
- package/dist/lexicons/tools/ozone/moderation/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/report/defs.defs.d.ts +200 -120
- package/dist/lexicons/tools/ozone/report/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/report/defs.defs.js +126 -0
- package/dist/lexicons/tools/ozone/report/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/team/defs.defs.d.ts +20 -12
- package/dist/lexicons/tools/ozone/team/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/team/defs.defs.js +12 -0
- package/dist/lexicons/tools/ozone/team/defs.defs.js.map +1 -1
- package/dist/scripts/index.d.ts +2 -2
- package/dist/scripts/index.d.ts.map +1 -1
- package/dist/scripts/index.js +2 -2
- package/dist/scripts/index.js.map +1 -1
- package/dist/telemetry.js +8 -186
- package/dist/telemetry.js.map +1 -1
- package/example.env +55 -0
- package/package.json +19 -28
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defs.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/tools/ozone/team/defs.defs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAChC,OAAO,KAAK,SAAS,MAAM,sCAAsC,CAAA;AAEjE,MAAM,KAAK,GAAG,uBAAuB,CAAA;AAIrC,OAAO,EAAE,KAAK,EAAE,CAAA;AAoBhB,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CACxC,KAAK,EACL,QAAQ;AACR,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,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7D,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IAC/B,aAAa,CAAC,CAAC,CAAC,GAAG,CACjB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAQ,CAC7C,CACF;IACD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACjC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAC/C;IACD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACjC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAC/C;IACD,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,EAOxB;CACL,CAAC,CACH,CAAA;AAED,OAAO,EAAE,MAAM,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"defs.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/tools/ozone/team/defs.defs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAChC,OAAO,KAAK,SAAS,MAAM,sCAAsC,CAAA;AAEjE,MAAM,KAAK,GAAG,uBAAuB,CAAA;AAIrC,OAAO,EAAE,KAAK,EAAE,CAAA;AAoBhB,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CACxC,KAAK,EACL,QAAQ;AACR,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,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7D,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IAC/B,aAAa,CAAC,CAAC,CAAC,GAAG,CACjB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAQ,CAC7C,CACF;IACD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACjC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAC/C;IACD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ;IACjC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAC/C;IACD,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,EAOxB;CACL,CAAC,CACH,CAAA;AAED,OAAO,EAAE,MAAM,EAAE,CAAA;AAEjB,oEAAoE;AACpE,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;AAE3D,OAAO,EAAE,SAAS,EAAE,CAAA;AAEpB,oEAAoE;AACpE,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,KAAK,CAAA;AAK/C,OAAO,EAAE,SAAS,EAAE,CAAA;AAEpB,gDAAgD;AAChD,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,eAAe,CAAC,CAAA;AAEnE,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,gDAAgD;AAChD,MAAM,aAAa,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,CAAA;AAKvD,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,yEAAyE;AACzE,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAA;AAE7D,OAAO,EAAE,UAAU,EAAE,CAAA;AAErB,yEAAyE;AACzE,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,KAAK,CAAA;AAKjD,OAAO,EAAE,UAAU,EAAE,CAAA;AAErB,0DAA0D;AAC1D,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,CAAA;AAEjE,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB,0DAA0D;AAC1D,MAAM,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,KAAK,CAAA;AAKrD,OAAO,EAAE,YAAY,EAAE,CAAA","sourcesContent":["/*\n * THIS FILE WAS GENERATED BY \"@atproto/lex\". DO NOT EDIT.\n */\n\nimport { l } from '@atproto/lex'\nimport * as ActorDefs from '../../../app/bsky/actor/defs.defs.js'\n\nconst $nsid = 'tools.ozone.team.defs'\n\ntype $nsid = typeof $nsid\n\nexport { $nsid }\n\ntype Member = {\n $type?: 'tools.ozone.team.defs#member'\n did: l.DidString\n disabled?: boolean\n profile?: ActorDefs.ProfileViewDetailed\n createdAt?: l.DatetimeString\n updatedAt?: l.DatetimeString\n lastUpdatedBy?: string\n role:\n | 'tools.ozone.team.defs#roleAdmin'\n | 'tools.ozone.team.defs#roleModerator'\n | 'tools.ozone.team.defs#roleTriage'\n | 'tools.ozone.team.defs#roleVerifier'\n | l.UnknownString\n}\n\nexport type { Member }\n\nconst member = /*#__PURE__*/ l.typedObject<Member>(\n $nsid,\n 'member',\n /*#__PURE__*/ l.object({\n did: /*#__PURE__*/ l.string({ format: 'did' }),\n disabled: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.boolean()),\n profile: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.ref<ActorDefs.ProfileViewDetailed>(\n (() => ActorDefs.profileViewDetailed) as any,\n ),\n ),\n createdAt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ format: 'datetime' }),\n ),\n updatedAt: /*#__PURE__*/ l.optional(\n /*#__PURE__*/ l.string({ format: 'datetime' }),\n ),\n lastUpdatedBy: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string()),\n role: /*#__PURE__*/ l.string<{\n knownValues: [\n 'tools.ozone.team.defs#roleAdmin',\n 'tools.ozone.team.defs#roleModerator',\n 'tools.ozone.team.defs#roleTriage',\n 'tools.ozone.team.defs#roleVerifier',\n ]\n }>(),\n }),\n)\n\nexport { member }\n\n/** Admin role. Highest level of access, can perform all actions. */\nconst roleAdmin = /*#__PURE__*/ l.token($nsid, 'roleAdmin')\n\nexport { roleAdmin }\n\n/** Admin role. Highest level of access, can perform all actions. */\nconst RoleAdmin = /*#__PURE__*/ roleAdmin.value\n\n/** Admin role. Highest level of access, can perform all actions. */\ntype RoleAdmin = typeof RoleAdmin\n\nexport { RoleAdmin }\n\n/** Moderator role. Can perform most actions. */\nconst roleModerator = /*#__PURE__*/ l.token($nsid, 'roleModerator')\n\nexport { roleModerator }\n\n/** Moderator role. Can perform most actions. */\nconst RoleModerator = /*#__PURE__*/ roleModerator.value\n\n/** Moderator role. Can perform most actions. */\ntype RoleModerator = typeof RoleModerator\n\nexport { RoleModerator }\n\n/** Triage role. Mostly intended for monitoring and escalating issues. */\nconst roleTriage = /*#__PURE__*/ l.token($nsid, 'roleTriage')\n\nexport { roleTriage }\n\n/** Triage role. Mostly intended for monitoring and escalating issues. */\nconst RoleTriage = /*#__PURE__*/ roleTriage.value\n\n/** Triage role. Mostly intended for monitoring and escalating issues. */\ntype RoleTriage = typeof RoleTriage\n\nexport { RoleTriage }\n\n/** Verifier role. Only allowed to issue verifications. */\nconst roleVerifier = /*#__PURE__*/ l.token($nsid, 'roleVerifier')\n\nexport { roleVerifier }\n\n/** Verifier role. Only allowed to issue verifications. */\nconst RoleVerifier = /*#__PURE__*/ roleVerifier.value\n\n/** Verifier role. Only allowed to issue verifications. */\ntype RoleVerifier = typeof RoleVerifier\n\nexport { RoleVerifier }\n"]}
|
package/dist/scripts/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { publishIdentity, publishIdentityFromFile } from './publish-identity.js';
|
|
2
|
-
import {
|
|
2
|
+
import { rebuildRepoScript } from './rebuild-repo.js';
|
|
3
3
|
import { rotateKeys, rotateKeysFromFile, rotateKeysRecovery } from './rotate-keys.js';
|
|
4
4
|
import { sequencerRecovery } from './sequencer-recovery/index.js';
|
|
5
5
|
import { repairRepos } from './sequencer-recovery/repair-repos.js';
|
|
6
6
|
export declare const scripts: {
|
|
7
|
-
'rebuild-repo': typeof
|
|
7
|
+
'rebuild-repo': typeof rebuildRepoScript;
|
|
8
8
|
'sequencer-recovery': typeof sequencerRecovery;
|
|
9
9
|
'recovery-repair-repos': typeof repairRepos;
|
|
10
10
|
'rotate-keys': typeof rotateKeys;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAChF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAA;AAElE,eAAO,MAAM,OAAO;;;;;;;;;CASmD,CAAA"}
|
package/dist/scripts/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { publishIdentity, publishIdentityFromFile } from './publish-identity.js';
|
|
2
|
-
import {
|
|
2
|
+
import { rebuildRepoScript } from './rebuild-repo.js';
|
|
3
3
|
import { rotateKeys, rotateKeysFromFile, rotateKeysRecovery, } from './rotate-keys.js';
|
|
4
4
|
import { sequencerRecovery } from './sequencer-recovery/index.js';
|
|
5
5
|
import { repairRepos } from './sequencer-recovery/repair-repos.js';
|
|
6
6
|
export const scripts = {
|
|
7
|
-
'rebuild-repo':
|
|
7
|
+
'rebuild-repo': rebuildRepoScript,
|
|
8
8
|
'sequencer-recovery': sequencerRecovery,
|
|
9
9
|
'recovery-repair-repos': repairRepos,
|
|
10
10
|
'rotate-keys': rotateKeys,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAChF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAA;AAElE,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,cAAc,EAAE,iBAAiB;IACjC,oBAAoB,EAAE,iBAAiB;IACvC,uBAAuB,EAAE,WAAW;IACpC,aAAa,EAAE,UAAU;IACzB,kBAAkB,EAAE,kBAAkB;IACtC,sBAAsB,EAAE,kBAAkB;IAC1C,kBAAkB,EAAE,eAAe;IACnC,uBAAuB,EAAE,uBAAuB;CACqB,CAAA","sourcesContent":["import { publishIdentity, publishIdentityFromFile } from './publish-identity.js'\nimport { rebuildRepoScript } from './rebuild-repo.js'\nimport {\n rotateKeys,\n rotateKeysFromFile,\n rotateKeysRecovery,\n} from './rotate-keys.js'\nimport { sequencerRecovery } from './sequencer-recovery/index.js'\nimport { repairRepos } from './sequencer-recovery/repair-repos.js'\n\nexport const scripts = {\n 'rebuild-repo': rebuildRepoScript,\n 'sequencer-recovery': sequencerRecovery,\n 'recovery-repair-repos': repairRepos,\n 'rotate-keys': rotateKeys,\n 'rotate-keys-file': rotateKeysFromFile,\n 'rotate-keys-recovery': rotateKeysRecovery,\n 'publish-identity': publishIdentity,\n 'publish-identity-file': publishIdentityFromFile,\n} satisfies Record<string, (ctx: any, args: string[]) => Promise<void>>\n"]}
|
package/dist/telemetry.js
CHANGED
|
@@ -1,193 +1,15 @@
|
|
|
1
|
-
import { register } from 'node:module';
|
|
2
|
-
import { diag } from '@opentelemetry/api';
|
|
3
|
-
import { getResourceDetectors } from '@opentelemetry/auto-instrumentations-node';
|
|
4
|
-
import { getBooleanFromEnv, getStringFromEnv, getStringListFromEnv, } from '@opentelemetry/core';
|
|
5
1
|
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';
|
|
6
|
-
import { ExpressInstrumentation, ExpressLayerType, } from '@opentelemetry/instrumentation-express';
|
|
7
|
-
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
8
2
|
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
|
9
|
-
import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';
|
|
10
|
-
import { RuntimeNodeInstrumentation } from '@opentelemetry/instrumentation-runtime-node';
|
|
11
|
-
import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
|
|
12
|
-
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
13
|
-
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
|
|
14
3
|
import { BetterSqlite3Instrumentation } from 'opentelemetry-plugin-better-sqlite3';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// rather than `registerInstrumentations` to get exporter setup from the
|
|
22
|
-
// conventional OTEL_* env vars for free.
|
|
23
|
-
// @NOTE Telemetry is opt-in via exporter endpoint rather than a non-standard
|
|
24
|
-
// flag: configuring an OTLP endpoint is what enables the SDK. OTEL_SDK_DISABLED
|
|
25
|
-
// remains a kill switch, per spec.
|
|
26
|
-
const otelDisabled = getBooleanFromEnv('OTEL_SDK_DISABLED');
|
|
27
|
-
const tracesConfigured = isSignalConfigured('TRACES');
|
|
28
|
-
const metricsConfigured = isSignalConfigured('METRICS');
|
|
29
|
-
const logsConfigured = isSignalConfigured('LOGS');
|
|
30
|
-
const otelConfigured = tracesConfigured || metricsConfigured || logsConfigured;
|
|
31
|
-
const otelEnabled = !otelDisabled && otelConfigured;
|
|
32
|
-
if (otelEnabled) {
|
|
33
|
-
try {
|
|
34
|
-
register('@opentelemetry/instrumentation/hook.mjs', import.meta.url);
|
|
35
|
-
const sdk = new NodeSDK({
|
|
36
|
-
// @NOTE Unlike sdk-node's default detectors, these include the
|
|
37
|
-
// "container" detector.
|
|
38
|
-
resourceDetectors: getResourceDetectors(),
|
|
39
|
-
instrumentations: getInstrumentations(),
|
|
40
|
-
// @NOTE The gate above enables the SDK as soon as *any* signal is
|
|
41
|
-
// configured, but NodeSDK then defaults every unspecified
|
|
42
|
-
// OTEL_{SIGNAL}_EXPORTER to "otlp" on http://localhost:4318 — shipping
|
|
43
|
-
// signals the operator never opted into. An *empty* pipeline opts a
|
|
44
|
-
// signal out: NodeSDK only reads OTEL_{SIGNAL}_EXPORTER when the pipeline
|
|
45
|
-
// option is `undefined`, and registers no provider when handed an empty
|
|
46
|
-
// one. Opted-in signals get `undefined` so they stay env-configured.
|
|
47
|
-
spanProcessors: tracesConfigured ? undefined : [],
|
|
48
|
-
metricReaders: metricsConfigured ? undefined : [],
|
|
49
|
-
logRecordProcessors: logsConfigured ? undefined : [],
|
|
50
|
-
});
|
|
51
|
-
sdk.start();
|
|
52
|
-
// @NOTE On SIGINT/SIGTERM the PDS releases its resources without calling
|
|
53
|
-
// process.exit(), so the event loop empties and Node emits "beforeExit"
|
|
54
|
-
// (https://nodejs.org/api/process.html#event-beforeexit). That's our window
|
|
55
|
-
// to flush pending telemetry.
|
|
56
|
-
process.once('beforeExit', () => {
|
|
57
|
-
sdk.shutdown().catch((err) => {
|
|
58
|
-
diag.error('Error terminating OpenTelemetry SDK', err);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
catch (err) {
|
|
63
|
-
diag.error('Error initializing OpenTelemetry SDK', err);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function getInstrumentations() {
|
|
67
|
-
return [
|
|
68
|
-
// @NOTE Not using getNodeAutoInstrumentations: it pulls in many
|
|
69
|
-
// instrumentations we don't need, with no easy way to filter them out.
|
|
70
|
-
new RuntimeNodeInstrumentation(),
|
|
71
|
-
new HttpInstrumentation({
|
|
72
|
-
// Derives "http.route" (and the span name) from the normalized XRPC path,
|
|
73
|
-
// for both incoming and outgoing requests.
|
|
74
|
-
//
|
|
75
|
-
// @NOTE Must be applyCustomAttributesOnSpan (fires on response finish),
|
|
76
|
-
// not requestHook (fires on request start). The express instrumentation
|
|
77
|
-
// overwrites the shared rpcMetadata.route on every layer it enters, which
|
|
78
|
-
// in this app resolves to "/" more often than not (multiple express apps
|
|
79
|
-
// and routers mounted at "/", plus catchall middlewares with no route
|
|
80
|
-
// layer). On finish, the http instrumentation copies rpcMetadata.route
|
|
81
|
-
// into "http.route" and renames the span from it, clobbering anything a
|
|
82
|
-
// requestHook set. This hook runs after that, so it wins.
|
|
83
|
-
applyCustomAttributesOnSpan: (span, request) => {
|
|
84
|
-
const { url, method, proxy } = 'path' in request
|
|
85
|
-
? // ClientRequest
|
|
86
|
-
{
|
|
87
|
-
url: request.path,
|
|
88
|
-
method: request.method,
|
|
89
|
-
proxy: request.getHeader('atproto-proxy'),
|
|
90
|
-
}
|
|
91
|
-
: // IncomingMessage
|
|
92
|
-
{
|
|
93
|
-
url: request.url ?? '/',
|
|
94
|
-
method: request.method ?? 'GET',
|
|
95
|
-
proxy: request.headers['atproto-proxy'],
|
|
96
|
-
};
|
|
97
|
-
const lxm = method === 'GET' || method === 'POST'
|
|
98
|
-
? extractNormalizedLxm(url)
|
|
99
|
-
: undefined;
|
|
100
|
-
// Normalized route for XRPC, raw path otherwise
|
|
101
|
-
const route = lxm ? `/xrpc/${lxm}` : url.split('?')[0];
|
|
102
|
-
span.setAttribute(ATTR_HTTP_ROUTE, route);
|
|
103
|
-
if (lxm) {
|
|
104
|
-
span.updateName(`${method} /xrpc/${lxm}`);
|
|
105
|
-
span.setAttribute(ATTR_XRPC_METHOD, lxm);
|
|
106
|
-
span.setAttribute(ATTR_XRPC_PROXIED, !!proxy);
|
|
107
|
-
if (proxy) {
|
|
108
|
-
span.setAttribute(ATTR_XRPC_PROXY, proxy);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
}),
|
|
113
|
-
new ExpressInstrumentation({
|
|
114
|
-
ignoreLayersType: [ExpressLayerType.MIDDLEWARE],
|
|
115
|
-
}),
|
|
116
|
-
new UndiciInstrumentation({
|
|
117
|
-
requestHook: (span, request) => {
|
|
118
|
-
const lxm = extractNormalizedLxm(request.path);
|
|
119
|
-
if (lxm) {
|
|
120
|
-
span.setAttribute(ATTR_XRPC_METHOD, lxm);
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
}),
|
|
4
|
+
import pkg from '@atproto/pds/package.json' with { type: 'json' };
|
|
5
|
+
import { setup } from '@atproto-labs/opentelemetry-node';
|
|
6
|
+
setup(() => ({
|
|
7
|
+
name: pkg.name,
|
|
8
|
+
version: pkg.version,
|
|
9
|
+
instrumentations: [
|
|
124
10
|
new AwsInstrumentation(),
|
|
125
11
|
new IORedisInstrumentation(),
|
|
126
12
|
new BetterSqlite3Instrumentation(),
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// and would forward all subsystems indiscriminately. Events we actually want
|
|
130
|
-
// in the OTEL stack go through the Logs API explicitly (see ./events.ts).
|
|
131
|
-
new PinoInstrumentation({ disableLogSending: true }),
|
|
132
|
-
];
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* A signal counts as configured when an OTLP endpoint applies to it
|
|
136
|
-
* (signal-specific or generic) and its exporter isn't set to "none".
|
|
137
|
-
*
|
|
138
|
-
* @NOTE OTEL_{SIGNAL}_EXPORTER is a comma-separated list, and the SDK handles
|
|
139
|
-
* "none" alongside other exporters inconsistently (metrics & logs disable the
|
|
140
|
-
* signal, traces falls back to "otlp"). Such a combination is a
|
|
141
|
-
* misconfiguration, so we treat any list containing "none" as disabling.
|
|
142
|
-
*/
|
|
143
|
-
function isSignalConfigured(signal) {
|
|
144
|
-
if (getStringListFromEnv(`OTEL_${signal}_EXPORTER`)?.includes('none')) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
return (!!getStringFromEnv(`OTEL_EXPORTER_OTLP_${signal}_ENDPOINT`) ||
|
|
148
|
-
!!getStringFromEnv('OTEL_EXPORTER_OTLP_ENDPOINT'));
|
|
149
|
-
}
|
|
150
|
-
// @NOTE Hand-rolled (rather than using URL/split) because this runs on every
|
|
151
|
-
// instrumented request. Should become obsolete once we have dedicated
|
|
152
|
-
// XrpcClient/XrpcServer instrumentations.
|
|
153
|
-
function extractNormalizedLxm(url) {
|
|
154
|
-
if (typeof url !== 'string') {
|
|
155
|
-
return undefined;
|
|
156
|
-
}
|
|
157
|
-
// 9 = "/xrpc/".length + shortest conceivable NSID ("a.b")
|
|
158
|
-
if (url.length < 9 || !url.startsWith('/xrpc/')) {
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
const firstMethodCharPos = 6; // "/xrpc/".length
|
|
162
|
-
// Characters that can never open an NSID (note "_" skips "/xrpc/_health")
|
|
163
|
-
const nextChar = url.charCodeAt(firstMethodCharPos);
|
|
164
|
-
if (nextChar === 0x2e /* '.' */ ||
|
|
165
|
-
nextChar === 0x2f /* '/' */ ||
|
|
166
|
-
nextChar === 0x3f /* '?' */ ||
|
|
167
|
-
nextChar === 0x5f /* '_' */) {
|
|
168
|
-
return undefined;
|
|
169
|
-
}
|
|
170
|
-
const queryIndex = url.indexOf('?', firstMethodCharPos + 1);
|
|
171
|
-
let lastMethodCharPos = queryIndex === -1 ? url.length - 1 : queryIndex - 1;
|
|
172
|
-
// Ignore the trailing slash, if there is one
|
|
173
|
-
if (url.charCodeAt(lastMethodCharPos) === 0x2f /* '/' */) {
|
|
174
|
-
lastMethodCharPos--;
|
|
175
|
-
}
|
|
176
|
-
if (lastMethodCharPos < 9) {
|
|
177
|
-
return undefined;
|
|
178
|
-
}
|
|
179
|
-
// Make sure there is no other slash in the path
|
|
180
|
-
if (url.lastIndexOf('/', lastMethodCharPos) !== firstMethodCharPos - 1) {
|
|
181
|
-
return undefined;
|
|
182
|
-
}
|
|
183
|
-
// Require at least one dot, and not as the last character
|
|
184
|
-
const lastDotPos = url.lastIndexOf('.', lastMethodCharPos);
|
|
185
|
-
if (lastDotPos === -1 || lastDotPos === lastMethodCharPos) {
|
|
186
|
-
return undefined;
|
|
187
|
-
}
|
|
188
|
-
// @NOTE Only the domain authority is case-insensitive; the trailing name
|
|
189
|
-
// segment is not, so it must be preserved as-is to avoid conflating
|
|
190
|
-
// distinct NSIDs.
|
|
191
|
-
return `${url.substring(firstMethodCharPos, lastDotPos).toLowerCase()}${url.substring(lastDotPos, lastMethodCharPos + 1)}`;
|
|
192
|
-
}
|
|
13
|
+
],
|
|
14
|
+
}));
|
|
193
15
|
//# sourceMappingURL=telemetry.js.map
|
package/dist/telemetry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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","sourcesContent":["import { register } from 'node:module'\nimport { diag } from '@opentelemetry/api'\nimport { getResourceDetectors } from '@opentelemetry/auto-instrumentations-node'\nimport {\n getBooleanFromEnv,\n getStringFromEnv,\n getStringListFromEnv,\n} from '@opentelemetry/core'\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\nimport { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk'\nimport {\n ExpressInstrumentation,\n ExpressLayerType,\n} from '@opentelemetry/instrumentation-express'\nimport { HttpInstrumentation } from '@opentelemetry/instrumentation-http'\nimport { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'\nimport { PinoInstrumentation } from '@opentelemetry/instrumentation-pino'\nimport { RuntimeNodeInstrumentation } from '@opentelemetry/instrumentation-runtime-node'\nimport { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici'\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'\nimport { BetterSqlite3Instrumentation } from 'opentelemetry-plugin-better-sqlite3'\n\nconst ATTR_XRPC_METHOD = 'xrpc.method'\nconst ATTR_XRPC_PROXIED = 'xrpc.proxied'\nconst ATTR_XRPC_PROXY = 'xrpc.proxy'\n\n// @NOTE Hand-rolled equivalent of \"@opentelemetry/auto-instrumentations-node\"'s\n// register script, because that one lacks better-sqlite3 instrumentation and\n// doesn't let us customize the HTTP span naming for XRPC. We use `NodeSDK`\n// rather than `registerInstrumentations` to get exporter setup from the\n// conventional OTEL_* env vars for free.\n\n// @NOTE Telemetry is opt-in via exporter endpoint rather than a non-standard\n// flag: configuring an OTLP endpoint is what enables the SDK. OTEL_SDK_DISABLED\n// remains a kill switch, per spec.\nconst otelDisabled = getBooleanFromEnv('OTEL_SDK_DISABLED')\nconst tracesConfigured = isSignalConfigured('TRACES')\nconst metricsConfigured = isSignalConfigured('METRICS')\nconst logsConfigured = isSignalConfigured('LOGS')\nconst otelConfigured = tracesConfigured || metricsConfigured || logsConfigured\nconst otelEnabled = !otelDisabled && otelConfigured\n\nif (otelEnabled) {\n try {\n register('@opentelemetry/instrumentation/hook.mjs', import.meta.url)\n\n const sdk = new NodeSDK({\n // @NOTE Unlike sdk-node's default detectors, these include the\n // \"container\" detector.\n resourceDetectors: getResourceDetectors(),\n instrumentations: getInstrumentations(),\n\n // @NOTE The gate above enables the SDK as soon as *any* signal is\n // configured, but NodeSDK then defaults every unspecified\n // OTEL_{SIGNAL}_EXPORTER to \"otlp\" on http://localhost:4318 — shipping\n // signals the operator never opted into. An *empty* pipeline opts a\n // signal out: NodeSDK only reads OTEL_{SIGNAL}_EXPORTER when the pipeline\n // option is `undefined`, and registers no provider when handed an empty\n // one. Opted-in signals get `undefined` so they stay env-configured.\n spanProcessors: tracesConfigured ? undefined : [],\n metricReaders: metricsConfigured ? undefined : [],\n logRecordProcessors: logsConfigured ? undefined : [],\n })\n\n sdk.start()\n\n // @NOTE On SIGINT/SIGTERM the PDS releases its resources without calling\n // process.exit(), so the event loop empties and Node emits \"beforeExit\"\n // (https://nodejs.org/api/process.html#event-beforeexit). That's our window\n // to flush pending telemetry.\n process.once('beforeExit', () => {\n sdk.shutdown().catch((err) => {\n diag.error('Error terminating OpenTelemetry SDK', err)\n })\n })\n } catch (err) {\n diag.error('Error initializing OpenTelemetry SDK', err)\n }\n}\n\nfunction getInstrumentations(): Instrumentation[] {\n return [\n // @NOTE Not using getNodeAutoInstrumentations: it pulls in many\n // instrumentations we don't need, with no easy way to filter them out.\n new RuntimeNodeInstrumentation(),\n new HttpInstrumentation({\n // Derives \"http.route\" (and the span name) from the normalized XRPC path,\n // for both incoming and outgoing requests.\n //\n // @NOTE Must be applyCustomAttributesOnSpan (fires on response finish),\n // not requestHook (fires on request start). The express instrumentation\n // overwrites the shared rpcMetadata.route on every layer it enters, which\n // in this app resolves to \"/\" more often than not (multiple express apps\n // and routers mounted at \"/\", plus catchall middlewares with no route\n // layer). On finish, the http instrumentation copies rpcMetadata.route\n // into \"http.route\" and renames the span from it, clobbering anything a\n // requestHook set. This hook runs after that, so it wins.\n applyCustomAttributesOnSpan: (span, request) => {\n const { url, method, proxy } =\n 'path' in request\n ? // ClientRequest\n {\n url: request.path,\n method: request.method,\n proxy: request.getHeader('atproto-proxy'),\n }\n : // IncomingMessage\n {\n url: request.url ?? '/',\n method: request.method ?? 'GET',\n proxy: request.headers['atproto-proxy'],\n }\n\n const lxm =\n method === 'GET' || method === 'POST'\n ? extractNormalizedLxm(url)\n : undefined\n\n // Normalized route for XRPC, raw path otherwise\n const route = lxm ? `/xrpc/${lxm}` : url.split('?')[0]\n span.setAttribute(ATTR_HTTP_ROUTE, route)\n\n if (lxm) {\n span.updateName(`${method} /xrpc/${lxm}`)\n span.setAttribute(ATTR_XRPC_METHOD, lxm)\n span.setAttribute(ATTR_XRPC_PROXIED, !!proxy)\n\n if (proxy) {\n span.setAttribute(ATTR_XRPC_PROXY, proxy)\n }\n }\n },\n }),\n new ExpressInstrumentation({\n ignoreLayersType: [ExpressLayerType.MIDDLEWARE],\n }),\n new UndiciInstrumentation({\n requestHook: (span, request) => {\n const lxm = extractNormalizedLxm(request.path)\n if (lxm) {\n span.setAttribute(ATTR_XRPC_METHOD, lxm)\n }\n },\n }),\n new AwsInstrumentation(),\n new IORedisInstrumentation(),\n new BetterSqlite3Instrumentation(),\n // @NOTE Keep log correlation (trace_id/span_id injected into pino records)\n // but disable log sending: it JSON.parse()s every record on the main thread\n // and would forward all subsystems indiscriminately. Events we actually want\n // in the OTEL stack go through the Logs API explicitly (see ./events.ts).\n new PinoInstrumentation({ disableLogSending: true }),\n ]\n}\n\n/**\n * A signal counts as configured when an OTLP endpoint applies to it\n * (signal-specific or generic) and its exporter isn't set to \"none\".\n *\n * @NOTE OTEL_{SIGNAL}_EXPORTER is a comma-separated list, and the SDK handles\n * \"none\" alongside other exporters inconsistently (metrics & logs disable the\n * signal, traces falls back to \"otlp\"). Such a combination is a\n * misconfiguration, so we treat any list containing \"none\" as disabling.\n */\nfunction isSignalConfigured(signal: 'TRACES' | 'METRICS' | 'LOGS'): boolean {\n if (getStringListFromEnv(`OTEL_${signal}_EXPORTER`)?.includes('none')) {\n return false\n }\n\n return (\n !!getStringFromEnv(`OTEL_EXPORTER_OTLP_${signal}_ENDPOINT`) ||\n !!getStringFromEnv('OTEL_EXPORTER_OTLP_ENDPOINT')\n )\n}\n\n// @NOTE Hand-rolled (rather than using URL/split) because this runs on every\n// instrumented request. Should become obsolete once we have dedicated\n// XrpcClient/XrpcServer instrumentations.\nfunction extractNormalizedLxm(url: unknown): string | undefined {\n if (typeof url !== 'string') {\n return undefined\n }\n\n // 9 = \"/xrpc/\".length + shortest conceivable NSID (\"a.b\")\n if (url.length < 9 || !url.startsWith('/xrpc/')) {\n return undefined\n }\n\n const firstMethodCharPos = 6 // \"/xrpc/\".length\n\n // Characters that can never open an NSID (note \"_\" skips \"/xrpc/_health\")\n const nextChar = url.charCodeAt(firstMethodCharPos)\n if (\n nextChar === 0x2e /* '.' */ ||\n nextChar === 0x2f /* '/' */ ||\n nextChar === 0x3f /* '?' */ ||\n nextChar === 0x5f /* '_' */\n ) {\n return undefined\n }\n\n const queryIndex = url.indexOf('?', firstMethodCharPos + 1)\n\n let lastMethodCharPos = queryIndex === -1 ? url.length - 1 : queryIndex - 1\n\n // Ignore the trailing slash, if there is one\n if (url.charCodeAt(lastMethodCharPos) === 0x2f /* '/' */) {\n lastMethodCharPos--\n }\n\n if (lastMethodCharPos < 9) {\n return undefined\n }\n\n // Make sure there is no other slash in the path\n if (url.lastIndexOf('/', lastMethodCharPos) !== firstMethodCharPos - 1) {\n return undefined\n }\n\n // Require at least one dot, and not as the last character\n const lastDotPos = url.lastIndexOf('.', lastMethodCharPos)\n if (lastDotPos === -1 || lastDotPos === lastMethodCharPos) {\n return undefined\n }\n\n // @NOTE Only the domain authority is case-insensitive; the trailing name\n // segment is not, so it must be preserved as-is to avoid conflating\n // distinct NSIDs.\n return `${url.substring(firstMethodCharPos, lastDotPos).toLowerCase()}${url.substring(lastDotPos, lastMethodCharPos + 1)}`\n}\n"]}
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAA;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAA;AAClF,OAAO,GAAG,MAAM,2BAA2B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAA;AAExD,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,gBAAgB,EAAE;QAChB,IAAI,kBAAkB,EAAE;QACxB,IAAI,sBAAsB,EAAE;QAC5B,IAAI,4BAA4B,EAAE;KACnC;CACF,CAAC,CAAC,CAAA","sourcesContent":["import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk'\nimport { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'\nimport { BetterSqlite3Instrumentation } from 'opentelemetry-plugin-better-sqlite3'\nimport pkg from '@atproto/pds/package.json' with { type: 'json' }\nimport { setup } from '@atproto-labs/opentelemetry-node'\n\nsetup(() => ({\n name: pkg.name,\n version: pkg.version,\n instrumentations: [\n new AwsInstrumentation(),\n new IORedisInstrumentation(),\n new BetterSqlite3Instrumentation(),\n ],\n}))\n"]}
|
package/example.env
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# See more env options in src/config/env.ts
|
|
2
|
+
# Hostname - the public domain that you intend to deploy your service at
|
|
3
|
+
PDS_HOSTNAME="example.com"
|
|
4
|
+
PDS_PORT="2583"
|
|
5
|
+
|
|
6
|
+
# Database config - use one or the other
|
|
7
|
+
PDS_DATA_DIRECTORY="data"
|
|
8
|
+
|
|
9
|
+
# Blobstore - filesystem location to store uploaded blobs
|
|
10
|
+
PDS_BLOBSTORE_DISK_LOCATION="blobs"
|
|
11
|
+
|
|
12
|
+
# Private keys - these are each expected to be 64 char hex strings (256 bit)
|
|
13
|
+
PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX="3ee68..."
|
|
14
|
+
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="e049f..."
|
|
15
|
+
|
|
16
|
+
# Secrets - update to secure high-entropy strings
|
|
17
|
+
PDS_DPOP_SECRET="32-random-bytes-hex-encoded"
|
|
18
|
+
PDS_JWT_SECRET="jwt-secret"
|
|
19
|
+
PDS_ADMIN_PASSWORD="admin-pass"
|
|
20
|
+
|
|
21
|
+
# Environment - example is for live network
|
|
22
|
+
PDS_DID_PLC_URL="https://plc.directory"
|
|
23
|
+
PDS_BSKY_APP_VIEW_URL="https://api.bsky.app"
|
|
24
|
+
PDS_BSKY_APP_VIEW_DID="did:web:api.bsky.app"
|
|
25
|
+
PDS_CRAWLERS="https://bsky.network"
|
|
26
|
+
|
|
27
|
+
# OAuth Provider - branding for the login / consent screens
|
|
28
|
+
PDS_SERVICE_NAME="John's self hosted PDS"
|
|
29
|
+
PDS_LOGO_URL=
|
|
30
|
+
PDS_PRIMARY_COLOR="#7507e3"
|
|
31
|
+
PDS_ERROR_COLOR=
|
|
32
|
+
PDS_HOME_URL=
|
|
33
|
+
PDS_TERMS_OF_SERVICE_URL=
|
|
34
|
+
PDS_PRIVACY_POLICY_URL=
|
|
35
|
+
PDS_SUPPORT_URL=
|
|
36
|
+
# Auth screen background images, shown behind the login card, by colour scheme
|
|
37
|
+
PDS_BACKGROUND_LIGHT_URL=
|
|
38
|
+
PDS_BACKGROUND_DARK_URL=
|
|
39
|
+
|
|
40
|
+
# Debugging
|
|
41
|
+
NODE_TLS_REJECT_UNAUTHORIZED=1
|
|
42
|
+
LOG_ENABLED=0
|
|
43
|
+
LOG_LEVEL=info
|
|
44
|
+
PDS_INVITE_REQUIRED=1
|
|
45
|
+
PDS_DISABLE_SSRF_PROTECTION=0
|
|
46
|
+
|
|
47
|
+
# Telemetry (optional) - requires running with `node --import @atproto/pds/telemetry`.
|
|
48
|
+
# See:
|
|
49
|
+
# - https://opentelemetry.io/docs/languages/sdk-configuration/general/
|
|
50
|
+
# - https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/
|
|
51
|
+
#OTEL_SERVICE_NAME="pds"
|
|
52
|
+
#OTEL_NODE_RESOURCE_DETECTORS="container,env,host"
|
|
53
|
+
#OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-collector.example.com"
|
|
54
|
+
#OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
|
|
55
|
+
#OTEL_SEMCONV_STABILITY_OPT_IN="http"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/pds",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.30",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Reference implementation of atproto Personal Data Server (PDS)",
|
|
6
6
|
"keywords": [
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"./dist",
|
|
18
|
+
"example.env",
|
|
18
19
|
"./README.md",
|
|
19
20
|
"./CHANGELOG.md"
|
|
20
21
|
],
|
|
@@ -36,21 +37,11 @@
|
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@did-plc/lib": "^0.0.4",
|
|
38
39
|
"@hapi/address": "^5.1.1",
|
|
40
|
+
"@noble/curves": "^1.7.0",
|
|
39
41
|
"@opentelemetry/api": "^1.9.1",
|
|
40
42
|
"@opentelemetry/api-logs": "^0.219.0",
|
|
41
|
-
"@opentelemetry/auto-instrumentations-node": "^0.77.0",
|
|
42
|
-
"@opentelemetry/core": "^2.9.0",
|
|
43
|
-
"@opentelemetry/instrumentation": "^0.219.0",
|
|
44
43
|
"@opentelemetry/instrumentation-aws-sdk": "^0.74.0",
|
|
45
|
-
"@opentelemetry/instrumentation-express": "^0.67.0",
|
|
46
|
-
"@opentelemetry/instrumentation-http": "^0.219.0",
|
|
47
44
|
"@opentelemetry/instrumentation-ioredis": "^0.67.0",
|
|
48
|
-
"@opentelemetry/instrumentation-pino": "^0.65.0",
|
|
49
|
-
"@opentelemetry/instrumentation-runtime-node": "^0.32.0",
|
|
50
|
-
"@opentelemetry/instrumentation-undici": "^0.29.0",
|
|
51
|
-
"@opentelemetry/resource-detector-container": "^0.8.10",
|
|
52
|
-
"@opentelemetry/sdk-node": "^0.219.0",
|
|
53
|
-
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
54
45
|
"better-sqlite3": "^12.0.0",
|
|
55
46
|
"compression": "^1.7.4",
|
|
56
47
|
"cors": "^2.8.5",
|
|
@@ -62,7 +53,6 @@
|
|
|
62
53
|
"http-terminator": "^3.2.0",
|
|
63
54
|
"ioredis": "^5.3.2",
|
|
64
55
|
"jose": "^5.0.1",
|
|
65
|
-
"key-encoder": "^2.0.3",
|
|
66
56
|
"kysely": "^0.29.2",
|
|
67
57
|
"nodemailer": "^6.8.0",
|
|
68
58
|
"nodemailer-html-to-text": "^3.2.0",
|
|
@@ -75,24 +65,25 @@
|
|
|
75
65
|
"undici": "^8.5.0",
|
|
76
66
|
"zod": "^3.23.8",
|
|
77
67
|
"@atproto-labs/fetch-node": "^0.3.7",
|
|
68
|
+
"@atproto-labs/opentelemetry-node": "^0.1.0",
|
|
69
|
+
"@atproto-labs/simple-store": "^0.5.1",
|
|
78
70
|
"@atproto-labs/simple-store-redis": "^0.1.6",
|
|
79
|
-
"@atproto-labs/
|
|
80
|
-
"@atproto/
|
|
71
|
+
"@atproto-labs/simple-store-memory": "^0.2.6",
|
|
72
|
+
"@atproto-labs/xrpc-utils": "^0.1.19",
|
|
73
|
+
"@atproto/aws": "^0.3.15",
|
|
74
|
+
"@atproto/common": "^0.8.1",
|
|
81
75
|
"@atproto/crypto": "^0.5.4",
|
|
82
|
-
"@atproto/common": "^0.8.0",
|
|
83
76
|
"@atproto/did": "^0.5.4",
|
|
84
|
-
"@atproto/
|
|
77
|
+
"@atproto/identity": "^0.5.10",
|
|
78
|
+
"@atproto/lex": "^0.3.7",
|
|
79
|
+
"@atproto/lex-data": "^0.1.7",
|
|
85
80
|
"@atproto/lex-cbor": "^0.1.6",
|
|
86
|
-
"@atproto-labs/simple-store": "^0.5.1",
|
|
87
|
-
"@atproto/identity": "^0.5.9",
|
|
88
|
-
"@atproto-labs/simple-store-memory": "^0.2.6",
|
|
89
|
-
"@atproto/repo": "^0.10.11",
|
|
90
81
|
"@atproto/lex-json": "^0.1.6",
|
|
91
|
-
"@atproto/
|
|
92
|
-
"@atproto/oauth-scopes": "^0.5.
|
|
93
|
-
"@atproto/
|
|
94
|
-
"@atproto/
|
|
95
|
-
"@atproto/
|
|
82
|
+
"@atproto/oauth-provider": "^0.22.4",
|
|
83
|
+
"@atproto/oauth-scopes": "^0.5.10",
|
|
84
|
+
"@atproto/xrpc-server": "^0.12.6",
|
|
85
|
+
"@atproto/syntax": "^0.7.5",
|
|
86
|
+
"@atproto/repo": "^0.10.12"
|
|
96
87
|
},
|
|
97
88
|
"devDependencies": {
|
|
98
89
|
"@did-plc/server": "^0.0.1",
|
|
@@ -107,8 +98,8 @@
|
|
|
107
98
|
"jest": "^30.0.0",
|
|
108
99
|
"puppeteer": "^23.11.1",
|
|
109
100
|
"ws": "^8.12.0",
|
|
110
|
-
"@atproto/api": "^0.20.
|
|
111
|
-
"@atproto/lex-document": "^0.1.
|
|
101
|
+
"@atproto/api": "^0.20.42",
|
|
102
|
+
"@atproto/lex-document": "^0.1.10",
|
|
112
103
|
"@atproto/oauth-client-browser-example": "^0.1.7"
|
|
113
104
|
},
|
|
114
105
|
"scripts": {
|