@infinitetoken/lumber-kit 0.6.0 → 0.7.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/README.md +21 -4
- package/contract/README.md +21 -0
- package/contract/schema.json +2273 -0
- package/contract/vectors.json +180 -0
- package/dist/index.d.mts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.js +55 -7
- package/dist/index.mjs +49 -7
- package/package.json +8 -3
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Known answers every Lumber plugin is tested against, whatever its language. Lumber-Kit's own tests check each one against its TypeScript (buildLogPayload, splitApiKey, logDeliveryOutcome, logRetryDelayMs, the constants) and Node's crypto, so these can't drift from the kit. An absent key means absent: JSON has no undefined, and null data values are left out like missing ones.",
|
|
3
|
+
"constants": {
|
|
4
|
+
"defaultEndpoint": "https://api.lumber.infinitetoken.com",
|
|
5
|
+
"ingestPath": "/logs",
|
|
6
|
+
"keyVersion": 1,
|
|
7
|
+
"keyBytes": 32,
|
|
8
|
+
"nonceBytes": 12,
|
|
9
|
+
"tagBytes": 16,
|
|
10
|
+
"levels": { "debug": 0, "info": 1, "warn": 2, "error": 3, "fatal": 4 },
|
|
11
|
+
"delivery": { "maxAttempts": 5, "baseDelayMs": 1000, "maxDelayMs": 30000, "pauseMs": 3600000 }
|
|
12
|
+
},
|
|
13
|
+
"apiKeys": [
|
|
14
|
+
{
|
|
15
|
+
"name": "token and encryption key",
|
|
16
|
+
"apiKey": "3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60.AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
|
|
17
|
+
"token": "3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60",
|
|
18
|
+
"encryptionKey": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "surrounding whitespace, as pasted from a terminal",
|
|
22
|
+
"apiKey": " 3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60.AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=\n",
|
|
23
|
+
"token": "3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60",
|
|
24
|
+
"encryptionKey": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "a bare token carries no encryption key",
|
|
28
|
+
"apiKey": "3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60",
|
|
29
|
+
"token": "3f9c0e7a1b2d4c6e8f0a1b2c3d4e5f60",
|
|
30
|
+
"encryptionKey": null
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "empty",
|
|
34
|
+
"apiKey": "",
|
|
35
|
+
"token": "",
|
|
36
|
+
"encryptionKey": null
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"encryption": [
|
|
40
|
+
{
|
|
41
|
+
"name": "ascii",
|
|
42
|
+
"key": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
|
|
43
|
+
"nonce": "oKGio6Slpqeoqaqr",
|
|
44
|
+
"plaintext": "{\"level\":1,\"message\":\"Server started\",\"metadata\":{\"port\":3000}}",
|
|
45
|
+
"payload": "GJU0Lu4J1IGhob9mA32TqJ06EEgzrm6dWFSr8Wofs60RyzwyqJURCe54Q/Rf2AFgoAIim40OcVA66GWsaA7i231gZDgNom5ce207bpQN+A=="
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "non-ascii, encoded as utf-8",
|
|
49
|
+
"key": "QkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkI=",
|
|
50
|
+
"nonce": "BwcHBwcHBwcHBwcH",
|
|
51
|
+
"plaintext": "{\"level\":3,\"message\":\"Paiement échoué ☕ 🚨\",\"context\":{\"pid\":4242,\"hostname\":\"web-1\"},\"metadata\":{\"user\":\"Zoë\"}}",
|
|
52
|
+
"payload": "bG1l/6IGl9vfE0wA1rhuEAPAMcnDlB7ZGWfAErA+VQ+UPWofx/cYJAkRUjZ0WTi3hotyvwFw3G2lbtCoKgD6/aRDnUpDt4kk+HF3FGk6VaEEt5fqiu28C5u9EifuYjd4Qh8KcSMdO9eeVWLqsg2eIpbV9qQQOtD1fMXktGfQmxTjmMtMZuKm"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "empty message",
|
|
56
|
+
"key": "7qi7Ixae6epI48zxshkBw43xktBTaE/pwLxUoUhZ6e0=",
|
|
57
|
+
"nonce": "eDd7UldXtJRCf4kB",
|
|
58
|
+
"plaintext": "{\"level\":0,\"message\":\"\"}",
|
|
59
|
+
"payload": "M2E8vR0ITv6RfAwC3fDiMVIfWt3N9U6DEveRBpqxc/K49Py/HVQpMw=="
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"payloads": [
|
|
63
|
+
{
|
|
64
|
+
"name": "message alone",
|
|
65
|
+
"level": 1,
|
|
66
|
+
"message": "Server started",
|
|
67
|
+
"payload": { "level": 1, "message": "Server started" }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "request and trace ids",
|
|
71
|
+
"level": 3,
|
|
72
|
+
"message": "Payment failed",
|
|
73
|
+
"data": { "requestId": "req-123", "traceId": "trace-abc" },
|
|
74
|
+
"payload": { "level": 3, "message": "Payment failed", "requestId": "req-123", "traceId": "trace-abc" }
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "other keys become metadata",
|
|
78
|
+
"level": 1,
|
|
79
|
+
"message": "User action",
|
|
80
|
+
"data": { "userId": "123", "action": "login", "order": { "id": 7, "total": 12.5, "items": ["a", "b"] } },
|
|
81
|
+
"payload": { "level": 1, "message": "User action", "metadata": { "userId": "123", "action": "login", "order": { "id": 7, "total": 12.5, "items": ["a", "b"] } } }
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "explicit metadata wins over other keys",
|
|
85
|
+
"level": 2,
|
|
86
|
+
"message": "Rate limit approaching",
|
|
87
|
+
"data": { "version": 1, "region": "us", "metadata": { "version": 2, "build": "b7" } },
|
|
88
|
+
"payload": { "level": 2, "message": "Rate limit approaching", "metadata": { "version": 2, "region": "us", "build": "b7" } }
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "metadata alone",
|
|
92
|
+
"level": 1,
|
|
93
|
+
"message": "Cache warmed",
|
|
94
|
+
"data": { "metadata": { "entries": 512 } },
|
|
95
|
+
"payload": { "level": 1, "message": "Cache warmed", "metadata": { "entries": 512 } }
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "automatic context alone",
|
|
99
|
+
"level": 0,
|
|
100
|
+
"message": "Cache miss",
|
|
101
|
+
"autoContext": { "pid": 4242, "hostname": "web-1" },
|
|
102
|
+
"payload": { "level": 0, "message": "Cache miss", "context": { "pid": 4242, "hostname": "web-1" } }
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "the call's context over the automatic context",
|
|
106
|
+
"level": 1,
|
|
107
|
+
"message": "Job done",
|
|
108
|
+
"autoContext": { "pid": 4242, "hostname": "web-1", "env": "production" },
|
|
109
|
+
"data": { "context": { "hostname": "worker-3", "code": "jobs/billing.py", "line": 42 } },
|
|
110
|
+
"payload": { "level": 1, "message": "Job done", "context": { "pid": 4242, "hostname": "worker-3", "env": "production", "code": "jobs/billing.py", "line": 42 } }
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "context with no automatic context",
|
|
114
|
+
"level": 1,
|
|
115
|
+
"message": "Job done",
|
|
116
|
+
"autoContext": {},
|
|
117
|
+
"data": { "context": { "code": "app.ts" } },
|
|
118
|
+
"payload": { "level": 1, "message": "Job done", "context": { "code": "app.ts" } }
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "a context that isn't an object is a metadata key",
|
|
122
|
+
"level": 1,
|
|
123
|
+
"message": "Invoice sent",
|
|
124
|
+
"data": { "context": "billing" },
|
|
125
|
+
"payload": { "level": 1, "message": "Invoice sent", "metadata": { "context": "billing" } }
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "metadata that isn't an object is a metadata key",
|
|
129
|
+
"level": 1,
|
|
130
|
+
"message": "Batch",
|
|
131
|
+
"data": { "metadata": [1, 2, 3] },
|
|
132
|
+
"payload": { "level": 1, "message": "Batch", "metadata": { "metadata": [1, 2, 3] } }
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "a null context and metadata are left out",
|
|
136
|
+
"level": 1,
|
|
137
|
+
"message": "Nothing extra",
|
|
138
|
+
"data": { "context": null, "metadata": null },
|
|
139
|
+
"payload": { "level": 1, "message": "Nothing extra" }
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "a level key in the data is metadata, never the log's level",
|
|
143
|
+
"level": 3,
|
|
144
|
+
"message": "Disk nearly full",
|
|
145
|
+
"data": { "level": "high", "message": "ignored" },
|
|
146
|
+
"payload": { "level": 3, "message": "Disk nearly full", "metadata": { "level": "high", "message": "ignored" } }
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"name": "everything",
|
|
150
|
+
"level": 4,
|
|
151
|
+
"message": "DB connection lost ☠",
|
|
152
|
+
"autoContext": { "pid": 1, "hostname": "db-proxy" },
|
|
153
|
+
"data": { "requestId": "r1", "traceId": "t1", "context": { "method": "connect" }, "metadata": { "retries": 3 }, "host": "10.0.0.5" },
|
|
154
|
+
"payload": { "level": 4, "message": "DB connection lost ☠", "requestId": "r1", "traceId": "t1", "context": { "pid": 1, "hostname": "db-proxy", "method": "connect" }, "metadata": { "host": "10.0.0.5", "retries": 3 } }
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"deliveryOutcomes": [
|
|
158
|
+
{ "status": 200, "outcome": "sent" },
|
|
159
|
+
{ "status": 201, "outcome": "sent" },
|
|
160
|
+
{ "status": 301, "outcome": "retry" },
|
|
161
|
+
{ "status": 400, "outcome": "drop" },
|
|
162
|
+
{ "status": 401, "outcome": "drop" },
|
|
163
|
+
{ "status": 403, "outcome": "drop" },
|
|
164
|
+
{ "status": 404, "outcome": "drop" },
|
|
165
|
+
{ "status": 413, "outcome": "drop" },
|
|
166
|
+
{ "status": 429, "outcome": "pause" },
|
|
167
|
+
{ "status": 500, "outcome": "retry" },
|
|
168
|
+
{ "status": 502, "outcome": "retry" },
|
|
169
|
+
{ "status": 503, "outcome": "retry" },
|
|
170
|
+
{ "status": null, "outcome": "retry" }
|
|
171
|
+
],
|
|
172
|
+
"retryDelaysMs": [
|
|
173
|
+
{ "failedAttempts": 1, "delayMs": 1000 },
|
|
174
|
+
{ "failedAttempts": 2, "delayMs": 2000 },
|
|
175
|
+
{ "failedAttempts": 3, "delayMs": 4000 },
|
|
176
|
+
{ "failedAttempts": 4, "delayMs": 8000 },
|
|
177
|
+
{ "failedAttempts": 5, "delayMs": 16000 },
|
|
178
|
+
{ "failedAttempts": 6, "delayMs": 30000 }
|
|
179
|
+
]
|
|
180
|
+
}
|
package/dist/index.d.mts
CHANGED
|
@@ -15,6 +15,23 @@ declare const APP_COLORS: readonly ["#EF4444", "#F97316", "#F59E0B", "#84CC16",
|
|
|
15
15
|
declare const apiErrorCodes: readonly ["APP_LIMIT", "SEAT_LIMIT", "GUEST_LIMIT", "ALREADY_MEMBER", "ALREADY_READS", "ALREADY_INVITED", "HAS_ACCOUNT"];
|
|
16
16
|
type ApiErrorCode = (typeof apiErrorCodes)[number];
|
|
17
17
|
|
|
18
|
+
/** The Lumber API a plugin sends logs to unless it's given another endpoint. */
|
|
19
|
+
declare const DEFAULT_API_ENDPOINT = "https://api.lumber.infinitetoken.com";
|
|
20
|
+
/** LogEncrypted's keyVersion. Every app has one encryption key, so it's 1 until keys can be rotated. */
|
|
21
|
+
declare const LOG_KEY_VERSION = 1;
|
|
22
|
+
/**
|
|
23
|
+
* How a plugin delivers logs: one POST /logs per log, in the order they were logged. A network error or a 5xx is a
|
|
24
|
+
* failed attempt, tried again after `baseDelayMs`, doubling up to `maxDelayMs`, and dropped after `maxAttempts`. Any
|
|
25
|
+
* other 4xx is dropped at once, since sending it again won't help. A 429 (the team's logs for the month are used up)
|
|
26
|
+
* drops what's queued and every new log until its Retry-After, or for `pauseMs` when it has none.
|
|
27
|
+
*/
|
|
28
|
+
declare const logDelivery: {
|
|
29
|
+
readonly maxAttempts: 5;
|
|
30
|
+
readonly baseDelayMs: 1000;
|
|
31
|
+
readonly maxDelayMs: 30000;
|
|
32
|
+
readonly pauseMs: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
18
35
|
/** Log severity level. Numeric values match the existing Lumber-API level field. */
|
|
19
36
|
declare const enum LogLevel {
|
|
20
37
|
Debug = 0,
|
|
@@ -423,7 +440,7 @@ interface LogEncrypted {
|
|
|
423
440
|
keyVersion: number;
|
|
424
441
|
}
|
|
425
442
|
/**
|
|
426
|
-
* Plaintext shape of log content
|
|
443
|
+
* Plaintext shape of log content: a plugin encrypts it into LogEncrypted, and the server never sees it.
|
|
427
444
|
*/
|
|
428
445
|
interface LogPayload {
|
|
429
446
|
level: LogLevel;
|
|
@@ -433,6 +450,25 @@ interface LogPayload {
|
|
|
433
450
|
context?: LogContext;
|
|
434
451
|
metadata?: Record<string, unknown>;
|
|
435
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* What a plugin's log call takes beside its message (Lumber-Node's second argument). requestId and traceId become the
|
|
455
|
+
* payload's own fields, context is merged over the plugin's automatic context, and any other key goes into metadata,
|
|
456
|
+
* where an explicit metadata key wins. A context or metadata that isn't an object is kept as an ordinary metadata key.
|
|
457
|
+
*/
|
|
458
|
+
interface LogData {
|
|
459
|
+
requestId?: string;
|
|
460
|
+
traceId?: string;
|
|
461
|
+
context?: LogContext;
|
|
462
|
+
metadata?: Record<string, unknown>;
|
|
463
|
+
[key: string]: unknown;
|
|
464
|
+
}
|
|
465
|
+
/** POST /logs' body. The level stays plaintext for filtering and pushes; everything else is in `encrypted`. */
|
|
466
|
+
interface LogIngestBody {
|
|
467
|
+
level: LogLevel;
|
|
468
|
+
encrypted: LogEncrypted;
|
|
469
|
+
}
|
|
470
|
+
/** What a plugin does with a log after POST /logs answers (see logDelivery). */
|
|
471
|
+
type LogDeliveryOutcome = 'sent' | 'retry' | 'drop' | 'pause';
|
|
436
472
|
/**
|
|
437
473
|
* API response shape for a stored log.
|
|
438
474
|
* level is plaintext for server-side notification routing; all content is inside encrypted.
|
|
@@ -674,6 +710,22 @@ interface UserRecord {
|
|
|
674
710
|
notesReadAt?: Record<string, string>;
|
|
675
711
|
}
|
|
676
712
|
|
|
713
|
+
/**
|
|
714
|
+
* The plaintext a plugin encrypts for one log call: its level and message, requestId and traceId when given, the
|
|
715
|
+
* plugin's automatic context (pid, hostname and the like) with the call's context over it, and the call's other keys
|
|
716
|
+
* as metadata with its explicit metadata over them. A context or metadata that isn't an object (a string, an array) is
|
|
717
|
+
* kept as an ordinary metadata key, since spreading it would turn `{ context: 'billing' }` into `{ 0: 'b', ... }`, and
|
|
718
|
+
* a null one is left out. Every plugin builds the same payload: contract/vectors.json pins it for the other languages.
|
|
719
|
+
*/
|
|
720
|
+
declare const buildLogPayload: (level: LogLevel, message: string, data?: LogData, autoContext?: Record<string, unknown>) => LogPayload;
|
|
721
|
+
/**
|
|
722
|
+
* What to do with a log once POST /logs answers with `status`, or null for no answer (a network error): sent on a 2xx,
|
|
723
|
+
* pause on a 429, drop on any other 4xx, and retry on anything else.
|
|
724
|
+
*/
|
|
725
|
+
declare const logDeliveryOutcome: (status: number | null) => LogDeliveryOutcome;
|
|
726
|
+
/** How long to wait before trying a log again after its `failedAttempts`th failure: 1s, 2s, 4s and so on, up to 30s. */
|
|
727
|
+
declare const logRetryDelayMs: (failedAttempts: number) => number;
|
|
728
|
+
|
|
677
729
|
declare const isValidAppearance: (value: unknown) => value is Appearance;
|
|
678
730
|
/** Accepts 3- and 6-digit hex color strings (#rgb, #rrggbb). */
|
|
679
731
|
declare const isValidColor: (value: string) => boolean;
|
|
@@ -714,4 +766,4 @@ declare const apiErrorCodeOf: (body: unknown) => ApiErrorCode | null;
|
|
|
714
766
|
/** A push notification's data as PushData, or null for data no Lumber push sends. */
|
|
715
767
|
declare const parsePushData: (data: unknown) => PushData | null;
|
|
716
768
|
|
|
717
|
-
export { APP_COLORS, type ApiErrorBody, type ApiErrorCode, type ApiKeyRecord, type ApiResponse, type AppCreatedRecord, type AppEncryptedKey, type AppKeyUpsertBody, type AppPermission, type AppPersonRecord, type AppRecord, type AppTeamAccess, type Appearance, type AppsQuery, type ClaimantKeyCheck, type ClientToServerEvents, DEFAULT_ACCENT, DEFAULT_PUSH_THRESHOLD, type DeviceLinkApproveBody, type DeviceLinkCreateBody, type DeviceLinkCreatedRecord, type DeviceLinkPlatform, type DeviceLinkRecord, type DeviceLinkStatus, type FlagRecord, type FlagsQuery, type GuestRecord, type HolderKeyCheck, type InvitationRecord, type KeyCheckResult, type KeyHolder, type KeyPin, type LogContext, type LogEncrypted, LogLevel, type LogLevelName, type LogPayload, type LogRecord, type LogTimeseriesQuery, type LogsQuery, type NoteEncrypted, type NoteRecord, type NotesQuery, type NotificationPreference, type NotificationPreferences, PUSH_OFF, type PendingAppKey, type PendingDeviceLink, type PushData, type PushThreshold, type PushToken, type PushType, type ResponseMetadata, type ServerToClientEvents, type SocketAppPayload, SubscriptionLevel, type SubscriptionLevelName, type SubscriptionLimits, type SubscriptionPlan, type SubscriptionPlanRecord, type TeamMemberRecord, type TeamRecord, type TeamsQuery, type TimeseriesBucket, type TimeseriesResponse, type UserRecord, apiErrorCodeOf, apiErrorCodes, isApiErrorCode, isValidAppearance, isValidColor, isValidDeviceLinkStatus, isValidImageUrl, isValidLogLevel, isValidSubscriptionLevel, isValidTeamMemberRole, joinApiKey, logLevelColors, logLevelNameToLevel, logLevelToName, logLevels, nameColor, normalizePushThreshold, parsePushData, personColor, resolveAppColor, splitApiKey, subscriptionLevelToName, subscriptionLevels, subscriptionLimits, subscriptionPlans };
|
|
769
|
+
export { APP_COLORS, type ApiErrorBody, type ApiErrorCode, type ApiKeyRecord, type ApiResponse, type AppCreatedRecord, type AppEncryptedKey, type AppKeyUpsertBody, type AppPermission, type AppPersonRecord, type AppRecord, type AppTeamAccess, type Appearance, type AppsQuery, type ClaimantKeyCheck, type ClientToServerEvents, DEFAULT_ACCENT, DEFAULT_API_ENDPOINT, DEFAULT_PUSH_THRESHOLD, type DeviceLinkApproveBody, type DeviceLinkCreateBody, type DeviceLinkCreatedRecord, type DeviceLinkPlatform, type DeviceLinkRecord, type DeviceLinkStatus, type FlagRecord, type FlagsQuery, type GuestRecord, type HolderKeyCheck, type InvitationRecord, type KeyCheckResult, type KeyHolder, type KeyPin, LOG_KEY_VERSION, type LogContext, type LogData, type LogDeliveryOutcome, type LogEncrypted, type LogIngestBody, LogLevel, type LogLevelName, type LogPayload, type LogRecord, type LogTimeseriesQuery, type LogsQuery, type NoteEncrypted, type NoteRecord, type NotesQuery, type NotificationPreference, type NotificationPreferences, PUSH_OFF, type PendingAppKey, type PendingDeviceLink, type PushData, type PushThreshold, type PushToken, type PushType, type ResponseMetadata, type ServerToClientEvents, type SocketAppPayload, SubscriptionLevel, type SubscriptionLevelName, type SubscriptionLimits, type SubscriptionPlan, type SubscriptionPlanRecord, type TeamMemberRecord, type TeamRecord, type TeamsQuery, type TimeseriesBucket, type TimeseriesResponse, type UserRecord, apiErrorCodeOf, apiErrorCodes, buildLogPayload, isApiErrorCode, isValidAppearance, isValidColor, isValidDeviceLinkStatus, isValidImageUrl, isValidLogLevel, isValidSubscriptionLevel, isValidTeamMemberRole, joinApiKey, logDelivery, logDeliveryOutcome, logLevelColors, logLevelNameToLevel, logLevelToName, logLevels, logRetryDelayMs, nameColor, normalizePushThreshold, parsePushData, personColor, resolveAppColor, splitApiKey, subscriptionLevelToName, subscriptionLevels, subscriptionLimits, subscriptionPlans };
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,23 @@ declare const APP_COLORS: readonly ["#EF4444", "#F97316", "#F59E0B", "#84CC16",
|
|
|
15
15
|
declare const apiErrorCodes: readonly ["APP_LIMIT", "SEAT_LIMIT", "GUEST_LIMIT", "ALREADY_MEMBER", "ALREADY_READS", "ALREADY_INVITED", "HAS_ACCOUNT"];
|
|
16
16
|
type ApiErrorCode = (typeof apiErrorCodes)[number];
|
|
17
17
|
|
|
18
|
+
/** The Lumber API a plugin sends logs to unless it's given another endpoint. */
|
|
19
|
+
declare const DEFAULT_API_ENDPOINT = "https://api.lumber.infinitetoken.com";
|
|
20
|
+
/** LogEncrypted's keyVersion. Every app has one encryption key, so it's 1 until keys can be rotated. */
|
|
21
|
+
declare const LOG_KEY_VERSION = 1;
|
|
22
|
+
/**
|
|
23
|
+
* How a plugin delivers logs: one POST /logs per log, in the order they were logged. A network error or a 5xx is a
|
|
24
|
+
* failed attempt, tried again after `baseDelayMs`, doubling up to `maxDelayMs`, and dropped after `maxAttempts`. Any
|
|
25
|
+
* other 4xx is dropped at once, since sending it again won't help. A 429 (the team's logs for the month are used up)
|
|
26
|
+
* drops what's queued and every new log until its Retry-After, or for `pauseMs` when it has none.
|
|
27
|
+
*/
|
|
28
|
+
declare const logDelivery: {
|
|
29
|
+
readonly maxAttempts: 5;
|
|
30
|
+
readonly baseDelayMs: 1000;
|
|
31
|
+
readonly maxDelayMs: 30000;
|
|
32
|
+
readonly pauseMs: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
18
35
|
/** Log severity level. Numeric values match the existing Lumber-API level field. */
|
|
19
36
|
declare const enum LogLevel {
|
|
20
37
|
Debug = 0,
|
|
@@ -423,7 +440,7 @@ interface LogEncrypted {
|
|
|
423
440
|
keyVersion: number;
|
|
424
441
|
}
|
|
425
442
|
/**
|
|
426
|
-
* Plaintext shape of log content
|
|
443
|
+
* Plaintext shape of log content: a plugin encrypts it into LogEncrypted, and the server never sees it.
|
|
427
444
|
*/
|
|
428
445
|
interface LogPayload {
|
|
429
446
|
level: LogLevel;
|
|
@@ -433,6 +450,25 @@ interface LogPayload {
|
|
|
433
450
|
context?: LogContext;
|
|
434
451
|
metadata?: Record<string, unknown>;
|
|
435
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* What a plugin's log call takes beside its message (Lumber-Node's second argument). requestId and traceId become the
|
|
455
|
+
* payload's own fields, context is merged over the plugin's automatic context, and any other key goes into metadata,
|
|
456
|
+
* where an explicit metadata key wins. A context or metadata that isn't an object is kept as an ordinary metadata key.
|
|
457
|
+
*/
|
|
458
|
+
interface LogData {
|
|
459
|
+
requestId?: string;
|
|
460
|
+
traceId?: string;
|
|
461
|
+
context?: LogContext;
|
|
462
|
+
metadata?: Record<string, unknown>;
|
|
463
|
+
[key: string]: unknown;
|
|
464
|
+
}
|
|
465
|
+
/** POST /logs' body. The level stays plaintext for filtering and pushes; everything else is in `encrypted`. */
|
|
466
|
+
interface LogIngestBody {
|
|
467
|
+
level: LogLevel;
|
|
468
|
+
encrypted: LogEncrypted;
|
|
469
|
+
}
|
|
470
|
+
/** What a plugin does with a log after POST /logs answers (see logDelivery). */
|
|
471
|
+
type LogDeliveryOutcome = 'sent' | 'retry' | 'drop' | 'pause';
|
|
436
472
|
/**
|
|
437
473
|
* API response shape for a stored log.
|
|
438
474
|
* level is plaintext for server-side notification routing; all content is inside encrypted.
|
|
@@ -674,6 +710,22 @@ interface UserRecord {
|
|
|
674
710
|
notesReadAt?: Record<string, string>;
|
|
675
711
|
}
|
|
676
712
|
|
|
713
|
+
/**
|
|
714
|
+
* The plaintext a plugin encrypts for one log call: its level and message, requestId and traceId when given, the
|
|
715
|
+
* plugin's automatic context (pid, hostname and the like) with the call's context over it, and the call's other keys
|
|
716
|
+
* as metadata with its explicit metadata over them. A context or metadata that isn't an object (a string, an array) is
|
|
717
|
+
* kept as an ordinary metadata key, since spreading it would turn `{ context: 'billing' }` into `{ 0: 'b', ... }`, and
|
|
718
|
+
* a null one is left out. Every plugin builds the same payload: contract/vectors.json pins it for the other languages.
|
|
719
|
+
*/
|
|
720
|
+
declare const buildLogPayload: (level: LogLevel, message: string, data?: LogData, autoContext?: Record<string, unknown>) => LogPayload;
|
|
721
|
+
/**
|
|
722
|
+
* What to do with a log once POST /logs answers with `status`, or null for no answer (a network error): sent on a 2xx,
|
|
723
|
+
* pause on a 429, drop on any other 4xx, and retry on anything else.
|
|
724
|
+
*/
|
|
725
|
+
declare const logDeliveryOutcome: (status: number | null) => LogDeliveryOutcome;
|
|
726
|
+
/** How long to wait before trying a log again after its `failedAttempts`th failure: 1s, 2s, 4s and so on, up to 30s. */
|
|
727
|
+
declare const logRetryDelayMs: (failedAttempts: number) => number;
|
|
728
|
+
|
|
677
729
|
declare const isValidAppearance: (value: unknown) => value is Appearance;
|
|
678
730
|
/** Accepts 3- and 6-digit hex color strings (#rgb, #rrggbb). */
|
|
679
731
|
declare const isValidColor: (value: string) => boolean;
|
|
@@ -714,4 +766,4 @@ declare const apiErrorCodeOf: (body: unknown) => ApiErrorCode | null;
|
|
|
714
766
|
/** A push notification's data as PushData, or null for data no Lumber push sends. */
|
|
715
767
|
declare const parsePushData: (data: unknown) => PushData | null;
|
|
716
768
|
|
|
717
|
-
export { APP_COLORS, type ApiErrorBody, type ApiErrorCode, type ApiKeyRecord, type ApiResponse, type AppCreatedRecord, type AppEncryptedKey, type AppKeyUpsertBody, type AppPermission, type AppPersonRecord, type AppRecord, type AppTeamAccess, type Appearance, type AppsQuery, type ClaimantKeyCheck, type ClientToServerEvents, DEFAULT_ACCENT, DEFAULT_PUSH_THRESHOLD, type DeviceLinkApproveBody, type DeviceLinkCreateBody, type DeviceLinkCreatedRecord, type DeviceLinkPlatform, type DeviceLinkRecord, type DeviceLinkStatus, type FlagRecord, type FlagsQuery, type GuestRecord, type HolderKeyCheck, type InvitationRecord, type KeyCheckResult, type KeyHolder, type KeyPin, type LogContext, type LogEncrypted, LogLevel, type LogLevelName, type LogPayload, type LogRecord, type LogTimeseriesQuery, type LogsQuery, type NoteEncrypted, type NoteRecord, type NotesQuery, type NotificationPreference, type NotificationPreferences, PUSH_OFF, type PendingAppKey, type PendingDeviceLink, type PushData, type PushThreshold, type PushToken, type PushType, type ResponseMetadata, type ServerToClientEvents, type SocketAppPayload, SubscriptionLevel, type SubscriptionLevelName, type SubscriptionLimits, type SubscriptionPlan, type SubscriptionPlanRecord, type TeamMemberRecord, type TeamRecord, type TeamsQuery, type TimeseriesBucket, type TimeseriesResponse, type UserRecord, apiErrorCodeOf, apiErrorCodes, isApiErrorCode, isValidAppearance, isValidColor, isValidDeviceLinkStatus, isValidImageUrl, isValidLogLevel, isValidSubscriptionLevel, isValidTeamMemberRole, joinApiKey, logLevelColors, logLevelNameToLevel, logLevelToName, logLevels, nameColor, normalizePushThreshold, parsePushData, personColor, resolveAppColor, splitApiKey, subscriptionLevelToName, subscriptionLevels, subscriptionLimits, subscriptionPlans };
|
|
769
|
+
export { APP_COLORS, type ApiErrorBody, type ApiErrorCode, type ApiKeyRecord, type ApiResponse, type AppCreatedRecord, type AppEncryptedKey, type AppKeyUpsertBody, type AppPermission, type AppPersonRecord, type AppRecord, type AppTeamAccess, type Appearance, type AppsQuery, type ClaimantKeyCheck, type ClientToServerEvents, DEFAULT_ACCENT, DEFAULT_API_ENDPOINT, DEFAULT_PUSH_THRESHOLD, type DeviceLinkApproveBody, type DeviceLinkCreateBody, type DeviceLinkCreatedRecord, type DeviceLinkPlatform, type DeviceLinkRecord, type DeviceLinkStatus, type FlagRecord, type FlagsQuery, type GuestRecord, type HolderKeyCheck, type InvitationRecord, type KeyCheckResult, type KeyHolder, type KeyPin, LOG_KEY_VERSION, type LogContext, type LogData, type LogDeliveryOutcome, type LogEncrypted, type LogIngestBody, LogLevel, type LogLevelName, type LogPayload, type LogRecord, type LogTimeseriesQuery, type LogsQuery, type NoteEncrypted, type NoteRecord, type NotesQuery, type NotificationPreference, type NotificationPreferences, PUSH_OFF, type PendingAppKey, type PendingDeviceLink, type PushData, type PushThreshold, type PushToken, type PushType, type ResponseMetadata, type ServerToClientEvents, type SocketAppPayload, SubscriptionLevel, type SubscriptionLevelName, type SubscriptionLimits, type SubscriptionPlan, type SubscriptionPlanRecord, type TeamMemberRecord, type TeamRecord, type TeamsQuery, type TimeseriesBucket, type TimeseriesResponse, type UserRecord, apiErrorCodeOf, apiErrorCodes, buildLogPayload, isApiErrorCode, isValidAppearance, isValidColor, isValidDeviceLinkStatus, isValidImageUrl, isValidLogLevel, isValidSubscriptionLevel, isValidTeamMemberRole, joinApiKey, logDelivery, logDeliveryOutcome, logLevelColors, logLevelNameToLevel, logLevelToName, logLevels, logRetryDelayMs, nameColor, normalizePushThreshold, parsePushData, personColor, resolveAppColor, splitApiKey, subscriptionLevelToName, subscriptionLevels, subscriptionLimits, subscriptionPlans };
|
package/dist/index.js
CHANGED
|
@@ -22,12 +22,15 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
APP_COLORS: () => APP_COLORS,
|
|
24
24
|
DEFAULT_ACCENT: () => DEFAULT_ACCENT,
|
|
25
|
+
DEFAULT_API_ENDPOINT: () => DEFAULT_API_ENDPOINT,
|
|
25
26
|
DEFAULT_PUSH_THRESHOLD: () => DEFAULT_PUSH_THRESHOLD,
|
|
27
|
+
LOG_KEY_VERSION: () => LOG_KEY_VERSION,
|
|
26
28
|
LogLevel: () => LogLevel,
|
|
27
29
|
PUSH_OFF: () => PUSH_OFF,
|
|
28
30
|
SubscriptionLevel: () => SubscriptionLevel,
|
|
29
31
|
apiErrorCodeOf: () => apiErrorCodeOf,
|
|
30
32
|
apiErrorCodes: () => apiErrorCodes,
|
|
33
|
+
buildLogPayload: () => buildLogPayload,
|
|
31
34
|
isApiErrorCode: () => isApiErrorCode,
|
|
32
35
|
isValidAppearance: () => isValidAppearance,
|
|
33
36
|
isValidColor: () => isValidColor,
|
|
@@ -37,10 +40,13 @@ __export(index_exports, {
|
|
|
37
40
|
isValidSubscriptionLevel: () => isValidSubscriptionLevel,
|
|
38
41
|
isValidTeamMemberRole: () => isValidTeamMemberRole,
|
|
39
42
|
joinApiKey: () => joinApiKey,
|
|
43
|
+
logDelivery: () => logDelivery,
|
|
44
|
+
logDeliveryOutcome: () => logDeliveryOutcome,
|
|
40
45
|
logLevelColors: () => logLevelColors,
|
|
41
46
|
logLevelNameToLevel: () => logLevelNameToLevel,
|
|
42
47
|
logLevelToName: () => logLevelToName,
|
|
43
48
|
logLevels: () => logLevels,
|
|
49
|
+
logRetryDelayMs: () => logRetryDelayMs,
|
|
44
50
|
nameColor: () => nameColor,
|
|
45
51
|
normalizePushThreshold: () => normalizePushThreshold,
|
|
46
52
|
parsePushData: () => parsePushData,
|
|
@@ -55,13 +61,13 @@ __export(index_exports, {
|
|
|
55
61
|
module.exports = __toCommonJS(index_exports);
|
|
56
62
|
|
|
57
63
|
// src/constants/logLevel.ts
|
|
58
|
-
var LogLevel = /* @__PURE__ */ ((
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return
|
|
64
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel3) => {
|
|
65
|
+
LogLevel3[LogLevel3["Debug"] = 0] = "Debug";
|
|
66
|
+
LogLevel3[LogLevel3["Info"] = 1] = "Info";
|
|
67
|
+
LogLevel3[LogLevel3["Warn"] = 2] = "Warn";
|
|
68
|
+
LogLevel3[LogLevel3["Error"] = 3] = "Error";
|
|
69
|
+
LogLevel3[LogLevel3["Fatal"] = 4] = "Fatal";
|
|
70
|
+
return LogLevel3;
|
|
65
71
|
})(LogLevel || {});
|
|
66
72
|
var logLevelToName = {
|
|
67
73
|
[0 /* Debug */]: "debug",
|
|
@@ -108,6 +114,16 @@ var apiErrorCodes = [
|
|
|
108
114
|
"HAS_ACCOUNT"
|
|
109
115
|
];
|
|
110
116
|
|
|
117
|
+
// src/constants/ingest.ts
|
|
118
|
+
var DEFAULT_API_ENDPOINT = "https://api.lumber.infinitetoken.com";
|
|
119
|
+
var LOG_KEY_VERSION = 1;
|
|
120
|
+
var logDelivery = {
|
|
121
|
+
maxAttempts: 5,
|
|
122
|
+
baseDelayMs: 1e3,
|
|
123
|
+
maxDelayMs: 3e4,
|
|
124
|
+
pauseMs: 60 * 60 * 1e3
|
|
125
|
+
};
|
|
126
|
+
|
|
111
127
|
// src/constants/notifications.ts
|
|
112
128
|
var PUSH_OFF = 5;
|
|
113
129
|
var DEFAULT_PUSH_THRESHOLD = 2 /* Warn */;
|
|
@@ -140,6 +156,32 @@ var subscriptionPlans = {
|
|
|
140
156
|
[3 /* Enterprise */]: { name: "Enterprise", monthlyPrice: null }
|
|
141
157
|
};
|
|
142
158
|
|
|
159
|
+
// src/utils/ingest.ts
|
|
160
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
161
|
+
var buildLogPayload = (level, message, data, autoContext) => {
|
|
162
|
+
const { requestId, traceId, context: givenContext, metadata: givenMetadata, ...rest } = data ?? {};
|
|
163
|
+
const context = isRecord(givenContext) ? givenContext : void 0;
|
|
164
|
+
const metadata = isRecord(givenMetadata) ? givenMetadata : void 0;
|
|
165
|
+
if (givenContext != null && !context) rest.context = givenContext;
|
|
166
|
+
if (givenMetadata != null && !metadata) rest.metadata = givenMetadata;
|
|
167
|
+
const mergedMetadata = Object.keys(rest).length > 0 ? { ...rest, ...metadata ?? {} } : metadata;
|
|
168
|
+
const mergedContext = autoContext && Object.keys(autoContext).length > 0 ? { ...autoContext, ...context ?? {} } : context;
|
|
169
|
+
const payload = { level, message };
|
|
170
|
+
if (requestId !== void 0) payload.requestId = requestId;
|
|
171
|
+
if (traceId !== void 0) payload.traceId = traceId;
|
|
172
|
+
if (mergedContext !== void 0) payload.context = mergedContext;
|
|
173
|
+
if (mergedMetadata !== void 0) payload.metadata = mergedMetadata;
|
|
174
|
+
return payload;
|
|
175
|
+
};
|
|
176
|
+
var logDeliveryOutcome = (status) => {
|
|
177
|
+
if (status === null) return "retry";
|
|
178
|
+
if (status >= 200 && status < 300) return "sent";
|
|
179
|
+
if (status === 429) return "pause";
|
|
180
|
+
if (status >= 400 && status < 500) return "drop";
|
|
181
|
+
return "retry";
|
|
182
|
+
};
|
|
183
|
+
var logRetryDelayMs = (failedAttempts) => Math.min(logDelivery.baseDelayMs * 2 ** Math.max(0, failedAttempts - 1), logDelivery.maxDelayMs);
|
|
184
|
+
|
|
143
185
|
// src/utils/index.ts
|
|
144
186
|
var appearanceValues = ["system", "dark", "light"];
|
|
145
187
|
var isValidAppearance = (value) => appearanceValues.includes(value);
|
|
@@ -215,12 +257,15 @@ var parsePushData = (data) => {
|
|
|
215
257
|
0 && (module.exports = {
|
|
216
258
|
APP_COLORS,
|
|
217
259
|
DEFAULT_ACCENT,
|
|
260
|
+
DEFAULT_API_ENDPOINT,
|
|
218
261
|
DEFAULT_PUSH_THRESHOLD,
|
|
262
|
+
LOG_KEY_VERSION,
|
|
219
263
|
LogLevel,
|
|
220
264
|
PUSH_OFF,
|
|
221
265
|
SubscriptionLevel,
|
|
222
266
|
apiErrorCodeOf,
|
|
223
267
|
apiErrorCodes,
|
|
268
|
+
buildLogPayload,
|
|
224
269
|
isApiErrorCode,
|
|
225
270
|
isValidAppearance,
|
|
226
271
|
isValidColor,
|
|
@@ -230,10 +275,13 @@ var parsePushData = (data) => {
|
|
|
230
275
|
isValidSubscriptionLevel,
|
|
231
276
|
isValidTeamMemberRole,
|
|
232
277
|
joinApiKey,
|
|
278
|
+
logDelivery,
|
|
279
|
+
logDeliveryOutcome,
|
|
233
280
|
logLevelColors,
|
|
234
281
|
logLevelNameToLevel,
|
|
235
282
|
logLevelToName,
|
|
236
283
|
logLevels,
|
|
284
|
+
logRetryDelayMs,
|
|
237
285
|
nameColor,
|
|
238
286
|
normalizePushThreshold,
|
|
239
287
|
parsePushData,
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/constants/logLevel.ts
|
|
2
|
-
var LogLevel = /* @__PURE__ */ ((
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return
|
|
2
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel3) => {
|
|
3
|
+
LogLevel3[LogLevel3["Debug"] = 0] = "Debug";
|
|
4
|
+
LogLevel3[LogLevel3["Info"] = 1] = "Info";
|
|
5
|
+
LogLevel3[LogLevel3["Warn"] = 2] = "Warn";
|
|
6
|
+
LogLevel3[LogLevel3["Error"] = 3] = "Error";
|
|
7
|
+
LogLevel3[LogLevel3["Fatal"] = 4] = "Fatal";
|
|
8
|
+
return LogLevel3;
|
|
9
9
|
})(LogLevel || {});
|
|
10
10
|
var logLevelToName = {
|
|
11
11
|
[0 /* Debug */]: "debug",
|
|
@@ -52,6 +52,16 @@ var apiErrorCodes = [
|
|
|
52
52
|
"HAS_ACCOUNT"
|
|
53
53
|
];
|
|
54
54
|
|
|
55
|
+
// src/constants/ingest.ts
|
|
56
|
+
var DEFAULT_API_ENDPOINT = "https://api.lumber.infinitetoken.com";
|
|
57
|
+
var LOG_KEY_VERSION = 1;
|
|
58
|
+
var logDelivery = {
|
|
59
|
+
maxAttempts: 5,
|
|
60
|
+
baseDelayMs: 1e3,
|
|
61
|
+
maxDelayMs: 3e4,
|
|
62
|
+
pauseMs: 60 * 60 * 1e3
|
|
63
|
+
};
|
|
64
|
+
|
|
55
65
|
// src/constants/notifications.ts
|
|
56
66
|
var PUSH_OFF = 5;
|
|
57
67
|
var DEFAULT_PUSH_THRESHOLD = 2 /* Warn */;
|
|
@@ -84,6 +94,32 @@ var subscriptionPlans = {
|
|
|
84
94
|
[3 /* Enterprise */]: { name: "Enterprise", monthlyPrice: null }
|
|
85
95
|
};
|
|
86
96
|
|
|
97
|
+
// src/utils/ingest.ts
|
|
98
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
99
|
+
var buildLogPayload = (level, message, data, autoContext) => {
|
|
100
|
+
const { requestId, traceId, context: givenContext, metadata: givenMetadata, ...rest } = data ?? {};
|
|
101
|
+
const context = isRecord(givenContext) ? givenContext : void 0;
|
|
102
|
+
const metadata = isRecord(givenMetadata) ? givenMetadata : void 0;
|
|
103
|
+
if (givenContext != null && !context) rest.context = givenContext;
|
|
104
|
+
if (givenMetadata != null && !metadata) rest.metadata = givenMetadata;
|
|
105
|
+
const mergedMetadata = Object.keys(rest).length > 0 ? { ...rest, ...metadata ?? {} } : metadata;
|
|
106
|
+
const mergedContext = autoContext && Object.keys(autoContext).length > 0 ? { ...autoContext, ...context ?? {} } : context;
|
|
107
|
+
const payload = { level, message };
|
|
108
|
+
if (requestId !== void 0) payload.requestId = requestId;
|
|
109
|
+
if (traceId !== void 0) payload.traceId = traceId;
|
|
110
|
+
if (mergedContext !== void 0) payload.context = mergedContext;
|
|
111
|
+
if (mergedMetadata !== void 0) payload.metadata = mergedMetadata;
|
|
112
|
+
return payload;
|
|
113
|
+
};
|
|
114
|
+
var logDeliveryOutcome = (status) => {
|
|
115
|
+
if (status === null) return "retry";
|
|
116
|
+
if (status >= 200 && status < 300) return "sent";
|
|
117
|
+
if (status === 429) return "pause";
|
|
118
|
+
if (status >= 400 && status < 500) return "drop";
|
|
119
|
+
return "retry";
|
|
120
|
+
};
|
|
121
|
+
var logRetryDelayMs = (failedAttempts) => Math.min(logDelivery.baseDelayMs * 2 ** Math.max(0, failedAttempts - 1), logDelivery.maxDelayMs);
|
|
122
|
+
|
|
87
123
|
// src/utils/index.ts
|
|
88
124
|
var appearanceValues = ["system", "dark", "light"];
|
|
89
125
|
var isValidAppearance = (value) => appearanceValues.includes(value);
|
|
@@ -158,12 +194,15 @@ var parsePushData = (data) => {
|
|
|
158
194
|
export {
|
|
159
195
|
APP_COLORS,
|
|
160
196
|
DEFAULT_ACCENT,
|
|
197
|
+
DEFAULT_API_ENDPOINT,
|
|
161
198
|
DEFAULT_PUSH_THRESHOLD,
|
|
199
|
+
LOG_KEY_VERSION,
|
|
162
200
|
LogLevel,
|
|
163
201
|
PUSH_OFF,
|
|
164
202
|
SubscriptionLevel,
|
|
165
203
|
apiErrorCodeOf,
|
|
166
204
|
apiErrorCodes,
|
|
205
|
+
buildLogPayload,
|
|
167
206
|
isApiErrorCode,
|
|
168
207
|
isValidAppearance,
|
|
169
208
|
isValidColor,
|
|
@@ -173,10 +212,13 @@ export {
|
|
|
173
212
|
isValidSubscriptionLevel,
|
|
174
213
|
isValidTeamMemberRole,
|
|
175
214
|
joinApiKey,
|
|
215
|
+
logDelivery,
|
|
216
|
+
logDeliveryOutcome,
|
|
176
217
|
logLevelColors,
|
|
177
218
|
logLevelNameToLevel,
|
|
178
219
|
logLevelToName,
|
|
179
220
|
logLevels,
|
|
221
|
+
logRetryDelayMs,
|
|
180
222
|
nameColor,
|
|
181
223
|
normalizePushThreshold,
|
|
182
224
|
parsePushData,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infinitetoken/lumber-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Shared TypeScript types and wire format contracts for the Lumber cloud logging suite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lumber",
|
|
@@ -31,17 +31,20 @@
|
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
32
|
"default": "./dist/index.js"
|
|
33
33
|
}
|
|
34
|
-
}
|
|
34
|
+
},
|
|
35
|
+
"./contract/*": "./contract/*"
|
|
35
36
|
},
|
|
36
37
|
"main": "./dist/index.js",
|
|
37
38
|
"module": "./dist/index.mjs",
|
|
38
39
|
"types": "./dist/index.d.ts",
|
|
39
40
|
"files": [
|
|
40
|
-
"dist"
|
|
41
|
+
"dist",
|
|
42
|
+
"contract"
|
|
41
43
|
],
|
|
42
44
|
"scripts": {
|
|
43
45
|
"build": "tsup",
|
|
44
46
|
"clean": "rm -rf dist coverage",
|
|
47
|
+
"contract": "node scripts/contract.cjs",
|
|
45
48
|
"fix": "eslint . --fix",
|
|
46
49
|
"lint": "eslint .",
|
|
47
50
|
"prepublishOnly": "npm run build",
|
|
@@ -61,9 +64,11 @@
|
|
|
61
64
|
"@infinitetoken/tsconfig": "^0.6.0",
|
|
62
65
|
"@types/jest": "^30.0.0",
|
|
63
66
|
"@types/node": "^25.0.0",
|
|
67
|
+
"ajv": "^8.20.0",
|
|
64
68
|
"eslint": "^10.2.1",
|
|
65
69
|
"jest": "^30.4.2",
|
|
66
70
|
"prettier": "^3.8.3",
|
|
71
|
+
"ts-json-schema-generator": "^2.9.0",
|
|
67
72
|
"tsup": "^8.5.1",
|
|
68
73
|
"typescript": "^6.0.3"
|
|
69
74
|
},
|