@primitivedotdev/cli 0.31.7 → 0.31.8
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/bin/run.js +5 -0
- package/dist/oclif/index.js +647 -5
- package/dist/oclif/root-signup-hint.js +31 -0
- package/package.json +14 -3
package/bin/run.js
CHANGED
|
@@ -7,5 +7,10 @@ import { restartWithProxyEnvIfNeeded } from "../dist/oclif/proxy-auto-detect.js"
|
|
|
7
7
|
// process.env inside this process is too late for built-in fetch.
|
|
8
8
|
restartWithProxyEnvIfNeeded();
|
|
9
9
|
|
|
10
|
+
const { writeLoggedOutSignupHintIfNeeded } = await import(
|
|
11
|
+
"../dist/oclif/root-signup-hint.js"
|
|
12
|
+
);
|
|
13
|
+
writeLoggedOutSignupHintIfNeeded();
|
|
14
|
+
|
|
10
15
|
const { execute } = await import("@oclif/core");
|
|
11
16
|
await execute({ dir: import.meta.url });
|
package/dist/oclif/index.js
CHANGED
|
@@ -655,6 +655,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
|
|
|
655
655
|
getSendPermissions: () => getSendPermissions,
|
|
656
656
|
getSentEmail: () => getSentEmail,
|
|
657
657
|
getStorageStats: () => getStorageStats,
|
|
658
|
+
getThread: () => getThread,
|
|
658
659
|
getWebhookSecret: () => getWebhookSecret,
|
|
659
660
|
listDeliveries: () => listDeliveries,
|
|
660
661
|
listDomains: () => listDomains,
|
|
@@ -1579,6 +1580,33 @@ const getSentEmail = (options) => (options.client ?? client).get({
|
|
|
1579
1580
|
...options
|
|
1580
1581
|
});
|
|
1581
1582
|
/**
|
|
1583
|
+
* Get a conversation thread by id
|
|
1584
|
+
*
|
|
1585
|
+
* Returns a conversation thread: its metadata plus the inbound
|
|
1586
|
+
* and outbound messages that belong to it, interleaved in time
|
|
1587
|
+
* order (oldest first). A thread spans both received emails and
|
|
1588
|
+
* your sends, so an agent can reconstruct an entire back-and-forth
|
|
1589
|
+
* from one call instead of walking reply headers.
|
|
1590
|
+
*
|
|
1591
|
+
* Each message carries a `direction` (`inbound` | `outbound`) and
|
|
1592
|
+
* an `id`; fetch the full message via `/emails/{id}` or
|
|
1593
|
+
* `/sent-emails/{id}` accordingly. Bodies are omitted here to keep
|
|
1594
|
+
* the thread view lightweight.
|
|
1595
|
+
*
|
|
1596
|
+
* Discover a thread id from the `thread_id` field on any email or
|
|
1597
|
+
* sent-email (list or detail). The message list is capped; compare
|
|
1598
|
+
* `message_count` against `messages.length` to detect truncation.
|
|
1599
|
+
*
|
|
1600
|
+
*/
|
|
1601
|
+
const getThread = (options) => (options.client ?? client).get({
|
|
1602
|
+
security: [{
|
|
1603
|
+
scheme: "bearer",
|
|
1604
|
+
type: "http"
|
|
1605
|
+
}],
|
|
1606
|
+
url: "/threads/{id}",
|
|
1607
|
+
...options
|
|
1608
|
+
});
|
|
1609
|
+
/**
|
|
1582
1610
|
* List functions
|
|
1583
1611
|
*
|
|
1584
1612
|
* Returns every active (non-deleted) function in the org, newest
|
|
@@ -1929,6 +1957,10 @@ const openapiDocument = {
|
|
|
1929
1957
|
"name": "Sending",
|
|
1930
1958
|
"description": "Send outbound emails through the Primitive API"
|
|
1931
1959
|
},
|
|
1960
|
+
{
|
|
1961
|
+
"name": "Threads",
|
|
1962
|
+
"description": "Conversation threads spanning received and sent emails"
|
|
1963
|
+
},
|
|
1932
1964
|
{
|
|
1933
1965
|
"name": "Endpoints",
|
|
1934
1966
|
"description": "Manage webhook endpoints that receive email events"
|
|
@@ -3424,6 +3456,27 @@ const openapiDocument = {
|
|
|
3424
3456
|
"404": { "$ref": "#/components/responses/NotFound" }
|
|
3425
3457
|
}
|
|
3426
3458
|
} },
|
|
3459
|
+
"/threads/{id}": {
|
|
3460
|
+
"parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
|
|
3461
|
+
"get": {
|
|
3462
|
+
"operationId": "getThread",
|
|
3463
|
+
"summary": "Get a conversation thread by id",
|
|
3464
|
+
"description": "Returns a conversation thread: its metadata plus the inbound\nand outbound messages that belong to it, interleaved in time\norder (oldest first). A thread spans both received emails and\nyour sends, so an agent can reconstruct an entire back-and-forth\nfrom one call instead of walking reply headers.\n\nEach message carries a `direction` (`inbound` | `outbound`) and\nan `id`; fetch the full message via `/emails/{id}` or\n`/sent-emails/{id}` accordingly. Bodies are omitted here to keep\nthe thread view lightweight.\n\nDiscover a thread id from the `thread_id` field on any email or\nsent-email (list or detail). The message list is capped; compare\n`message_count` against `messages.length` to detect truncation.\n",
|
|
3465
|
+
"tags": ["Threads"],
|
|
3466
|
+
"responses": {
|
|
3467
|
+
"200": {
|
|
3468
|
+
"description": "Thread detail",
|
|
3469
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3470
|
+
"type": "object",
|
|
3471
|
+
"properties": { "data": { "$ref": "#/components/schemas/Thread" } }
|
|
3472
|
+
}] } } }
|
|
3473
|
+
},
|
|
3474
|
+
"400": { "$ref": "#/components/responses/ValidationError" },
|
|
3475
|
+
"401": { "$ref": "#/components/responses/Unauthorized" },
|
|
3476
|
+
"404": { "$ref": "#/components/responses/NotFound" }
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
},
|
|
3427
3480
|
"/functions": {
|
|
3428
3481
|
"get": {
|
|
3429
3482
|
"operationId": "listFunctions",
|
|
@@ -5291,7 +5344,12 @@ const openapiDocument = {
|
|
|
5291
5344
|
},
|
|
5292
5345
|
"raw_size_bytes": { "type": ["integer", "null"] },
|
|
5293
5346
|
"webhook_status": { "$ref": "#/components/schemas/EmailWebhookStatus" },
|
|
5294
|
-
"webhook_attempt_count": { "type": "integer" }
|
|
5347
|
+
"webhook_attempt_count": { "type": "integer" },
|
|
5348
|
+
"thread_id": {
|
|
5349
|
+
"type": ["string", "null"],
|
|
5350
|
+
"format": "uuid",
|
|
5351
|
+
"description": "Conversation thread this message belongs to. Fetch\n`/threads/{thread_id}` for the full ordered thread. NULL on\nmessages received before threading was enabled.\n"
|
|
5352
|
+
}
|
|
5295
5353
|
},
|
|
5296
5354
|
"required": [
|
|
5297
5355
|
"id",
|
|
@@ -5510,6 +5568,19 @@ const openapiDocument = {
|
|
|
5510
5568
|
"type": ["string", "null"],
|
|
5511
5569
|
"format": "uuid",
|
|
5512
5570
|
"description": "The `sent_emails.id` of the outbound this inbound was a\nreply to, when resolvable. Set at inbound ingest by\nmatching the parsed In-Reply-To (or References, as a\nfallback) against `sent_emails.message_id` in the same\norg. The mirror of `sent_emails.in_reply_to_email_id` for\nthe inbound side of a thread. NULL when the inbound is\nnot a threaded reply to one of your sends, when neither\nheader survived the path through intermediate MTAs, or on\ninbound received before this auto-link landed.\n"
|
|
5571
|
+
},
|
|
5572
|
+
"thread_id": {
|
|
5573
|
+
"type": ["string", "null"],
|
|
5574
|
+
"format": "uuid",
|
|
5575
|
+
"description": "Conversation thread this message belongs to. Inbound and\noutbound messages in the same conversation share a\n`thread_id`; fetch `/threads/{thread_id}` for the full\nordered thread. Assigned at ingest. NULL on messages\nreceived before threading was enabled (until backfilled).\n"
|
|
5576
|
+
},
|
|
5577
|
+
"parsed": {
|
|
5578
|
+
"allOf": [{ "$ref": "#/components/schemas/ParsedEmailData" }],
|
|
5579
|
+
"description": "Parsed MIME content (addresses, threading headers,\nattachment metadata), matching the `email.parsed` object\non the webhook payload so one parser handles both the\nwebhook and this endpoint. The top-level `body_text` /\n`body_html` fields above are the same values as\n`parsed.body_text` / `parsed.body_html`, retained for\nbackward compatibility.\n"
|
|
5580
|
+
},
|
|
5581
|
+
"auth": {
|
|
5582
|
+
"allOf": [{ "$ref": "#/components/schemas/EmailAuth" }],
|
|
5583
|
+
"description": "SPF / DKIM / DMARC verdicts computed at ingest, matching\nthe `email.auth` object on the webhook payload. Use these\nto decide how much to trust a message before acting on\ninstructions it contains.\n"
|
|
5513
5584
|
}
|
|
5514
5585
|
},
|
|
5515
5586
|
"required": [
|
|
@@ -5523,7 +5594,9 @@ const openapiDocument = {
|
|
|
5523
5594
|
"webhook_attempt_count",
|
|
5524
5595
|
"from_email",
|
|
5525
5596
|
"to_email",
|
|
5526
|
-
"replies"
|
|
5597
|
+
"replies",
|
|
5598
|
+
"parsed",
|
|
5599
|
+
"auth"
|
|
5527
5600
|
]
|
|
5528
5601
|
},
|
|
5529
5602
|
"EmailDetailReply": {
|
|
@@ -5556,6 +5629,241 @@ const openapiDocument = {
|
|
|
5556
5629
|
"created_at"
|
|
5557
5630
|
]
|
|
5558
5631
|
},
|
|
5632
|
+
"EmailAddress": {
|
|
5633
|
+
"type": "object",
|
|
5634
|
+
"description": "A parsed RFC 5322 address with optional display name.",
|
|
5635
|
+
"properties": {
|
|
5636
|
+
"name": {
|
|
5637
|
+
"type": ["string", "null"],
|
|
5638
|
+
"description": "Display name, when present (e.g. `Alice Example`)."
|
|
5639
|
+
},
|
|
5640
|
+
"address": {
|
|
5641
|
+
"type": "string",
|
|
5642
|
+
"description": "Bare email address (e.g. `alice@example.com`)."
|
|
5643
|
+
}
|
|
5644
|
+
},
|
|
5645
|
+
"required": ["address"]
|
|
5646
|
+
},
|
|
5647
|
+
"EmailAttachment": {
|
|
5648
|
+
"type": "object",
|
|
5649
|
+
"description": "Metadata for one attachment. The bytes are not inline; download\nall attachments for a message as a gzipped tarball via\n`/emails/{id}/attachments.tar.gz`. `sha256` lets you verify a\nspecific part after extraction.\n",
|
|
5650
|
+
"properties": {
|
|
5651
|
+
"filename": { "type": ["string", "null"] },
|
|
5652
|
+
"content_type": { "type": ["string", "null"] },
|
|
5653
|
+
"size_bytes": { "type": "integer" },
|
|
5654
|
+
"sha256": { "type": ["string", "null"] },
|
|
5655
|
+
"part_index": {
|
|
5656
|
+
"type": "integer",
|
|
5657
|
+
"description": "Zero-based index of this part within the message."
|
|
5658
|
+
}
|
|
5659
|
+
},
|
|
5660
|
+
"required": ["size_bytes"]
|
|
5661
|
+
},
|
|
5662
|
+
"ParsedEmailData": {
|
|
5663
|
+
"type": "object",
|
|
5664
|
+
"description": "Parsed MIME content for an inbound email. Mirrors the\n`email.parsed` object on the webhook payload so a single parser\nhandles both surfaces. `status` is `complete` when parsing\nsucceeded; on `failed` the body/address/attachment fields are\nabsent and `error` describes why.\n",
|
|
5665
|
+
"properties": {
|
|
5666
|
+
"status": {
|
|
5667
|
+
"type": "string",
|
|
5668
|
+
"enum": ["complete", "failed"]
|
|
5669
|
+
},
|
|
5670
|
+
"body_text": {
|
|
5671
|
+
"type": ["string", "null"],
|
|
5672
|
+
"description": "Plain-text body. Present when `status` is `complete`."
|
|
5673
|
+
},
|
|
5674
|
+
"body_html": {
|
|
5675
|
+
"type": ["string", "null"],
|
|
5676
|
+
"description": "HTML body. Present when `status` is `complete`."
|
|
5677
|
+
},
|
|
5678
|
+
"reply_to": {
|
|
5679
|
+
"type": ["array", "null"],
|
|
5680
|
+
"items": { "$ref": "#/components/schemas/EmailAddress" },
|
|
5681
|
+
"description": "Parsed `Reply-To` header addresses."
|
|
5682
|
+
},
|
|
5683
|
+
"cc": {
|
|
5684
|
+
"type": ["array", "null"],
|
|
5685
|
+
"items": { "$ref": "#/components/schemas/EmailAddress" },
|
|
5686
|
+
"description": "Parsed `Cc` header addresses."
|
|
5687
|
+
},
|
|
5688
|
+
"bcc": {
|
|
5689
|
+
"type": ["array", "null"],
|
|
5690
|
+
"items": { "$ref": "#/components/schemas/EmailAddress" },
|
|
5691
|
+
"description": "Parsed `Bcc` header addresses (rarely present on inbound)."
|
|
5692
|
+
},
|
|
5693
|
+
"to_addresses": {
|
|
5694
|
+
"type": ["array", "null"],
|
|
5695
|
+
"items": { "$ref": "#/components/schemas/EmailAddress" },
|
|
5696
|
+
"description": "Parsed `To` header addresses."
|
|
5697
|
+
},
|
|
5698
|
+
"in_reply_to": {
|
|
5699
|
+
"type": ["array", "null"],
|
|
5700
|
+
"items": { "type": "string" },
|
|
5701
|
+
"description": "Message-IDs from the `In-Reply-To` header."
|
|
5702
|
+
},
|
|
5703
|
+
"references": {
|
|
5704
|
+
"type": ["array", "null"],
|
|
5705
|
+
"items": { "type": "string" },
|
|
5706
|
+
"description": "Message-IDs from the `References` header."
|
|
5707
|
+
},
|
|
5708
|
+
"attachments": {
|
|
5709
|
+
"type": "array",
|
|
5710
|
+
"items": { "$ref": "#/components/schemas/EmailAttachment" },
|
|
5711
|
+
"description": "Attachment metadata. Empty array when none."
|
|
5712
|
+
},
|
|
5713
|
+
"error": {
|
|
5714
|
+
"type": ["object", "null"],
|
|
5715
|
+
"description": "Present (non-null) only when `status` is `failed`. When\npresent, all three fields are populated, so a consumer can\nbranch on `code` without defensive null checks.\n",
|
|
5716
|
+
"properties": {
|
|
5717
|
+
"code": {
|
|
5718
|
+
"type": "string",
|
|
5719
|
+
"description": "Stable failure code (e.g. `PARSE_FAILED`)."
|
|
5720
|
+
},
|
|
5721
|
+
"message": { "type": "string" },
|
|
5722
|
+
"retryable": { "type": "boolean" }
|
|
5723
|
+
},
|
|
5724
|
+
"required": [
|
|
5725
|
+
"code",
|
|
5726
|
+
"message",
|
|
5727
|
+
"retryable"
|
|
5728
|
+
]
|
|
5729
|
+
}
|
|
5730
|
+
},
|
|
5731
|
+
"required": ["status"]
|
|
5732
|
+
},
|
|
5733
|
+
"DkimSignature": {
|
|
5734
|
+
"type": "object",
|
|
5735
|
+
"description": "One DKIM signature found on the message, with its verdict.",
|
|
5736
|
+
"properties": {
|
|
5737
|
+
"domain": { "type": "string" },
|
|
5738
|
+
"selector": { "type": "string" },
|
|
5739
|
+
"result": {
|
|
5740
|
+
"type": "string",
|
|
5741
|
+
"description": "Verification result (e.g. `pass`, `fail`, `none`)."
|
|
5742
|
+
},
|
|
5743
|
+
"aligned": {
|
|
5744
|
+
"type": "boolean",
|
|
5745
|
+
"description": "Whether the signing domain aligns with the From domain (for DMARC)."
|
|
5746
|
+
},
|
|
5747
|
+
"keyBits": { "type": ["integer", "null"] },
|
|
5748
|
+
"algo": { "type": ["string", "null"] }
|
|
5749
|
+
},
|
|
5750
|
+
"required": [
|
|
5751
|
+
"domain",
|
|
5752
|
+
"selector",
|
|
5753
|
+
"result",
|
|
5754
|
+
"aligned"
|
|
5755
|
+
]
|
|
5756
|
+
},
|
|
5757
|
+
"EmailAuth": {
|
|
5758
|
+
"type": "object",
|
|
5759
|
+
"description": "SPF / DKIM / DMARC verdicts computed at ingest. Mirrors the\n`email.auth` object on the webhook payload. Field names are\ncamelCase to match that payload exactly. For messages received\nbefore auth was recorded, the verdicts default to `none`.\n",
|
|
5760
|
+
"properties": {
|
|
5761
|
+
"spf": {
|
|
5762
|
+
"type": "string",
|
|
5763
|
+
"description": "SPF result (e.g. `pass`, `fail`, `softfail`, `none`)."
|
|
5764
|
+
},
|
|
5765
|
+
"dmarc": {
|
|
5766
|
+
"type": "string",
|
|
5767
|
+
"description": "DMARC result (e.g. `pass`, `fail`, `none`)."
|
|
5768
|
+
},
|
|
5769
|
+
"dmarcPolicy": {
|
|
5770
|
+
"type": ["string", "null"],
|
|
5771
|
+
"description": "Published DMARC policy (`none`, `quarantine`, `reject`)."
|
|
5772
|
+
},
|
|
5773
|
+
"dmarcFromDomain": {
|
|
5774
|
+
"type": ["string", "null"],
|
|
5775
|
+
"description": "The From-header domain DMARC was evaluated against."
|
|
5776
|
+
},
|
|
5777
|
+
"dmarcSpfAligned": { "type": "boolean" },
|
|
5778
|
+
"dmarcDkimAligned": { "type": "boolean" },
|
|
5779
|
+
"dmarcSpfStrict": { "type": ["boolean", "null"] },
|
|
5780
|
+
"dmarcDkimStrict": { "type": ["boolean", "null"] },
|
|
5781
|
+
"dkimSignatures": {
|
|
5782
|
+
"type": "array",
|
|
5783
|
+
"items": { "$ref": "#/components/schemas/DkimSignature" }
|
|
5784
|
+
}
|
|
5785
|
+
},
|
|
5786
|
+
"required": [
|
|
5787
|
+
"spf",
|
|
5788
|
+
"dmarc",
|
|
5789
|
+
"dmarcSpfAligned",
|
|
5790
|
+
"dmarcDkimAligned",
|
|
5791
|
+
"dkimSignatures"
|
|
5792
|
+
]
|
|
5793
|
+
},
|
|
5794
|
+
"Thread": {
|
|
5795
|
+
"type": "object",
|
|
5796
|
+
"description": "A conversation thread: its metadata plus the inbound and\noutbound messages that belong to it, interleaved oldest-first.\nMembership is the stored `thread_id` on each message. Bodies are\nomitted here to keep the thread view lightweight; fetch\n`/emails/{id}` or `/sent-emails/{id}` for a single message's\nfull content.\n",
|
|
5797
|
+
"properties": {
|
|
5798
|
+
"id": {
|
|
5799
|
+
"type": "string",
|
|
5800
|
+
"format": "uuid"
|
|
5801
|
+
},
|
|
5802
|
+
"subject": {
|
|
5803
|
+
"type": ["string", "null"],
|
|
5804
|
+
"description": "Normalized subject of the thread (Re/Fwd prefixes stripped)."
|
|
5805
|
+
},
|
|
5806
|
+
"root_message_id": {
|
|
5807
|
+
"type": ["string", "null"],
|
|
5808
|
+
"description": "Message-ID of the conversation root, when known."
|
|
5809
|
+
},
|
|
5810
|
+
"message_count": {
|
|
5811
|
+
"type": "integer",
|
|
5812
|
+
"description": "Total messages in the thread. `messages` is capped (most\nrecent first, then re-sorted oldest-first), so\n`message_count > messages.length` signals truncation.\n"
|
|
5813
|
+
},
|
|
5814
|
+
"first_message_at": {
|
|
5815
|
+
"type": ["string", "null"],
|
|
5816
|
+
"format": "date-time"
|
|
5817
|
+
},
|
|
5818
|
+
"last_message_at": {
|
|
5819
|
+
"type": ["string", "null"],
|
|
5820
|
+
"format": "date-time"
|
|
5821
|
+
},
|
|
5822
|
+
"created_at": {
|
|
5823
|
+
"type": "string",
|
|
5824
|
+
"format": "date-time"
|
|
5825
|
+
},
|
|
5826
|
+
"messages": {
|
|
5827
|
+
"type": "array",
|
|
5828
|
+
"items": { "$ref": "#/components/schemas/ThreadMessage" }
|
|
5829
|
+
}
|
|
5830
|
+
},
|
|
5831
|
+
"required": [
|
|
5832
|
+
"id",
|
|
5833
|
+
"message_count",
|
|
5834
|
+
"created_at",
|
|
5835
|
+
"messages"
|
|
5836
|
+
]
|
|
5837
|
+
},
|
|
5838
|
+
"ThreadMessage": {
|
|
5839
|
+
"type": "object",
|
|
5840
|
+
"description": "One message in a thread (inbound or outbound).",
|
|
5841
|
+
"properties": {
|
|
5842
|
+
"direction": {
|
|
5843
|
+
"type": "string",
|
|
5844
|
+
"enum": ["inbound", "outbound"],
|
|
5845
|
+
"description": "`inbound` for a received email (`/emails/{id}`), `outbound`\nfor a send (`/sent-emails/{id}`). Use it with `id` to fetch\nfull content from the right endpoint.\n"
|
|
5846
|
+
},
|
|
5847
|
+
"id": {
|
|
5848
|
+
"type": "string",
|
|
5849
|
+
"format": "uuid"
|
|
5850
|
+
},
|
|
5851
|
+
"message_id": { "type": ["string", "null"] },
|
|
5852
|
+
"from": { "type": ["string", "null"] },
|
|
5853
|
+
"to": { "type": ["string", "null"] },
|
|
5854
|
+
"subject": { "type": ["string", "null"] },
|
|
5855
|
+
"status": {
|
|
5856
|
+
"type": ["string", "null"],
|
|
5857
|
+
"description": "Lifecycle status (an EmailStatus or SentEmailStatus value, per `direction`)."
|
|
5858
|
+
},
|
|
5859
|
+
"timestamp": {
|
|
5860
|
+
"type": ["string", "null"],
|
|
5861
|
+
"format": "date-time",
|
|
5862
|
+
"description": "received_at for inbound, created_at for outbound."
|
|
5863
|
+
}
|
|
5864
|
+
},
|
|
5865
|
+
"required": ["direction", "id"]
|
|
5866
|
+
},
|
|
5559
5867
|
"SendMailAttachment": {
|
|
5560
5868
|
"type": "object",
|
|
5561
5869
|
"additionalProperties": false,
|
|
@@ -5772,6 +6080,11 @@ const openapiDocument = {
|
|
|
5772
6080
|
"format": "uuid",
|
|
5773
6081
|
"description": "Reference to the inbound `emails.id` that this send\nreplied to, when known. Populated when the caller used\n/emails/{id}/reply or when /send-mail's `in_reply_to`\nmatched a stored inbound message_id in the same org.\n"
|
|
5774
6082
|
},
|
|
6083
|
+
"thread_id": {
|
|
6084
|
+
"type": ["string", "null"],
|
|
6085
|
+
"format": "uuid",
|
|
6086
|
+
"description": "Conversation thread this send belongs to. A reply inherits\nthe thread of the inbound it answers; a fresh send starts a\nnew thread. Fetch `/threads/{thread_id}` for the full\nordered thread (inbound + outbound interleaved). NULL on\ngate-denied sends and on sends created before threading was\nenabled.\n"
|
|
6087
|
+
},
|
|
5775
6088
|
"queue_id": {
|
|
5776
6089
|
"type": ["string", "null"],
|
|
5777
6090
|
"description": "Message identifier assigned by Primitive's outbound\nrelay once the agent accepts the message. Null on\nqueued, gate_denied, and agent_failed rows.\n"
|
|
@@ -8873,6 +9186,218 @@ const operationManifest = [
|
|
|
8873
9186
|
"type": ["string", "null"],
|
|
8874
9187
|
"format": "uuid",
|
|
8875
9188
|
"description": "The `sent_emails.id` of the outbound this inbound was a\nreply to, when resolvable. Set at inbound ingest by\nmatching the parsed In-Reply-To (or References, as a\nfallback) against `sent_emails.message_id` in the same\norg. The mirror of `sent_emails.in_reply_to_email_id` for\nthe inbound side of a thread. NULL when the inbound is\nnot a threaded reply to one of your sends, when neither\nheader survived the path through intermediate MTAs, or on\ninbound received before this auto-link landed.\n"
|
|
9189
|
+
},
|
|
9190
|
+
"thread_id": {
|
|
9191
|
+
"type": ["string", "null"],
|
|
9192
|
+
"format": "uuid",
|
|
9193
|
+
"description": "Conversation thread this message belongs to. Inbound and\noutbound messages in the same conversation share a\n`thread_id`; fetch `/threads/{thread_id}` for the full\nordered thread. Assigned at ingest. NULL on messages\nreceived before threading was enabled (until backfilled).\n"
|
|
9194
|
+
},
|
|
9195
|
+
"parsed": {
|
|
9196
|
+
"allOf": [{
|
|
9197
|
+
"type": "object",
|
|
9198
|
+
"description": "Parsed MIME content for an inbound email. Mirrors the\n`email.parsed` object on the webhook payload so a single parser\nhandles both surfaces. `status` is `complete` when parsing\nsucceeded; on `failed` the body/address/attachment fields are\nabsent and `error` describes why.\n",
|
|
9199
|
+
"properties": {
|
|
9200
|
+
"status": {
|
|
9201
|
+
"type": "string",
|
|
9202
|
+
"enum": ["complete", "failed"]
|
|
9203
|
+
},
|
|
9204
|
+
"body_text": {
|
|
9205
|
+
"type": ["string", "null"],
|
|
9206
|
+
"description": "Plain-text body. Present when `status` is `complete`."
|
|
9207
|
+
},
|
|
9208
|
+
"body_html": {
|
|
9209
|
+
"type": ["string", "null"],
|
|
9210
|
+
"description": "HTML body. Present when `status` is `complete`."
|
|
9211
|
+
},
|
|
9212
|
+
"reply_to": {
|
|
9213
|
+
"type": ["array", "null"],
|
|
9214
|
+
"items": {
|
|
9215
|
+
"type": "object",
|
|
9216
|
+
"description": "A parsed RFC 5322 address with optional display name.",
|
|
9217
|
+
"properties": {
|
|
9218
|
+
"name": {
|
|
9219
|
+
"type": ["string", "null"],
|
|
9220
|
+
"description": "Display name, when present (e.g. `Alice Example`)."
|
|
9221
|
+
},
|
|
9222
|
+
"address": {
|
|
9223
|
+
"type": "string",
|
|
9224
|
+
"description": "Bare email address (e.g. `alice@example.com`)."
|
|
9225
|
+
}
|
|
9226
|
+
},
|
|
9227
|
+
"required": ["address"]
|
|
9228
|
+
},
|
|
9229
|
+
"description": "Parsed `Reply-To` header addresses."
|
|
9230
|
+
},
|
|
9231
|
+
"cc": {
|
|
9232
|
+
"type": ["array", "null"],
|
|
9233
|
+
"items": {
|
|
9234
|
+
"type": "object",
|
|
9235
|
+
"description": "A parsed RFC 5322 address with optional display name.",
|
|
9236
|
+
"properties": {
|
|
9237
|
+
"name": {
|
|
9238
|
+
"type": ["string", "null"],
|
|
9239
|
+
"description": "Display name, when present (e.g. `Alice Example`)."
|
|
9240
|
+
},
|
|
9241
|
+
"address": {
|
|
9242
|
+
"type": "string",
|
|
9243
|
+
"description": "Bare email address (e.g. `alice@example.com`)."
|
|
9244
|
+
}
|
|
9245
|
+
},
|
|
9246
|
+
"required": ["address"]
|
|
9247
|
+
},
|
|
9248
|
+
"description": "Parsed `Cc` header addresses."
|
|
9249
|
+
},
|
|
9250
|
+
"bcc": {
|
|
9251
|
+
"type": ["array", "null"],
|
|
9252
|
+
"items": {
|
|
9253
|
+
"type": "object",
|
|
9254
|
+
"description": "A parsed RFC 5322 address with optional display name.",
|
|
9255
|
+
"properties": {
|
|
9256
|
+
"name": {
|
|
9257
|
+
"type": ["string", "null"],
|
|
9258
|
+
"description": "Display name, when present (e.g. `Alice Example`)."
|
|
9259
|
+
},
|
|
9260
|
+
"address": {
|
|
9261
|
+
"type": "string",
|
|
9262
|
+
"description": "Bare email address (e.g. `alice@example.com`)."
|
|
9263
|
+
}
|
|
9264
|
+
},
|
|
9265
|
+
"required": ["address"]
|
|
9266
|
+
},
|
|
9267
|
+
"description": "Parsed `Bcc` header addresses (rarely present on inbound)."
|
|
9268
|
+
},
|
|
9269
|
+
"to_addresses": {
|
|
9270
|
+
"type": ["array", "null"],
|
|
9271
|
+
"items": {
|
|
9272
|
+
"type": "object",
|
|
9273
|
+
"description": "A parsed RFC 5322 address with optional display name.",
|
|
9274
|
+
"properties": {
|
|
9275
|
+
"name": {
|
|
9276
|
+
"type": ["string", "null"],
|
|
9277
|
+
"description": "Display name, when present (e.g. `Alice Example`)."
|
|
9278
|
+
},
|
|
9279
|
+
"address": {
|
|
9280
|
+
"type": "string",
|
|
9281
|
+
"description": "Bare email address (e.g. `alice@example.com`)."
|
|
9282
|
+
}
|
|
9283
|
+
},
|
|
9284
|
+
"required": ["address"]
|
|
9285
|
+
},
|
|
9286
|
+
"description": "Parsed `To` header addresses."
|
|
9287
|
+
},
|
|
9288
|
+
"in_reply_to": {
|
|
9289
|
+
"type": ["array", "null"],
|
|
9290
|
+
"items": { "type": "string" },
|
|
9291
|
+
"description": "Message-IDs from the `In-Reply-To` header."
|
|
9292
|
+
},
|
|
9293
|
+
"references": {
|
|
9294
|
+
"type": ["array", "null"],
|
|
9295
|
+
"items": { "type": "string" },
|
|
9296
|
+
"description": "Message-IDs from the `References` header."
|
|
9297
|
+
},
|
|
9298
|
+
"attachments": {
|
|
9299
|
+
"type": "array",
|
|
9300
|
+
"items": {
|
|
9301
|
+
"type": "object",
|
|
9302
|
+
"description": "Metadata for one attachment. The bytes are not inline; download\nall attachments for a message as a gzipped tarball via\n`/emails/{id}/attachments.tar.gz`. `sha256` lets you verify a\nspecific part after extraction.\n",
|
|
9303
|
+
"properties": {
|
|
9304
|
+
"filename": { "type": ["string", "null"] },
|
|
9305
|
+
"content_type": { "type": ["string", "null"] },
|
|
9306
|
+
"size_bytes": { "type": "integer" },
|
|
9307
|
+
"sha256": { "type": ["string", "null"] },
|
|
9308
|
+
"part_index": {
|
|
9309
|
+
"type": "integer",
|
|
9310
|
+
"description": "Zero-based index of this part within the message."
|
|
9311
|
+
}
|
|
9312
|
+
},
|
|
9313
|
+
"required": ["size_bytes"]
|
|
9314
|
+
},
|
|
9315
|
+
"description": "Attachment metadata. Empty array when none."
|
|
9316
|
+
},
|
|
9317
|
+
"error": {
|
|
9318
|
+
"type": ["object", "null"],
|
|
9319
|
+
"description": "Present (non-null) only when `status` is `failed`. When\npresent, all three fields are populated, so a consumer can\nbranch on `code` without defensive null checks.\n",
|
|
9320
|
+
"properties": {
|
|
9321
|
+
"code": {
|
|
9322
|
+
"type": "string",
|
|
9323
|
+
"description": "Stable failure code (e.g. `PARSE_FAILED`)."
|
|
9324
|
+
},
|
|
9325
|
+
"message": { "type": "string" },
|
|
9326
|
+
"retryable": { "type": "boolean" }
|
|
9327
|
+
},
|
|
9328
|
+
"required": [
|
|
9329
|
+
"code",
|
|
9330
|
+
"message",
|
|
9331
|
+
"retryable"
|
|
9332
|
+
]
|
|
9333
|
+
}
|
|
9334
|
+
},
|
|
9335
|
+
"required": ["status"]
|
|
9336
|
+
}],
|
|
9337
|
+
"description": "Parsed MIME content (addresses, threading headers,\nattachment metadata), matching the `email.parsed` object\non the webhook payload so one parser handles both the\nwebhook and this endpoint. The top-level `body_text` /\n`body_html` fields above are the same values as\n`parsed.body_text` / `parsed.body_html`, retained for\nbackward compatibility.\n"
|
|
9338
|
+
},
|
|
9339
|
+
"auth": {
|
|
9340
|
+
"allOf": [{
|
|
9341
|
+
"type": "object",
|
|
9342
|
+
"description": "SPF / DKIM / DMARC verdicts computed at ingest. Mirrors the\n`email.auth` object on the webhook payload. Field names are\ncamelCase to match that payload exactly. For messages received\nbefore auth was recorded, the verdicts default to `none`.\n",
|
|
9343
|
+
"properties": {
|
|
9344
|
+
"spf": {
|
|
9345
|
+
"type": "string",
|
|
9346
|
+
"description": "SPF result (e.g. `pass`, `fail`, `softfail`, `none`)."
|
|
9347
|
+
},
|
|
9348
|
+
"dmarc": {
|
|
9349
|
+
"type": "string",
|
|
9350
|
+
"description": "DMARC result (e.g. `pass`, `fail`, `none`)."
|
|
9351
|
+
},
|
|
9352
|
+
"dmarcPolicy": {
|
|
9353
|
+
"type": ["string", "null"],
|
|
9354
|
+
"description": "Published DMARC policy (`none`, `quarantine`, `reject`)."
|
|
9355
|
+
},
|
|
9356
|
+
"dmarcFromDomain": {
|
|
9357
|
+
"type": ["string", "null"],
|
|
9358
|
+
"description": "The From-header domain DMARC was evaluated against."
|
|
9359
|
+
},
|
|
9360
|
+
"dmarcSpfAligned": { "type": "boolean" },
|
|
9361
|
+
"dmarcDkimAligned": { "type": "boolean" },
|
|
9362
|
+
"dmarcSpfStrict": { "type": ["boolean", "null"] },
|
|
9363
|
+
"dmarcDkimStrict": { "type": ["boolean", "null"] },
|
|
9364
|
+
"dkimSignatures": {
|
|
9365
|
+
"type": "array",
|
|
9366
|
+
"items": {
|
|
9367
|
+
"type": "object",
|
|
9368
|
+
"description": "One DKIM signature found on the message, with its verdict.",
|
|
9369
|
+
"properties": {
|
|
9370
|
+
"domain": { "type": "string" },
|
|
9371
|
+
"selector": { "type": "string" },
|
|
9372
|
+
"result": {
|
|
9373
|
+
"type": "string",
|
|
9374
|
+
"description": "Verification result (e.g. `pass`, `fail`, `none`)."
|
|
9375
|
+
},
|
|
9376
|
+
"aligned": {
|
|
9377
|
+
"type": "boolean",
|
|
9378
|
+
"description": "Whether the signing domain aligns with the From domain (for DMARC)."
|
|
9379
|
+
},
|
|
9380
|
+
"keyBits": { "type": ["integer", "null"] },
|
|
9381
|
+
"algo": { "type": ["string", "null"] }
|
|
9382
|
+
},
|
|
9383
|
+
"required": [
|
|
9384
|
+
"domain",
|
|
9385
|
+
"selector",
|
|
9386
|
+
"result",
|
|
9387
|
+
"aligned"
|
|
9388
|
+
]
|
|
9389
|
+
}
|
|
9390
|
+
}
|
|
9391
|
+
},
|
|
9392
|
+
"required": [
|
|
9393
|
+
"spf",
|
|
9394
|
+
"dmarc",
|
|
9395
|
+
"dmarcSpfAligned",
|
|
9396
|
+
"dmarcDkimAligned",
|
|
9397
|
+
"dkimSignatures"
|
|
9398
|
+
]
|
|
9399
|
+
}],
|
|
9400
|
+
"description": "SPF / DKIM / DMARC verdicts computed at ingest, matching\nthe `email.auth` object on the webhook payload. Use these\nto decide how much to trust a message before acting on\ninstructions it contains.\n"
|
|
8876
9401
|
}
|
|
8877
9402
|
},
|
|
8878
9403
|
"required": [
|
|
@@ -8886,7 +9411,9 @@ const operationManifest = [
|
|
|
8886
9411
|
"webhook_attempt_count",
|
|
8887
9412
|
"from_email",
|
|
8888
9413
|
"to_email",
|
|
8889
|
-
"replies"
|
|
9414
|
+
"replies",
|
|
9415
|
+
"parsed",
|
|
9416
|
+
"auth"
|
|
8890
9417
|
]
|
|
8891
9418
|
},
|
|
8892
9419
|
"sdkName": "getEmail",
|
|
@@ -9016,7 +9543,12 @@ const operationManifest = [
|
|
|
9016
9543
|
null
|
|
9017
9544
|
]
|
|
9018
9545
|
},
|
|
9019
|
-
"webhook_attempt_count": { "type": "integer" }
|
|
9546
|
+
"webhook_attempt_count": { "type": "integer" },
|
|
9547
|
+
"thread_id": {
|
|
9548
|
+
"type": ["string", "null"],
|
|
9549
|
+
"format": "uuid",
|
|
9550
|
+
"description": "Conversation thread this message belongs to. Fetch\n`/threads/{thread_id}` for the full ordered thread. NULL on\nmessages received before threading was enabled.\n"
|
|
9551
|
+
}
|
|
9020
9552
|
},
|
|
9021
9553
|
"required": [
|
|
9022
9554
|
"id",
|
|
@@ -9277,7 +9809,12 @@ const operationManifest = [
|
|
|
9277
9809
|
null
|
|
9278
9810
|
]
|
|
9279
9811
|
},
|
|
9280
|
-
"webhook_attempt_count": { "type": "integer" }
|
|
9812
|
+
"webhook_attempt_count": { "type": "integer" },
|
|
9813
|
+
"thread_id": {
|
|
9814
|
+
"type": ["string", "null"],
|
|
9815
|
+
"format": "uuid",
|
|
9816
|
+
"description": "Conversation thread this message belongs to. Fetch\n`/threads/{thread_id}` for the full ordered thread. NULL on\nmessages received before threading was enabled.\n"
|
|
9817
|
+
}
|
|
9281
9818
|
},
|
|
9282
9819
|
"required": [
|
|
9283
9820
|
"id",
|
|
@@ -11523,6 +12060,11 @@ const operationManifest = [
|
|
|
11523
12060
|
"format": "uuid",
|
|
11524
12061
|
"description": "Reference to the inbound `emails.id` that this send\nreplied to, when known. Populated when the caller used\n/emails/{id}/reply or when /send-mail's `in_reply_to`\nmatched a stored inbound message_id in the same org.\n"
|
|
11525
12062
|
},
|
|
12063
|
+
"thread_id": {
|
|
12064
|
+
"type": ["string", "null"],
|
|
12065
|
+
"format": "uuid",
|
|
12066
|
+
"description": "Conversation thread this send belongs to. A reply inherits\nthe thread of the inbound it answers; a fresh send starts a\nnew thread. Fetch `/threads/{thread_id}` for the full\nordered thread (inbound + outbound interleaved). NULL on\ngate-denied sends and on sends created before threading was\nenabled.\n"
|
|
12067
|
+
},
|
|
11526
12068
|
"queue_id": {
|
|
11527
12069
|
"type": ["string", "null"],
|
|
11528
12070
|
"description": "Message identifier assigned by Primitive's outbound\nrelay once the agent accepts the message. Null on\nqueued, gate_denied, and agent_failed rows.\n"
|
|
@@ -11807,6 +12349,11 @@ const operationManifest = [
|
|
|
11807
12349
|
"format": "uuid",
|
|
11808
12350
|
"description": "Reference to the inbound `emails.id` that this send\nreplied to, when known. Populated when the caller used\n/emails/{id}/reply or when /send-mail's `in_reply_to`\nmatched a stored inbound message_id in the same org.\n"
|
|
11809
12351
|
},
|
|
12352
|
+
"thread_id": {
|
|
12353
|
+
"type": ["string", "null"],
|
|
12354
|
+
"format": "uuid",
|
|
12355
|
+
"description": "Conversation thread this send belongs to. A reply inherits\nthe thread of the inbound it answers; a fresh send starts a\nnew thread. Fetch `/threads/{thread_id}` for the full\nordered thread (inbound + outbound interleaved). NULL on\ngate-denied sends and on sends created before threading was\nenabled.\n"
|
|
12356
|
+
},
|
|
11810
12357
|
"queue_id": {
|
|
11811
12358
|
"type": ["string", "null"],
|
|
11812
12359
|
"description": "Message identifier assigned by Primitive's outbound\nrelay once the agent accepts the message. Null on\nqueued, gate_denied, and agent_failed rows.\n"
|
|
@@ -12259,6 +12806,101 @@ const operationManifest = [
|
|
|
12259
12806
|
"tag": "Sending",
|
|
12260
12807
|
"tagCommand": "sending"
|
|
12261
12808
|
},
|
|
12809
|
+
{
|
|
12810
|
+
"binaryResponse": false,
|
|
12811
|
+
"bodyRequired": false,
|
|
12812
|
+
"command": "get-thread",
|
|
12813
|
+
"description": "Returns a conversation thread: its metadata plus the inbound\nand outbound messages that belong to it, interleaved in time\norder (oldest first). A thread spans both received emails and\nyour sends, so an agent can reconstruct an entire back-and-forth\nfrom one call instead of walking reply headers.\n\nEach message carries a `direction` (`inbound` | `outbound`) and\nan `id`; fetch the full message via `/emails/{id}` or\n`/sent-emails/{id}` accordingly. Bodies are omitted here to keep\nthe thread view lightweight.\n\nDiscover a thread id from the `thread_id` field on any email or\nsent-email (list or detail). The message list is capped; compare\n`message_count` against `messages.length` to detect truncation.\n",
|
|
12814
|
+
"hasJsonBody": false,
|
|
12815
|
+
"method": "GET",
|
|
12816
|
+
"operationId": "getThread",
|
|
12817
|
+
"path": "/threads/{id}",
|
|
12818
|
+
"pathParams": [{
|
|
12819
|
+
"description": "Resource UUID",
|
|
12820
|
+
"enum": null,
|
|
12821
|
+
"name": "id",
|
|
12822
|
+
"required": true,
|
|
12823
|
+
"type": "string"
|
|
12824
|
+
}],
|
|
12825
|
+
"queryParams": [],
|
|
12826
|
+
"requestSchema": null,
|
|
12827
|
+
"responseSchema": {
|
|
12828
|
+
"type": "object",
|
|
12829
|
+
"description": "A conversation thread: its metadata plus the inbound and\noutbound messages that belong to it, interleaved oldest-first.\nMembership is the stored `thread_id` on each message. Bodies are\nomitted here to keep the thread view lightweight; fetch\n`/emails/{id}` or `/sent-emails/{id}` for a single message's\nfull content.\n",
|
|
12830
|
+
"properties": {
|
|
12831
|
+
"id": {
|
|
12832
|
+
"type": "string",
|
|
12833
|
+
"format": "uuid"
|
|
12834
|
+
},
|
|
12835
|
+
"subject": {
|
|
12836
|
+
"type": ["string", "null"],
|
|
12837
|
+
"description": "Normalized subject of the thread (Re/Fwd prefixes stripped)."
|
|
12838
|
+
},
|
|
12839
|
+
"root_message_id": {
|
|
12840
|
+
"type": ["string", "null"],
|
|
12841
|
+
"description": "Message-ID of the conversation root, when known."
|
|
12842
|
+
},
|
|
12843
|
+
"message_count": {
|
|
12844
|
+
"type": "integer",
|
|
12845
|
+
"description": "Total messages in the thread. `messages` is capped (most\nrecent first, then re-sorted oldest-first), so\n`message_count > messages.length` signals truncation.\n"
|
|
12846
|
+
},
|
|
12847
|
+
"first_message_at": {
|
|
12848
|
+
"type": ["string", "null"],
|
|
12849
|
+
"format": "date-time"
|
|
12850
|
+
},
|
|
12851
|
+
"last_message_at": {
|
|
12852
|
+
"type": ["string", "null"],
|
|
12853
|
+
"format": "date-time"
|
|
12854
|
+
},
|
|
12855
|
+
"created_at": {
|
|
12856
|
+
"type": "string",
|
|
12857
|
+
"format": "date-time"
|
|
12858
|
+
},
|
|
12859
|
+
"messages": {
|
|
12860
|
+
"type": "array",
|
|
12861
|
+
"items": {
|
|
12862
|
+
"type": "object",
|
|
12863
|
+
"description": "One message in a thread (inbound or outbound).",
|
|
12864
|
+
"properties": {
|
|
12865
|
+
"direction": {
|
|
12866
|
+
"type": "string",
|
|
12867
|
+
"enum": ["inbound", "outbound"],
|
|
12868
|
+
"description": "`inbound` for a received email (`/emails/{id}`), `outbound`\nfor a send (`/sent-emails/{id}`). Use it with `id` to fetch\nfull content from the right endpoint.\n"
|
|
12869
|
+
},
|
|
12870
|
+
"id": {
|
|
12871
|
+
"type": "string",
|
|
12872
|
+
"format": "uuid"
|
|
12873
|
+
},
|
|
12874
|
+
"message_id": { "type": ["string", "null"] },
|
|
12875
|
+
"from": { "type": ["string", "null"] },
|
|
12876
|
+
"to": { "type": ["string", "null"] },
|
|
12877
|
+
"subject": { "type": ["string", "null"] },
|
|
12878
|
+
"status": {
|
|
12879
|
+
"type": ["string", "null"],
|
|
12880
|
+
"description": "Lifecycle status (an EmailStatus or SentEmailStatus value, per `direction`)."
|
|
12881
|
+
},
|
|
12882
|
+
"timestamp": {
|
|
12883
|
+
"type": ["string", "null"],
|
|
12884
|
+
"format": "date-time",
|
|
12885
|
+
"description": "received_at for inbound, created_at for outbound."
|
|
12886
|
+
}
|
|
12887
|
+
},
|
|
12888
|
+
"required": ["direction", "id"]
|
|
12889
|
+
}
|
|
12890
|
+
}
|
|
12891
|
+
},
|
|
12892
|
+
"required": [
|
|
12893
|
+
"id",
|
|
12894
|
+
"message_count",
|
|
12895
|
+
"created_at",
|
|
12896
|
+
"messages"
|
|
12897
|
+
]
|
|
12898
|
+
},
|
|
12899
|
+
"sdkName": "getThread",
|
|
12900
|
+
"summary": "Get a conversation thread by id",
|
|
12901
|
+
"tag": "Threads",
|
|
12902
|
+
"tagCommand": "threads"
|
|
12903
|
+
},
|
|
12262
12904
|
{
|
|
12263
12905
|
"binaryResponse": false,
|
|
12264
12906
|
"bodyRequired": false,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
//#region src/oclif/root-signup-hint.ts
|
|
5
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
6
|
+
function activeConfigDir(env, home) {
|
|
7
|
+
if (env.PRIMITIVE_CONFIG_DIR) return env.PRIMITIVE_CONFIG_DIR;
|
|
8
|
+
return join(env.XDG_CONFIG_HOME || join(home, ".config"), "primitive");
|
|
9
|
+
}
|
|
10
|
+
function shouldShowLoggedOutSignupHint(options = {}) {
|
|
11
|
+
if ((options.argv ?? process.argv.slice(2)).length > 0) return false;
|
|
12
|
+
const env = options.env ?? process.env;
|
|
13
|
+
if (env.PRIMITIVE_HIDE_SIGNUP_HINT === "1") return false;
|
|
14
|
+
if (env.PRIMITIVE_API_KEY?.trim()) return false;
|
|
15
|
+
return !existsSync(join(activeConfigDir(env, options.home ?? homedir()), CREDENTIALS_FILE));
|
|
16
|
+
}
|
|
17
|
+
function loggedOutSignupHint() {
|
|
18
|
+
return [
|
|
19
|
+
"New to Primitive?",
|
|
20
|
+
" You or your user don't have an account yet?",
|
|
21
|
+
" Run `primitive signup <email> --signup-code <invite-code> --accept-terms`",
|
|
22
|
+
" to create an account, get your own domain, and get started now.",
|
|
23
|
+
""
|
|
24
|
+
].join("\n");
|
|
25
|
+
}
|
|
26
|
+
function writeLoggedOutSignupHintIfNeeded(options = {}) {
|
|
27
|
+
if (!shouldShowLoggedOutSignupHint(options)) return;
|
|
28
|
+
(options.write ?? ((message) => process.stdout.write(message)))(loggedOutSignupHint());
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { loggedOutSignupHint, shouldShowLoggedOutSignupHint, writeLoggedOutSignupHintIfNeeded };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitivedotdev/cli",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.8",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -25,8 +25,15 @@
|
|
|
25
25
|
"dirname": "primitive",
|
|
26
26
|
"plugins": [
|
|
27
27
|
"@oclif/plugin-help",
|
|
28
|
-
"@oclif/plugin-autocomplete"
|
|
28
|
+
"@oclif/plugin-autocomplete",
|
|
29
|
+
"@oclif/plugin-warn-if-update-available"
|
|
29
30
|
],
|
|
31
|
+
"warn-if-update-available": {
|
|
32
|
+
"timeoutInDays": 1,
|
|
33
|
+
"frequency": 1,
|
|
34
|
+
"frequencyUnit": "days",
|
|
35
|
+
"message": "Primitive CLI update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>. Run `npm install -g @primitivedotdev/cli@latest` to update."
|
|
36
|
+
},
|
|
30
37
|
"topics": {
|
|
31
38
|
"cli": {
|
|
32
39
|
"description": "CLI authentication"
|
|
@@ -59,6 +66,9 @@
|
|
|
59
66
|
"sent": {
|
|
60
67
|
"description": "Short aliases for outbound sent-email history: `primitive sent list` and `primitive sent get`."
|
|
61
68
|
},
|
|
69
|
+
"threads": {
|
|
70
|
+
"description": "Inspect conversation threads spanning received and sent emails: `primitive threads get --id <thread-id>`."
|
|
71
|
+
},
|
|
62
72
|
"endpoints": {
|
|
63
73
|
"description": "Manage webhook endpoints that receive email events"
|
|
64
74
|
},
|
|
@@ -112,7 +122,8 @@
|
|
|
112
122
|
"dependencies": {
|
|
113
123
|
"@oclif/core": "^4.10.5",
|
|
114
124
|
"@oclif/plugin-autocomplete": "^3.2.45",
|
|
115
|
-
"@oclif/plugin-help": "^6.2.44"
|
|
125
|
+
"@oclif/plugin-help": "^6.2.44",
|
|
126
|
+
"@oclif/plugin-warn-if-update-available": "^3.1.65"
|
|
116
127
|
},
|
|
117
128
|
"devDependencies": {
|
|
118
129
|
"@biomejs/biome": "^2.4.10",
|