@primitivedotdev/sdk 1.18.0 → 1.20.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.
@@ -97,6 +97,10 @@ const openapiDocument = {
97
97
  "name": "Memories",
98
98
  "description": "Durable org-scoped or function-scoped JSON key-value storage for\nagents and functions. Keys are caller-defined. Function scope is\nalways addressed by the function id UUID, not by function name.\n"
99
99
  },
100
+ {
101
+ "name": "Templates",
102
+ "description": "Browse approved Function templates, install deploy-mode templates, and\npoll install progress.\n"
103
+ },
100
104
  {
101
105
  "name": "Registries",
102
106
  "description": "The Agent Registry: ownable directories of agents, addressable by a\nregistry-scoped handle. A registry's publish policy (owner_only, request,\nor open) decides whether a publish lists immediately or pends owner\napproval. An agent is defined once with a globally unique,\nreachability-verified address, then published into any registry under a\nhandle. Discovery reads (list, resolve, get) are public for public\nregistries; managing a registry and moderating requests use the owner's\nAPI key.\n"
@@ -2922,6 +2926,167 @@ const openapiDocument = {
2922
2926
  "429": { "$ref": "#/components/responses/RateLimited" }
2923
2927
  }
2924
2928
  } },
2929
+ "/templates": { "get": {
2930
+ "operationId": "listTemplates",
2931
+ "summary": "List function templates",
2932
+ "description": "List approved Function templates available for browsing and\ninstallation. Results are cacheable and paginated with\n`data.next_cursor`.\n",
2933
+ "tags": ["Templates"],
2934
+ "security": [],
2935
+ "parameters": [
2936
+ {
2937
+ "name": "q",
2938
+ "in": "query",
2939
+ "required": false,
2940
+ "description": "Search templates by title, summary, or slug.",
2941
+ "schema": {
2942
+ "type": "string",
2943
+ "minLength": 1
2944
+ }
2945
+ },
2946
+ {
2947
+ "name": "tag",
2948
+ "in": "query",
2949
+ "required": false,
2950
+ "description": "Filter templates by an exact tag.",
2951
+ "schema": {
2952
+ "type": "string",
2953
+ "minLength": 1
2954
+ }
2955
+ },
2956
+ {
2957
+ "name": "cursor",
2958
+ "in": "query",
2959
+ "required": false,
2960
+ "description": "Cursor from a previous response `data.next_cursor` value.",
2961
+ "schema": { "type": "string" }
2962
+ },
2963
+ {
2964
+ "name": "limit",
2965
+ "in": "query",
2966
+ "required": false,
2967
+ "description": "Maximum number of templates to return. The server caps this at 100.",
2968
+ "schema": {
2969
+ "type": "integer",
2970
+ "minimum": 1,
2971
+ "maximum": 100,
2972
+ "default": 50
2973
+ }
2974
+ }
2975
+ ],
2976
+ "responses": {
2977
+ "200": {
2978
+ "description": "Paginated template registry summaries",
2979
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
2980
+ "type": "object",
2981
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateRegistryPage" } },
2982
+ "required": ["data"]
2983
+ }] } } }
2984
+ },
2985
+ "400": { "$ref": "#/components/responses/ValidationError" },
2986
+ "429": { "$ref": "#/components/responses/RateLimited" }
2987
+ }
2988
+ } },
2989
+ "/templates/{id}": { "get": {
2990
+ "operationId": "getTemplate",
2991
+ "summary": "Get a function template",
2992
+ "description": "Fetch one approved Function template by slug, including its manifest\nsnapshot and README. The stored source files used for install are not\nreturned.\n",
2993
+ "tags": ["Templates"],
2994
+ "security": [],
2995
+ "parameters": [{
2996
+ "name": "id",
2997
+ "in": "path",
2998
+ "required": true,
2999
+ "description": "Template slug from the template manifest.",
3000
+ "schema": {
3001
+ "type": "string",
3002
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$"
3003
+ }
3004
+ }],
3005
+ "responses": {
3006
+ "200": {
3007
+ "description": "Template registry detail",
3008
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3009
+ "type": "object",
3010
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateRegistryDetail" } },
3011
+ "required": ["data"]
3012
+ }] } } }
3013
+ },
3014
+ "400": { "$ref": "#/components/responses/ValidationError" },
3015
+ "404": { "$ref": "#/components/responses/NotFound" },
3016
+ "429": { "$ref": "#/components/responses/RateLimited" }
3017
+ }
3018
+ } },
3019
+ "/templates/{id}/install": { "post": {
3020
+ "operationId": "installTemplate",
3021
+ "summary": "Install a function template",
3022
+ "description": "Start a one-shot deploy of an approved deploy-mode Function template.\nThe response returns an install record immediately; poll\n`GET /templates/installs/{id}` for progress.\n",
3023
+ "tags": ["Templates"],
3024
+ "security": [{ "BearerAuth": [] }],
3025
+ "parameters": [{
3026
+ "name": "id",
3027
+ "in": "path",
3028
+ "required": true,
3029
+ "description": "Template slug from the template manifest.",
3030
+ "schema": {
3031
+ "type": "string",
3032
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$"
3033
+ }
3034
+ }],
3035
+ "requestBody": {
3036
+ "required": true,
3037
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstallTemplateBody" } } }
3038
+ },
3039
+ "responses": {
3040
+ "201": {
3041
+ "description": "Template install started",
3042
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3043
+ "type": "object",
3044
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateInstallStatus" } },
3045
+ "required": ["data"]
3046
+ }] } } }
3047
+ },
3048
+ "400": { "$ref": "#/components/responses/ValidationError" },
3049
+ "401": { "$ref": "#/components/responses/Unauthorized" },
3050
+ "403": { "$ref": "#/components/responses/Forbidden" },
3051
+ "404": { "$ref": "#/components/responses/NotFound" },
3052
+ "409": { "$ref": "#/components/responses/Conflict" },
3053
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" },
3054
+ "429": { "$ref": "#/components/responses/RateLimited" }
3055
+ }
3056
+ } },
3057
+ "/templates/installs/{id}": { "get": {
3058
+ "operationId": "getTemplateInstall",
3059
+ "summary": "Get template install status",
3060
+ "description": "Fetch the current state of a template install. Reads may advance the\nself-test phase when a reply effect has been observed.\n",
3061
+ "tags": ["Templates"],
3062
+ "security": [{ "BearerAuth": [] }],
3063
+ "parameters": [{
3064
+ "name": "id",
3065
+ "in": "path",
3066
+ "required": true,
3067
+ "description": "Template install UUID.",
3068
+ "schema": {
3069
+ "type": "string",
3070
+ "format": "uuid",
3071
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
3072
+ }
3073
+ }],
3074
+ "responses": {
3075
+ "200": {
3076
+ "description": "Current template install status",
3077
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3078
+ "type": "object",
3079
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateInstallStatus" } },
3080
+ "required": ["data"]
3081
+ }] } } }
3082
+ },
3083
+ "400": { "$ref": "#/components/responses/ValidationError" },
3084
+ "401": { "$ref": "#/components/responses/Unauthorized" },
3085
+ "403": { "$ref": "#/components/responses/Forbidden" },
3086
+ "404": { "$ref": "#/components/responses/NotFound" },
3087
+ "429": { "$ref": "#/components/responses/RateLimited" }
3088
+ }
3089
+ } },
2925
3090
  "/x402/payout-addresses": {
2926
3091
  "post": {
2927
3092
  "operationId": "registerPayoutAddress",
@@ -4592,6 +4757,16 @@ const openapiDocument = {
4592
4757
  "org_not_accessible",
4593
4758
  "feature_disabled",
4594
4759
  "memory_conflict",
4760
+ "template_not_installable",
4761
+ "scaffold_only",
4762
+ "invalid_variables",
4763
+ "unknown_secrets",
4764
+ "missing_secrets",
4765
+ "no_inbound_domain",
4766
+ "domain_cannot_send",
4767
+ "address_taken",
4768
+ "route_cap_reached",
4769
+ "name_exhausted",
4595
4770
  "developer_usage_credit_exhausted",
4596
4771
  "no_payout_address",
4597
4772
  "ownership_proof_failed",
@@ -9334,94 +9509,564 @@ const openapiDocument = {
9334
9509
  "key",
9335
9510
  "scope"
9336
9511
  ]
9337
- }
9338
- }
9339
- }
9340
- };
9341
- //#endregion
9342
- //#region ../packages/api-core/src/openapi/operations.generated.ts
9343
- const operationManifest = [
9344
- {
9345
- "binaryResponse": false,
9346
- "bodyRequired": false,
9347
- "command": "get-account",
9348
- "description": null,
9349
- "hasJsonBody": false,
9350
- "method": "GET",
9351
- "operationId": "getAccount",
9352
- "path": "/account",
9353
- "pathParams": [],
9354
- "queryParams": [],
9355
- "requestSchema": null,
9356
- "responseSchema": {
9357
- "type": "object",
9358
- "properties": {
9359
- "id": {
9360
- "type": "string",
9361
- "format": "uuid"
9362
- },
9363
- "email": { "type": "string" },
9364
- "plan": { "type": "string" },
9365
- "limits": {
9366
- "type": "object",
9367
- "description": "Plan-derived quota limits for an account.",
9368
- "properties": {
9369
- "storage_mb": { "type": "number" },
9370
- "send_per_hour": { "type": "number" },
9371
- "send_per_day": { "type": "number" },
9372
- "api_per_minute": { "type": "number" },
9373
- "webhooks_max_global": { "type": ["number", "null"] },
9374
- "webhooks_per_domain": { "type": "boolean" },
9375
- "filters_per_domain": { "type": "boolean" },
9376
- "spam_thresholds_per_domain": { "type": "boolean" }
9512
+ },
9513
+ "TemplateAuthor": {
9514
+ "type": "object",
9515
+ "additionalProperties": false,
9516
+ "properties": {
9517
+ "id": {
9518
+ "type": "string",
9519
+ "minLength": 1
9377
9520
  },
9378
- "required": [
9379
- "storage_mb",
9380
- "send_per_hour",
9381
- "send_per_day",
9382
- "api_per_minute",
9383
- "webhooks_max_global",
9384
- "webhooks_per_domain",
9385
- "filters_per_domain",
9386
- "spam_thresholds_per_domain"
9387
- ]
9388
- },
9389
- "entitlements": {
9390
- "type": "array",
9391
- "items": { "type": "string" },
9392
- "description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
9393
- },
9394
- "managed_inbox_address": {
9395
- "type": ["string", "null"],
9396
- "description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
9521
+ "name": {
9522
+ "type": "string",
9523
+ "minLength": 1
9524
+ },
9525
+ "url": {
9526
+ "type": "string",
9527
+ "format": "uri"
9528
+ }
9397
9529
  },
9398
- "created_at": {
9399
- "type": "string",
9400
- "format": "date-time"
9530
+ "required": ["id", "name"]
9531
+ },
9532
+ "TemplateSource": { "oneOf": [{
9533
+ "type": "object",
9534
+ "additionalProperties": false,
9535
+ "properties": {
9536
+ "mode": {
9537
+ "type": "string",
9538
+ "const": "managed-build"
9539
+ },
9540
+ "dir": {
9541
+ "type": "string",
9542
+ "minLength": 1,
9543
+ "default": "."
9544
+ }
9401
9545
  },
9402
- "onboarding_completed": { "type": "boolean" },
9403
- "onboarding_step": { "type": ["string", "null"] },
9404
- "stripe_subscription_status": { "type": ["string", "null"] },
9405
- "subscription_current_period_end": {
9406
- "type": ["string", "null"],
9407
- "format": "date-time"
9546
+ "required": ["mode", "dir"]
9547
+ }, {
9548
+ "type": "object",
9549
+ "additionalProperties": false,
9550
+ "properties": {
9551
+ "mode": {
9552
+ "type": "string",
9553
+ "const": "bundle"
9554
+ },
9555
+ "file": {
9556
+ "type": "string",
9557
+ "minLength": 1
9558
+ }
9408
9559
  },
9409
- "subscription_cancel_at_period_end": { "type": ["boolean", "null"] },
9410
- "spam_threshold": {
9411
- "type": ["number", "null"],
9412
- "minimum": 0,
9413
- "maximum": 15
9560
+ "required": ["mode", "file"]
9561
+ }] },
9562
+ "TemplateInstall": {
9563
+ "type": "object",
9564
+ "additionalProperties": false,
9565
+ "properties": {
9566
+ "mode": {
9567
+ "type": "string",
9568
+ "enum": ["deploy", "scaffold"]
9569
+ },
9570
+ "editFiles": {
9571
+ "type": "array",
9572
+ "items": {
9573
+ "type": "string",
9574
+ "minLength": 1
9575
+ }
9576
+ },
9577
+ "reason": {
9578
+ "type": "string",
9579
+ "default": ""
9580
+ }
9414
9581
  },
9415
- "discard_content_on_webhook_confirmed": { "type": "boolean" },
9416
- "webhook_secret_rotated_at": {
9417
- "type": ["string", "null"],
9418
- "format": "date-time"
9419
- }
9582
+ "required": [
9583
+ "mode",
9584
+ "editFiles",
9585
+ "reason"
9586
+ ]
9420
9587
  },
9421
- "required": [
9422
- "id",
9423
- "email",
9424
- "plan",
9588
+ "TemplateSecret": {
9589
+ "type": "object",
9590
+ "additionalProperties": false,
9591
+ "properties": {
9592
+ "key": {
9593
+ "type": "string",
9594
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
9595
+ },
9596
+ "required": {
9597
+ "type": "boolean",
9598
+ "default": true
9599
+ },
9600
+ "description": { "type": "string" }
9601
+ },
9602
+ "required": ["key", "required"]
9603
+ },
9604
+ "TemplateSecretGroup": {
9605
+ "type": "object",
9606
+ "additionalProperties": false,
9607
+ "properties": {
9608
+ "keys": {
9609
+ "type": "array",
9610
+ "minItems": 2,
9611
+ "items": {
9612
+ "type": "string",
9613
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
9614
+ }
9615
+ },
9616
+ "min": {
9617
+ "type": "integer",
9618
+ "minimum": 1,
9619
+ "default": 1
9620
+ },
9621
+ "description": { "type": "string" }
9622
+ },
9623
+ "required": ["keys", "min"]
9624
+ },
9625
+ "TemplateVariableValidation": {
9626
+ "type": "object",
9627
+ "additionalProperties": false,
9628
+ "properties": {
9629
+ "pattern": {
9630
+ "type": "string",
9631
+ "minLength": 1
9632
+ },
9633
+ "maxLength": {
9634
+ "type": "integer",
9635
+ "minimum": 1
9636
+ }
9637
+ }
9638
+ },
9639
+ "TemplateVariable": {
9640
+ "type": "object",
9641
+ "additionalProperties": false,
9642
+ "properties": {
9643
+ "key": {
9644
+ "type": "string",
9645
+ "minLength": 1
9646
+ },
9647
+ "prompt": {
9648
+ "type": "string",
9649
+ "minLength": 1
9650
+ },
9651
+ "default": { "type": "string" },
9652
+ "file": {
9653
+ "type": "string",
9654
+ "minLength": 1
9655
+ },
9656
+ "type": {
9657
+ "type": "string",
9658
+ "enum": [
9659
+ "string",
9660
+ "select",
9661
+ "url",
9662
+ "email"
9663
+ ],
9664
+ "default": "string"
9665
+ },
9666
+ "options": {
9667
+ "type": "array",
9668
+ "items": {
9669
+ "type": "string",
9670
+ "minLength": 1
9671
+ }
9672
+ },
9673
+ "validation": { "$ref": "#/components/schemas/TemplateVariableValidation" }
9674
+ },
9675
+ "required": [
9676
+ "key",
9677
+ "prompt",
9678
+ "type"
9679
+ ]
9680
+ },
9681
+ "TemplateSetup": {
9682
+ "type": "object",
9683
+ "additionalProperties": false,
9684
+ "properties": {
9685
+ "agent": {
9686
+ "type": "string",
9687
+ "minLength": 1
9688
+ },
9689
+ "prompt": {
9690
+ "type": "string",
9691
+ "minLength": 1
9692
+ },
9693
+ "produces": {
9694
+ "type": "array",
9695
+ "items": {
9696
+ "type": "string",
9697
+ "minLength": 1
9698
+ }
9699
+ }
9700
+ },
9701
+ "required": [
9702
+ "agent",
9703
+ "prompt",
9704
+ "produces"
9705
+ ]
9706
+ },
9707
+ "TemplateManifest": {
9708
+ "type": "object",
9709
+ "additionalProperties": false,
9710
+ "properties": {
9711
+ "schemaVersion": {
9712
+ "type": "integer",
9713
+ "const": 1
9714
+ },
9715
+ "id": {
9716
+ "type": "string",
9717
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
9718
+ "description": "Stable template slug from the manifest."
9719
+ },
9720
+ "title": {
9721
+ "type": "string",
9722
+ "minLength": 1
9723
+ },
9724
+ "summary": {
9725
+ "type": "string",
9726
+ "minLength": 1
9727
+ },
9728
+ "description": { "type": "string" },
9729
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
9730
+ "tags": {
9731
+ "type": "array",
9732
+ "items": {
9733
+ "type": "string",
9734
+ "minLength": 1
9735
+ }
9736
+ },
9737
+ "source": { "$ref": "#/components/schemas/TemplateSource" },
9738
+ "install": { "$ref": "#/components/schemas/TemplateInstall" },
9739
+ "secrets": {
9740
+ "type": "array",
9741
+ "items": { "$ref": "#/components/schemas/TemplateSecret" }
9742
+ },
9743
+ "secretGroups": {
9744
+ "type": "array",
9745
+ "items": { "$ref": "#/components/schemas/TemplateSecretGroup" }
9746
+ },
9747
+ "variables": {
9748
+ "type": "array",
9749
+ "items": { "$ref": "#/components/schemas/TemplateVariable" }
9750
+ },
9751
+ "setup": { "$ref": "#/components/schemas/TemplateSetup" },
9752
+ "postInstall": { "type": "string" }
9753
+ },
9754
+ "required": [
9755
+ "schemaVersion",
9756
+ "id",
9757
+ "title",
9758
+ "summary",
9759
+ "author",
9760
+ "tags",
9761
+ "source",
9762
+ "install",
9763
+ "secrets",
9764
+ "secretGroups",
9765
+ "variables"
9766
+ ]
9767
+ },
9768
+ "TemplateRegistryStatus": {
9769
+ "type": "string",
9770
+ "enum": [
9771
+ "pending",
9772
+ "approved",
9773
+ "rejected"
9774
+ ]
9775
+ },
9776
+ "TemplateRegistrySummary": {
9777
+ "type": "object",
9778
+ "properties": {
9779
+ "id": {
9780
+ "type": "string",
9781
+ "format": "uuid"
9782
+ },
9783
+ "slug": {
9784
+ "type": "string",
9785
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
9786
+ "description": "Stable template slug used in template URLs and install commands."
9787
+ },
9788
+ "title": { "type": "string" },
9789
+ "summary": { "type": "string" },
9790
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
9791
+ "tags": {
9792
+ "type": "array",
9793
+ "items": { "type": "string" }
9794
+ },
9795
+ "verified": { "type": "boolean" },
9796
+ "install_count": {
9797
+ "type": "integer",
9798
+ "minimum": 0
9799
+ },
9800
+ "github_repo": {
9801
+ "type": "string",
9802
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
9803
+ "description": "GitHub repository in owner/repo form."
9804
+ },
9805
+ "created_at": {
9806
+ "type": "string",
9807
+ "format": "date-time"
9808
+ },
9809
+ "updated_at": {
9810
+ "type": "string",
9811
+ "format": "date-time"
9812
+ }
9813
+ },
9814
+ "required": [
9815
+ "id",
9816
+ "slug",
9817
+ "title",
9818
+ "summary",
9819
+ "author",
9820
+ "tags",
9821
+ "verified",
9822
+ "install_count",
9823
+ "github_repo",
9824
+ "created_at",
9825
+ "updated_at"
9826
+ ]
9827
+ },
9828
+ "TemplateRegistryDetail": {
9829
+ "type": "object",
9830
+ "properties": {
9831
+ "id": {
9832
+ "type": "string",
9833
+ "format": "uuid"
9834
+ },
9835
+ "slug": {
9836
+ "type": "string",
9837
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
9838
+ "description": "Stable template slug used in template URLs and install commands."
9839
+ },
9840
+ "title": { "type": "string" },
9841
+ "summary": { "type": "string" },
9842
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
9843
+ "tags": {
9844
+ "type": "array",
9845
+ "items": { "type": "string" }
9846
+ },
9847
+ "verified": { "type": "boolean" },
9848
+ "install_count": {
9849
+ "type": "integer",
9850
+ "minimum": 0
9851
+ },
9852
+ "github_repo": {
9853
+ "type": "string",
9854
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
9855
+ "description": "GitHub repository in owner/repo form."
9856
+ },
9857
+ "created_at": {
9858
+ "type": "string",
9859
+ "format": "date-time"
9860
+ },
9861
+ "updated_at": {
9862
+ "type": "string",
9863
+ "format": "date-time"
9864
+ },
9865
+ "description": { "type": ["string", "null"] },
9866
+ "github_sha": { "type": "string" },
9867
+ "github_path": { "type": ["string", "null"] },
9868
+ "manifest": { "$ref": "#/components/schemas/TemplateManifest" },
9869
+ "readme": { "type": ["string", "null"] },
9870
+ "status": { "$ref": "#/components/schemas/TemplateRegistryStatus" }
9871
+ },
9872
+ "required": [
9873
+ "id",
9874
+ "slug",
9875
+ "title",
9876
+ "summary",
9877
+ "author",
9878
+ "tags",
9879
+ "verified",
9880
+ "install_count",
9881
+ "github_repo",
9882
+ "created_at",
9883
+ "updated_at",
9884
+ "description",
9885
+ "github_sha",
9886
+ "github_path",
9887
+ "manifest",
9888
+ "readme",
9889
+ "status"
9890
+ ]
9891
+ },
9892
+ "TemplateRegistryPage": {
9893
+ "type": "object",
9894
+ "properties": {
9895
+ "items": {
9896
+ "type": "array",
9897
+ "items": { "$ref": "#/components/schemas/TemplateRegistrySummary" }
9898
+ },
9899
+ "next_cursor": {
9900
+ "type": ["string", "null"],
9901
+ "description": "Cursor to pass as the next `cursor` query value, or null when there are no more templates."
9902
+ }
9903
+ },
9904
+ "required": ["items", "next_cursor"]
9905
+ },
9906
+ "InstallTemplateBody": {
9907
+ "type": "object",
9908
+ "additionalProperties": false,
9909
+ "properties": {
9910
+ "address": {
9911
+ "type": "string",
9912
+ "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
9913
+ "description": "Localpart to claim on the selected inbound domain. Defaults to the template slug."
9914
+ },
9915
+ "domain": {
9916
+ "type": "string",
9917
+ "minLength": 3,
9918
+ "description": "Org domain name to claim the address on. Defaults to the org's newest active domain."
9919
+ },
9920
+ "variables": {
9921
+ "type": "object",
9922
+ "additionalProperties": { "type": "string" },
9923
+ "description": "Template variable values keyed by manifest variable key."
9924
+ },
9925
+ "secrets": {
9926
+ "type": "object",
9927
+ "additionalProperties": { "type": "string" },
9928
+ "description": "Secret values keyed by manifest secret key."
9929
+ }
9930
+ }
9931
+ },
9932
+ "TemplateInstallState": {
9933
+ "type": "string",
9934
+ "enum": [
9935
+ "deploying",
9936
+ "connecting",
9937
+ "bound",
9938
+ "tested",
9939
+ "deploy_failed",
9940
+ "bind_failed",
9941
+ "test_failed"
9942
+ ]
9943
+ },
9944
+ "TemplateInstallStatus": {
9945
+ "type": "object",
9946
+ "properties": {
9947
+ "id": {
9948
+ "type": "string",
9949
+ "format": "uuid"
9950
+ },
9951
+ "template_slug": {
9952
+ "type": "string",
9953
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
9954
+ "description": "Template slug for this install."
9955
+ },
9956
+ "state": { "$ref": "#/components/schemas/TemplateInstallState" },
9957
+ "address": { "type": ["string", "null"] },
9958
+ "function_id": {
9959
+ "type": ["string", "null"],
9960
+ "format": "uuid"
9961
+ },
9962
+ "error": { "type": ["string", "null"] },
9963
+ "created_at": {
9964
+ "type": "string",
9965
+ "format": "date-time"
9966
+ },
9967
+ "updated_at": {
9968
+ "type": "string",
9969
+ "format": "date-time"
9970
+ }
9971
+ },
9972
+ "required": [
9973
+ "id",
9974
+ "template_slug",
9975
+ "state",
9976
+ "address",
9977
+ "function_id",
9978
+ "error",
9979
+ "created_at",
9980
+ "updated_at"
9981
+ ]
9982
+ }
9983
+ }
9984
+ }
9985
+ };
9986
+ //#endregion
9987
+ //#region ../packages/api-core/src/openapi/operations.generated.ts
9988
+ const operationManifest = [
9989
+ {
9990
+ "binaryResponse": false,
9991
+ "bodyRequired": false,
9992
+ "command": "get-account",
9993
+ "description": null,
9994
+ "hasJsonBody": false,
9995
+ "method": "GET",
9996
+ "operationId": "getAccount",
9997
+ "path": "/account",
9998
+ "pathParams": [],
9999
+ "queryParams": [],
10000
+ "requestSchema": null,
10001
+ "responseSchema": {
10002
+ "type": "object",
10003
+ "properties": {
10004
+ "id": {
10005
+ "type": "string",
10006
+ "format": "uuid"
10007
+ },
10008
+ "email": { "type": "string" },
10009
+ "plan": { "type": "string" },
10010
+ "limits": {
10011
+ "type": "object",
10012
+ "description": "Plan-derived quota limits for an account.",
10013
+ "properties": {
10014
+ "storage_mb": { "type": "number" },
10015
+ "send_per_hour": { "type": "number" },
10016
+ "send_per_day": { "type": "number" },
10017
+ "api_per_minute": { "type": "number" },
10018
+ "webhooks_max_global": { "type": ["number", "null"] },
10019
+ "webhooks_per_domain": { "type": "boolean" },
10020
+ "filters_per_domain": { "type": "boolean" },
10021
+ "spam_thresholds_per_domain": { "type": "boolean" }
10022
+ },
10023
+ "required": [
10024
+ "storage_mb",
10025
+ "send_per_hour",
10026
+ "send_per_day",
10027
+ "api_per_minute",
10028
+ "webhooks_max_global",
10029
+ "webhooks_per_domain",
10030
+ "filters_per_domain",
10031
+ "spam_thresholds_per_domain"
10032
+ ]
10033
+ },
10034
+ "entitlements": {
10035
+ "type": "array",
10036
+ "items": { "type": "string" },
10037
+ "description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
10038
+ },
10039
+ "managed_inbox_address": {
10040
+ "type": ["string", "null"],
10041
+ "description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
10042
+ },
10043
+ "created_at": {
10044
+ "type": "string",
10045
+ "format": "date-time"
10046
+ },
10047
+ "onboarding_completed": { "type": "boolean" },
10048
+ "onboarding_step": { "type": ["string", "null"] },
10049
+ "stripe_subscription_status": { "type": ["string", "null"] },
10050
+ "subscription_current_period_end": {
10051
+ "type": ["string", "null"],
10052
+ "format": "date-time"
10053
+ },
10054
+ "subscription_cancel_at_period_end": { "type": ["boolean", "null"] },
10055
+ "spam_threshold": {
10056
+ "type": ["number", "null"],
10057
+ "minimum": 0,
10058
+ "maximum": 15
10059
+ },
10060
+ "discard_content_on_webhook_confirmed": { "type": "boolean" },
10061
+ "webhook_secret_rotated_at": {
10062
+ "type": ["string", "null"],
10063
+ "format": "date-time"
10064
+ }
10065
+ },
10066
+ "required": [
10067
+ "id",
10068
+ "email",
10069
+ "plan",
9425
10070
  "limits",
9426
10071
  "entitlements",
9427
10072
  "managed_inbox_address",
@@ -18577,7 +19222,206 @@ const operationManifest = [
18577
19222
  "required": ["filename", "content_base64"]
18578
19223
  }
18579
19224
  }
18580
- }
19225
+ }
19226
+ },
19227
+ "responseSchema": {
19228
+ "type": "object",
19229
+ "properties": {
19230
+ "id": {
19231
+ "type": "string",
19232
+ "description": "Persisted sent-email attempt ID."
19233
+ },
19234
+ "status": {
19235
+ "type": "string",
19236
+ "description": "Lifecycle status of a sent_emails row. Possible values:\n\n - `queued`: pre-call INSERT; the outbound agent has not\n yet replied.\n - `submitted_to_agent`: agent accepted; `queue_id` is set.\n - `agent_failed`: agent rejected; `error_code` and\n `error_message` carry the reason.\n - `gate_denied`: a recipient-scope gate denied the send;\n the agent was never called. The `gates` array carries\n the denial detail. /send-mail returns 403 in this case\n so callers see the denial synchronously; /sent-emails\n additionally records the row for historical lookup,\n which is when this status appears in a listing.\n - `unknown`: terminal indeterminate; the on-box log\n poller couldn't classify the receiver's response.\n - `delivered` / `bounced` / `deferred` / `wait_timeout`:\n terminal delivery outcomes (see DeliveryStatus).\n",
19237
+ "enum": [
19238
+ "queued",
19239
+ "submitted_to_agent",
19240
+ "agent_failed",
19241
+ "gate_denied",
19242
+ "unknown",
19243
+ "delivered",
19244
+ "bounced",
19245
+ "deferred",
19246
+ "wait_timeout"
19247
+ ]
19248
+ },
19249
+ "from": {
19250
+ "type": "string",
19251
+ "description": "Bare from-address actually written on the wire. Echoed\non every success branch so callers can confirm what\nwent out, particularly useful for the /emails/{id}/reply\npath where `from` is server-derived from the inbound's\nrecipient when the caller doesn't override.\n\nFor sends where the caller passed a from-header that\nincluded a display name (e.g. `\"Acme Support\" <support@acme.test>`),\nthis field is the parsed bare address (`support@acme.test`).\nThe display name was sent on the wire intact; this field\njust makes the address easy to compare against allowlists.\n"
19252
+ },
19253
+ "queue_id": {
19254
+ "type": ["string", "null"],
19255
+ "description": "Message identifier assigned by Primitive's OUTBOUND relay\n(the box that signs your mail and submits it to the\nreceiving MTA). NOT the receiver's queue id.\n\nThe receiver may also report its own queue id in\n`smtp_response_text` (e.g. `\"250 2.0.0 Ok: queued as\n99D111927CDA\"` from a Postfix receiver). Those two ids\nrefer to different mail systems and are NOT comparable.\nTreat `queue_id` as Primitive-internal and the\nreceiver's id as remote-system-internal.\n\nNull on rows that never reached the relay (queued,\ngate_denied, agent_failed before signing).\n"
19256
+ },
19257
+ "accepted": {
19258
+ "type": "array",
19259
+ "items": { "type": "string" },
19260
+ "description": "Recipient addresses accepted by the relay."
19261
+ },
19262
+ "rejected": {
19263
+ "type": "array",
19264
+ "items": { "type": "string" },
19265
+ "description": "Recipient addresses rejected by the relay."
19266
+ },
19267
+ "client_idempotency_key": {
19268
+ "type": "string",
19269
+ "description": "Effective idempotency key used for this send."
19270
+ },
19271
+ "request_id": {
19272
+ "type": "string",
19273
+ "description": "Server-issued request identifier for support and tracing."
19274
+ },
19275
+ "content_hash": {
19276
+ "type": "string",
19277
+ "description": "Stable hash of the canonical send payload."
19278
+ },
19279
+ "delivery_status": {
19280
+ "type": "string",
19281
+ "description": "Narrower enum covering only the four terminal delivery\noutcomes returned to a synchronous `wait: true` send.\n\nOn the SendMailResult shape, `delivery_status` is always\nequal to `status` whenever both are present (i.e. on\nterminal-state replays and live wait=true responses).\nThe two fields exist so callers that want to type-narrow\non \"this is a delivery outcome\" can pattern-match against\nthe four-value enum without handling the broader\nSentEmailStatus value set (which also covers `queued`,\n`submitted_to_agent`, `agent_failed`, `gate_denied`,\n`unknown`).\n\nOn async-mode and pre-terminal responses, `delivery_status`\nis absent and only `status` is populated. Use `status` if\nyou want a single field that's always present.\n",
19282
+ "enum": [
19283
+ "delivered",
19284
+ "bounced",
19285
+ "deferred",
19286
+ "wait_timeout"
19287
+ ]
19288
+ },
19289
+ "smtp_response_code": {
19290
+ "type": ["integer", "null"],
19291
+ "description": "SMTP response code from the first downstream delivery outcome when wait is true."
19292
+ },
19293
+ "smtp_response_text": {
19294
+ "type": "string",
19295
+ "description": "SMTP response text from the first downstream delivery outcome when wait is true."
19296
+ },
19297
+ "idempotent_replay": {
19298
+ "type": "boolean",
19299
+ "description": "True when the response replays a previously-recorded send\nkeyed by `client_idempotency_key` (same key, same canonical\npayload). False on a fresh send and on gate-denied\nresponses. Lets callers branch on cache state without\ndiffing fields.\n"
19300
+ }
19301
+ },
19302
+ "required": [
19303
+ "id",
19304
+ "status",
19305
+ "from",
19306
+ "queue_id",
19307
+ "accepted",
19308
+ "rejected",
19309
+ "client_idempotency_key",
19310
+ "request_id",
19311
+ "content_hash",
19312
+ "idempotent_replay"
19313
+ ]
19314
+ },
19315
+ "sdkName": "replyToEmail",
19316
+ "summary": "Reply to an inbound email",
19317
+ "tag": "Sending",
19318
+ "tagCommand": "sending"
19319
+ },
19320
+ {
19321
+ "binaryResponse": false,
19322
+ "bodyRequired": true,
19323
+ "command": "send-email",
19324
+ "description": "Sends an outbound email through Primitive's outbound relay. By default\nthe request returns once the relay accepts the message for delivery.\nSet `wait: true` to wait for the first downstream SMTP delivery outcome.\n\n**Host routing.** /send-mail is served by the canonical API host\n(`https://api.primitive.dev/v1`) so the request body can carry\ninline attachments up to ~30 MiB raw. The legacy dashboard\ncompatibility host (`https://www.primitive.dev/api/v1`) also accepts\n/send-mail, but Vercel request body limits apply before proxying.\nThe typed SDKs route /send-mail to the canonical API host\nautomatically.\n",
19325
+ "hasJsonBody": true,
19326
+ "method": "POST",
19327
+ "operationId": "sendEmail",
19328
+ "path": "/send-mail",
19329
+ "pathParams": [],
19330
+ "queryParams": [],
19331
+ "requestSchema": {
19332
+ "type": "object",
19333
+ "additionalProperties": false,
19334
+ "properties": {
19335
+ "from": {
19336
+ "type": "string",
19337
+ "minLength": 3,
19338
+ "maxLength": 998,
19339
+ "description": "RFC 5322 From header. The sender domain must be a verified outbound domain for your organization."
19340
+ },
19341
+ "to": {
19342
+ "type": "string",
19343
+ "minLength": 3,
19344
+ "maxLength": 320,
19345
+ "description": "Recipient address. Recipient eligibility depends on your account's outbound entitlements."
19346
+ },
19347
+ "subject": {
19348
+ "type": "string",
19349
+ "minLength": 1,
19350
+ "maxLength": 998,
19351
+ "description": "Subject line for the outbound message"
19352
+ },
19353
+ "body_text": {
19354
+ "type": "string",
19355
+ "description": "Plain-text message body. At least one of body_text or body_html is required. The combined UTF-8 byte length of body_text and body_html must be at most 262144 bytes."
19356
+ },
19357
+ "body_html": {
19358
+ "type": "string",
19359
+ "description": "HTML message body. At least one of body_text or body_html is required. The combined UTF-8 byte length of body_text and body_html must be at most 262144 bytes."
19360
+ },
19361
+ "in_reply_to": {
19362
+ "type": "string",
19363
+ "minLength": 1,
19364
+ "maxLength": 998,
19365
+ "pattern": "^[^\\x00-\\x1F\\x7F]+$",
19366
+ "description": "Message-ID of the direct parent email when sending a threaded reply."
19367
+ },
19368
+ "references": {
19369
+ "type": "array",
19370
+ "maxItems": 100,
19371
+ "description": "Full ordered message-id chain for the thread.",
19372
+ "items": {
19373
+ "type": "string",
19374
+ "minLength": 1,
19375
+ "maxLength": 998,
19376
+ "pattern": "^[^\\x00-\\x1F\\x7F]+$"
19377
+ }
19378
+ },
19379
+ "attachments": {
19380
+ "type": "array",
19381
+ "maxItems": 100,
19382
+ "description": "Inline attachments. Send requests with attachments to https://api.primitive.dev/v1/send-mail. Combined raw decoded attachment bytes must be at most 31457280.",
19383
+ "items": {
19384
+ "type": "object",
19385
+ "additionalProperties": false,
19386
+ "properties": {
19387
+ "filename": {
19388
+ "type": "string",
19389
+ "minLength": 1,
19390
+ "maxLength": 255,
19391
+ "description": "Attachment filename. Control characters are rejected."
19392
+ },
19393
+ "content_type": {
19394
+ "type": "string",
19395
+ "minLength": 1,
19396
+ "maxLength": 255,
19397
+ "description": "Optional MIME content type. Control characters are rejected."
19398
+ },
19399
+ "content_base64": {
19400
+ "type": "string",
19401
+ "minLength": 1,
19402
+ "maxLength": 44040192,
19403
+ "description": "Base64-encoded attachment bytes."
19404
+ }
19405
+ },
19406
+ "required": ["filename", "content_base64"]
19407
+ }
19408
+ },
19409
+ "wait": {
19410
+ "type": "boolean",
19411
+ "description": "When true, wait for the first downstream SMTP delivery outcome before returning."
19412
+ },
19413
+ "wait_timeout_ms": {
19414
+ "type": "integer",
19415
+ "minimum": 1e3,
19416
+ "maximum": 3e4,
19417
+ "description": "Maximum time to wait for a delivery outcome when wait is true. Defaults to 30000."
19418
+ }
19419
+ },
19420
+ "required": [
19421
+ "from",
19422
+ "to",
19423
+ "subject"
19424
+ ]
18581
19425
  },
18582
19426
  "responseSchema": {
18583
19427
  "type": "object",
@@ -18667,209 +19511,671 @@ const operationManifest = [
18667
19511
  "idempotent_replay"
18668
19512
  ]
18669
19513
  },
18670
- "sdkName": "replyToEmail",
18671
- "summary": "Reply to an inbound email",
19514
+ "sdkName": "sendEmail",
19515
+ "summary": "Send outbound email",
18672
19516
  "tag": "Sending",
18673
19517
  "tagCommand": "sending"
18674
19518
  },
18675
19519
  {
18676
19520
  "binaryResponse": false,
18677
- "bodyRequired": true,
18678
- "command": "send-email",
18679
- "description": "Sends an outbound email through Primitive's outbound relay. By default\nthe request returns once the relay accepts the message for delivery.\nSet `wait: true` to wait for the first downstream SMTP delivery outcome.\n\n**Host routing.** /send-mail is served by the canonical API host\n(`https://api.primitive.dev/v1`) so the request body can carry\ninline attachments up to ~30 MiB raw. The legacy dashboard\ncompatibility host (`https://www.primitive.dev/api/v1`) also accepts\n/send-mail, but Vercel request body limits apply before proxying.\nThe typed SDKs route /send-mail to the canonical API host\nautomatically.\n",
18680
- "hasJsonBody": true,
18681
- "method": "POST",
18682
- "operationId": "sendEmail",
18683
- "path": "/send-mail",
18684
- "pathParams": [],
19521
+ "bodyRequired": false,
19522
+ "command": "get-template",
19523
+ "description": "Fetch one approved Function template by slug, including its manifest\nsnapshot and README. The stored source files used for install are not\nreturned.\n",
19524
+ "hasJsonBody": false,
19525
+ "method": "GET",
19526
+ "operationId": "getTemplate",
19527
+ "path": "/templates/{id}",
19528
+ "pathParams": [{
19529
+ "description": "Template slug from the template manifest.",
19530
+ "enum": null,
19531
+ "name": "id",
19532
+ "required": true,
19533
+ "type": "string"
19534
+ }],
18685
19535
  "queryParams": [],
18686
- "requestSchema": {
19536
+ "requestSchema": null,
19537
+ "responseSchema": {
18687
19538
  "type": "object",
18688
- "additionalProperties": false,
18689
19539
  "properties": {
18690
- "from": {
19540
+ "id": {
18691
19541
  "type": "string",
18692
- "minLength": 3,
18693
- "maxLength": 998,
18694
- "description": "RFC 5322 From header. The sender domain must be a verified outbound domain for your organization."
19542
+ "format": "uuid"
18695
19543
  },
18696
- "to": {
19544
+ "slug": {
18697
19545
  "type": "string",
18698
- "minLength": 3,
18699
- "maxLength": 320,
18700
- "description": "Recipient address. Recipient eligibility depends on your account's outbound entitlements."
19546
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
19547
+ "description": "Stable template slug used in template URLs and install commands."
18701
19548
  },
18702
- "subject": {
18703
- "type": "string",
18704
- "minLength": 1,
18705
- "maxLength": 998,
18706
- "description": "Subject line for the outbound message"
19549
+ "title": { "type": "string" },
19550
+ "summary": { "type": "string" },
19551
+ "author": {
19552
+ "type": "object",
19553
+ "additionalProperties": false,
19554
+ "properties": {
19555
+ "id": {
19556
+ "type": "string",
19557
+ "minLength": 1
19558
+ },
19559
+ "name": {
19560
+ "type": "string",
19561
+ "minLength": 1
19562
+ },
19563
+ "url": {
19564
+ "type": "string",
19565
+ "format": "uri"
19566
+ }
19567
+ },
19568
+ "required": ["id", "name"]
18707
19569
  },
18708
- "body_text": {
18709
- "type": "string",
18710
- "description": "Plain-text message body. At least one of body_text or body_html is required. The combined UTF-8 byte length of body_text and body_html must be at most 262144 bytes."
19570
+ "tags": {
19571
+ "type": "array",
19572
+ "items": { "type": "string" }
18711
19573
  },
18712
- "body_html": {
19574
+ "verified": { "type": "boolean" },
19575
+ "install_count": {
19576
+ "type": "integer",
19577
+ "minimum": 0
19578
+ },
19579
+ "github_repo": {
18713
19580
  "type": "string",
18714
- "description": "HTML message body. At least one of body_text or body_html is required. The combined UTF-8 byte length of body_text and body_html must be at most 262144 bytes."
19581
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
19582
+ "description": "GitHub repository in owner/repo form."
18715
19583
  },
18716
- "in_reply_to": {
19584
+ "created_at": {
18717
19585
  "type": "string",
18718
- "minLength": 1,
18719
- "maxLength": 998,
18720
- "pattern": "^[^\\x00-\\x1F\\x7F]+$",
18721
- "description": "Message-ID of the direct parent email when sending a threaded reply."
19586
+ "format": "date-time"
18722
19587
  },
18723
- "references": {
18724
- "type": "array",
18725
- "maxItems": 100,
18726
- "description": "Full ordered message-id chain for the thread.",
18727
- "items": {
18728
- "type": "string",
18729
- "minLength": 1,
18730
- "maxLength": 998,
18731
- "pattern": "^[^\\x00-\\x1F\\x7F]+$"
18732
- }
19588
+ "updated_at": {
19589
+ "type": "string",
19590
+ "format": "date-time"
18733
19591
  },
18734
- "attachments": {
18735
- "type": "array",
18736
- "maxItems": 100,
18737
- "description": "Inline attachments. Send requests with attachments to https://api.primitive.dev/v1/send-mail. Combined raw decoded attachment bytes must be at most 31457280.",
18738
- "items": {
18739
- "type": "object",
18740
- "additionalProperties": false,
18741
- "properties": {
18742
- "filename": {
18743
- "type": "string",
18744
- "minLength": 1,
18745
- "maxLength": 255,
18746
- "description": "Attachment filename. Control characters are rejected."
19592
+ "description": { "type": ["string", "null"] },
19593
+ "github_sha": { "type": "string" },
19594
+ "github_path": { "type": ["string", "null"] },
19595
+ "manifest": {
19596
+ "type": "object",
19597
+ "additionalProperties": false,
19598
+ "properties": {
19599
+ "schemaVersion": {
19600
+ "type": "integer",
19601
+ "const": 1
19602
+ },
19603
+ "id": {
19604
+ "type": "string",
19605
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
19606
+ "description": "Stable template slug from the manifest."
19607
+ },
19608
+ "title": {
19609
+ "type": "string",
19610
+ "minLength": 1
19611
+ },
19612
+ "summary": {
19613
+ "type": "string",
19614
+ "minLength": 1
19615
+ },
19616
+ "description": { "type": "string" },
19617
+ "author": {
19618
+ "type": "object",
19619
+ "additionalProperties": false,
19620
+ "properties": {
19621
+ "id": {
19622
+ "type": "string",
19623
+ "minLength": 1
19624
+ },
19625
+ "name": {
19626
+ "type": "string",
19627
+ "minLength": 1
19628
+ },
19629
+ "url": {
19630
+ "type": "string",
19631
+ "format": "uri"
19632
+ }
18747
19633
  },
18748
- "content_type": {
19634
+ "required": ["id", "name"]
19635
+ },
19636
+ "tags": {
19637
+ "type": "array",
19638
+ "items": {
18749
19639
  "type": "string",
18750
- "minLength": 1,
18751
- "maxLength": 255,
18752
- "description": "Optional MIME content type. Control characters are rejected."
19640
+ "minLength": 1
19641
+ }
19642
+ },
19643
+ "source": { "oneOf": [{
19644
+ "type": "object",
19645
+ "additionalProperties": false,
19646
+ "properties": {
19647
+ "mode": {
19648
+ "type": "string",
19649
+ "const": "managed-build"
19650
+ },
19651
+ "dir": {
19652
+ "type": "string",
19653
+ "minLength": 1,
19654
+ "default": "."
19655
+ }
18753
19656
  },
18754
- "content_base64": {
18755
- "type": "string",
18756
- "minLength": 1,
18757
- "maxLength": 44040192,
18758
- "description": "Base64-encoded attachment bytes."
19657
+ "required": ["mode", "dir"]
19658
+ }, {
19659
+ "type": "object",
19660
+ "additionalProperties": false,
19661
+ "properties": {
19662
+ "mode": {
19663
+ "type": "string",
19664
+ "const": "bundle"
19665
+ },
19666
+ "file": {
19667
+ "type": "string",
19668
+ "minLength": 1
19669
+ }
19670
+ },
19671
+ "required": ["mode", "file"]
19672
+ }] },
19673
+ "install": {
19674
+ "type": "object",
19675
+ "additionalProperties": false,
19676
+ "properties": {
19677
+ "mode": {
19678
+ "type": "string",
19679
+ "enum": ["deploy", "scaffold"]
19680
+ },
19681
+ "editFiles": {
19682
+ "type": "array",
19683
+ "items": {
19684
+ "type": "string",
19685
+ "minLength": 1
19686
+ }
19687
+ },
19688
+ "reason": {
19689
+ "type": "string",
19690
+ "default": ""
19691
+ }
19692
+ },
19693
+ "required": [
19694
+ "mode",
19695
+ "editFiles",
19696
+ "reason"
19697
+ ]
19698
+ },
19699
+ "secrets": {
19700
+ "type": "array",
19701
+ "items": {
19702
+ "type": "object",
19703
+ "additionalProperties": false,
19704
+ "properties": {
19705
+ "key": {
19706
+ "type": "string",
19707
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
19708
+ },
19709
+ "required": {
19710
+ "type": "boolean",
19711
+ "default": true
19712
+ },
19713
+ "description": { "type": "string" }
19714
+ },
19715
+ "required": ["key", "required"]
18759
19716
  }
18760
19717
  },
18761
- "required": ["filename", "content_base64"]
18762
- }
18763
- },
18764
- "wait": {
18765
- "type": "boolean",
18766
- "description": "When true, wait for the first downstream SMTP delivery outcome before returning."
18767
- },
18768
- "wait_timeout_ms": {
18769
- "type": "integer",
18770
- "minimum": 1e3,
18771
- "maximum": 3e4,
18772
- "description": "Maximum time to wait for a delivery outcome when wait is true. Defaults to 30000."
19718
+ "secretGroups": {
19719
+ "type": "array",
19720
+ "items": {
19721
+ "type": "object",
19722
+ "additionalProperties": false,
19723
+ "properties": {
19724
+ "keys": {
19725
+ "type": "array",
19726
+ "minItems": 2,
19727
+ "items": {
19728
+ "type": "string",
19729
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
19730
+ }
19731
+ },
19732
+ "min": {
19733
+ "type": "integer",
19734
+ "minimum": 1,
19735
+ "default": 1
19736
+ },
19737
+ "description": { "type": "string" }
19738
+ },
19739
+ "required": ["keys", "min"]
19740
+ }
19741
+ },
19742
+ "variables": {
19743
+ "type": "array",
19744
+ "items": {
19745
+ "type": "object",
19746
+ "additionalProperties": false,
19747
+ "properties": {
19748
+ "key": {
19749
+ "type": "string",
19750
+ "minLength": 1
19751
+ },
19752
+ "prompt": {
19753
+ "type": "string",
19754
+ "minLength": 1
19755
+ },
19756
+ "default": { "type": "string" },
19757
+ "file": {
19758
+ "type": "string",
19759
+ "minLength": 1
19760
+ },
19761
+ "type": {
19762
+ "type": "string",
19763
+ "enum": [
19764
+ "string",
19765
+ "select",
19766
+ "url",
19767
+ "email"
19768
+ ],
19769
+ "default": "string"
19770
+ },
19771
+ "options": {
19772
+ "type": "array",
19773
+ "items": {
19774
+ "type": "string",
19775
+ "minLength": 1
19776
+ }
19777
+ },
19778
+ "validation": {
19779
+ "type": "object",
19780
+ "additionalProperties": false,
19781
+ "properties": {
19782
+ "pattern": {
19783
+ "type": "string",
19784
+ "minLength": 1
19785
+ },
19786
+ "maxLength": {
19787
+ "type": "integer",
19788
+ "minimum": 1
19789
+ }
19790
+ }
19791
+ }
19792
+ },
19793
+ "required": [
19794
+ "key",
19795
+ "prompt",
19796
+ "type"
19797
+ ]
19798
+ }
19799
+ },
19800
+ "setup": {
19801
+ "type": "object",
19802
+ "additionalProperties": false,
19803
+ "properties": {
19804
+ "agent": {
19805
+ "type": "string",
19806
+ "minLength": 1
19807
+ },
19808
+ "prompt": {
19809
+ "type": "string",
19810
+ "minLength": 1
19811
+ },
19812
+ "produces": {
19813
+ "type": "array",
19814
+ "items": {
19815
+ "type": "string",
19816
+ "minLength": 1
19817
+ }
19818
+ }
19819
+ },
19820
+ "required": [
19821
+ "agent",
19822
+ "prompt",
19823
+ "produces"
19824
+ ]
19825
+ },
19826
+ "postInstall": { "type": "string" }
19827
+ },
19828
+ "required": [
19829
+ "schemaVersion",
19830
+ "id",
19831
+ "title",
19832
+ "summary",
19833
+ "author",
19834
+ "tags",
19835
+ "source",
19836
+ "install",
19837
+ "secrets",
19838
+ "secretGroups",
19839
+ "variables"
19840
+ ]
19841
+ },
19842
+ "readme": { "type": ["string", "null"] },
19843
+ "status": {
19844
+ "type": "string",
19845
+ "enum": [
19846
+ "pending",
19847
+ "approved",
19848
+ "rejected"
19849
+ ]
18773
19850
  }
18774
19851
  },
18775
19852
  "required": [
18776
- "from",
18777
- "to",
18778
- "subject"
19853
+ "id",
19854
+ "slug",
19855
+ "title",
19856
+ "summary",
19857
+ "author",
19858
+ "tags",
19859
+ "verified",
19860
+ "install_count",
19861
+ "github_repo",
19862
+ "created_at",
19863
+ "updated_at",
19864
+ "description",
19865
+ "github_sha",
19866
+ "github_path",
19867
+ "manifest",
19868
+ "readme",
19869
+ "status"
18779
19870
  ]
18780
19871
  },
19872
+ "sdkName": "getTemplate",
19873
+ "summary": "Get a function template",
19874
+ "tag": "Templates",
19875
+ "tagCommand": "templates"
19876
+ },
19877
+ {
19878
+ "binaryResponse": false,
19879
+ "bodyRequired": false,
19880
+ "command": "get-template-install",
19881
+ "description": "Fetch the current state of a template install. Reads may advance the\nself-test phase when a reply effect has been observed.\n",
19882
+ "hasJsonBody": false,
19883
+ "method": "GET",
19884
+ "operationId": "getTemplateInstall",
19885
+ "path": "/templates/installs/{id}",
19886
+ "pathParams": [{
19887
+ "description": "Template install UUID.",
19888
+ "enum": null,
19889
+ "name": "id",
19890
+ "required": true,
19891
+ "type": "string"
19892
+ }],
19893
+ "queryParams": [],
19894
+ "requestSchema": null,
18781
19895
  "responseSchema": {
18782
19896
  "type": "object",
18783
19897
  "properties": {
18784
19898
  "id": {
18785
19899
  "type": "string",
18786
- "description": "Persisted sent-email attempt ID."
19900
+ "format": "uuid"
18787
19901
  },
18788
- "status": {
19902
+ "template_slug": {
18789
19903
  "type": "string",
18790
- "description": "Lifecycle status of a sent_emails row. Possible values:\n\n - `queued`: pre-call INSERT; the outbound agent has not\n yet replied.\n - `submitted_to_agent`: agent accepted; `queue_id` is set.\n - `agent_failed`: agent rejected; `error_code` and\n `error_message` carry the reason.\n - `gate_denied`: a recipient-scope gate denied the send;\n the agent was never called. The `gates` array carries\n the denial detail. /send-mail returns 403 in this case\n so callers see the denial synchronously; /sent-emails\n additionally records the row for historical lookup,\n which is when this status appears in a listing.\n - `unknown`: terminal indeterminate; the on-box log\n poller couldn't classify the receiver's response.\n - `delivered` / `bounced` / `deferred` / `wait_timeout`:\n terminal delivery outcomes (see DeliveryStatus).\n",
18791
- "enum": [
18792
- "queued",
18793
- "submitted_to_agent",
18794
- "agent_failed",
18795
- "gate_denied",
18796
- "unknown",
18797
- "delivered",
18798
- "bounced",
18799
- "deferred",
18800
- "wait_timeout"
18801
- ]
19904
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
19905
+ "description": "Template slug for this install."
18802
19906
  },
18803
- "from": {
19907
+ "state": {
18804
19908
  "type": "string",
18805
- "description": "Bare from-address actually written on the wire. Echoed\non every success branch so callers can confirm what\nwent out, particularly useful for the /emails/{id}/reply\npath where `from` is server-derived from the inbound's\nrecipient when the caller doesn't override.\n\nFor sends where the caller passed a from-header that\nincluded a display name (e.g. `\"Acme Support\" <support@acme.test>`),\nthis field is the parsed bare address (`support@acme.test`).\nThe display name was sent on the wire intact; this field\njust makes the address easy to compare against allowlists.\n"
19909
+ "enum": [
19910
+ "deploying",
19911
+ "connecting",
19912
+ "bound",
19913
+ "tested",
19914
+ "deploy_failed",
19915
+ "bind_failed",
19916
+ "test_failed"
19917
+ ]
18806
19918
  },
18807
- "queue_id": {
19919
+ "address": { "type": ["string", "null"] },
19920
+ "function_id": {
18808
19921
  "type": ["string", "null"],
18809
- "description": "Message identifier assigned by Primitive's OUTBOUND relay\n(the box that signs your mail and submits it to the\nreceiving MTA). NOT the receiver's queue id.\n\nThe receiver may also report its own queue id in\n`smtp_response_text` (e.g. `\"250 2.0.0 Ok: queued as\n99D111927CDA\"` from a Postfix receiver). Those two ids\nrefer to different mail systems and are NOT comparable.\nTreat `queue_id` as Primitive-internal and the\nreceiver's id as remote-system-internal.\n\nNull on rows that never reached the relay (queued,\ngate_denied, agent_failed before signing).\n"
19922
+ "format": "uuid"
18810
19923
  },
18811
- "accepted": {
18812
- "type": "array",
18813
- "items": { "type": "string" },
18814
- "description": "Recipient addresses accepted by the relay."
19924
+ "error": { "type": ["string", "null"] },
19925
+ "created_at": {
19926
+ "type": "string",
19927
+ "format": "date-time"
18815
19928
  },
18816
- "rejected": {
18817
- "type": "array",
18818
- "items": { "type": "string" },
18819
- "description": "Recipient addresses rejected by the relay."
19929
+ "updated_at": {
19930
+ "type": "string",
19931
+ "format": "date-time"
19932
+ }
19933
+ },
19934
+ "required": [
19935
+ "id",
19936
+ "template_slug",
19937
+ "state",
19938
+ "address",
19939
+ "function_id",
19940
+ "error",
19941
+ "created_at",
19942
+ "updated_at"
19943
+ ]
19944
+ },
19945
+ "sdkName": "getTemplateInstall",
19946
+ "summary": "Get template install status",
19947
+ "tag": "Templates",
19948
+ "tagCommand": "templates"
19949
+ },
19950
+ {
19951
+ "binaryResponse": false,
19952
+ "bodyRequired": true,
19953
+ "command": "install-template",
19954
+ "description": "Start a one-shot deploy of an approved deploy-mode Function template.\nThe response returns an install record immediately; poll\n`GET /templates/installs/{id}` for progress.\n",
19955
+ "hasJsonBody": true,
19956
+ "method": "POST",
19957
+ "operationId": "installTemplate",
19958
+ "path": "/templates/{id}/install",
19959
+ "pathParams": [{
19960
+ "description": "Template slug from the template manifest.",
19961
+ "enum": null,
19962
+ "name": "id",
19963
+ "required": true,
19964
+ "type": "string"
19965
+ }],
19966
+ "queryParams": [],
19967
+ "requestSchema": {
19968
+ "type": "object",
19969
+ "additionalProperties": false,
19970
+ "properties": {
19971
+ "address": {
19972
+ "type": "string",
19973
+ "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
19974
+ "description": "Localpart to claim on the selected inbound domain. Defaults to the template slug."
18820
19975
  },
18821
- "client_idempotency_key": {
19976
+ "domain": {
18822
19977
  "type": "string",
18823
- "description": "Effective idempotency key used for this send."
19978
+ "minLength": 3,
19979
+ "description": "Org domain name to claim the address on. Defaults to the org's newest active domain."
18824
19980
  },
18825
- "request_id": {
19981
+ "variables": {
19982
+ "type": "object",
19983
+ "additionalProperties": { "type": "string" },
19984
+ "description": "Template variable values keyed by manifest variable key."
19985
+ },
19986
+ "secrets": {
19987
+ "type": "object",
19988
+ "additionalProperties": { "type": "string" },
19989
+ "description": "Secret values keyed by manifest secret key."
19990
+ }
19991
+ }
19992
+ },
19993
+ "responseSchema": {
19994
+ "type": "object",
19995
+ "properties": {
19996
+ "id": {
18826
19997
  "type": "string",
18827
- "description": "Server-issued request identifier for support and tracing."
19998
+ "format": "uuid"
18828
19999
  },
18829
- "content_hash": {
20000
+ "template_slug": {
18830
20001
  "type": "string",
18831
- "description": "Stable hash of the canonical send payload."
20002
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
20003
+ "description": "Template slug for this install."
18832
20004
  },
18833
- "delivery_status": {
20005
+ "state": {
18834
20006
  "type": "string",
18835
- "description": "Narrower enum covering only the four terminal delivery\noutcomes returned to a synchronous `wait: true` send.\n\nOn the SendMailResult shape, `delivery_status` is always\nequal to `status` whenever both are present (i.e. on\nterminal-state replays and live wait=true responses).\nThe two fields exist so callers that want to type-narrow\non \"this is a delivery outcome\" can pattern-match against\nthe four-value enum without handling the broader\nSentEmailStatus value set (which also covers `queued`,\n`submitted_to_agent`, `agent_failed`, `gate_denied`,\n`unknown`).\n\nOn async-mode and pre-terminal responses, `delivery_status`\nis absent and only `status` is populated. Use `status` if\nyou want a single field that's always present.\n",
18836
20007
  "enum": [
18837
- "delivered",
18838
- "bounced",
18839
- "deferred",
18840
- "wait_timeout"
20008
+ "deploying",
20009
+ "connecting",
20010
+ "bound",
20011
+ "tested",
20012
+ "deploy_failed",
20013
+ "bind_failed",
20014
+ "test_failed"
18841
20015
  ]
18842
20016
  },
18843
- "smtp_response_code": {
18844
- "type": ["integer", "null"],
18845
- "description": "SMTP response code from the first downstream delivery outcome when wait is true."
20017
+ "address": { "type": ["string", "null"] },
20018
+ "function_id": {
20019
+ "type": ["string", "null"],
20020
+ "format": "uuid"
18846
20021
  },
18847
- "smtp_response_text": {
20022
+ "error": { "type": ["string", "null"] },
20023
+ "created_at": {
18848
20024
  "type": "string",
18849
- "description": "SMTP response text from the first downstream delivery outcome when wait is true."
20025
+ "format": "date-time"
18850
20026
  },
18851
- "idempotent_replay": {
18852
- "type": "boolean",
18853
- "description": "True when the response replays a previously-recorded send\nkeyed by `client_idempotency_key` (same key, same canonical\npayload). False on a fresh send and on gate-denied\nresponses. Lets callers branch on cache state without\ndiffing fields.\n"
20027
+ "updated_at": {
20028
+ "type": "string",
20029
+ "format": "date-time"
18854
20030
  }
18855
20031
  },
18856
20032
  "required": [
18857
20033
  "id",
18858
- "status",
18859
- "from",
18860
- "queue_id",
18861
- "accepted",
18862
- "rejected",
18863
- "client_idempotency_key",
18864
- "request_id",
18865
- "content_hash",
18866
- "idempotent_replay"
20034
+ "template_slug",
20035
+ "state",
20036
+ "address",
20037
+ "function_id",
20038
+ "error",
20039
+ "created_at",
20040
+ "updated_at"
18867
20041
  ]
18868
20042
  },
18869
- "sdkName": "sendEmail",
18870
- "summary": "Send outbound email",
18871
- "tag": "Sending",
18872
- "tagCommand": "sending"
20043
+ "sdkName": "installTemplate",
20044
+ "summary": "Install a function template",
20045
+ "tag": "Templates",
20046
+ "tagCommand": "templates"
20047
+ },
20048
+ {
20049
+ "binaryResponse": false,
20050
+ "bodyRequired": false,
20051
+ "command": "list-templates",
20052
+ "description": "List approved Function templates available for browsing and\ninstallation. Results are cacheable and paginated with\n`data.next_cursor`.\n",
20053
+ "hasJsonBody": false,
20054
+ "method": "GET",
20055
+ "operationId": "listTemplates",
20056
+ "path": "/templates",
20057
+ "pathParams": [],
20058
+ "queryParams": [
20059
+ {
20060
+ "description": "Search templates by title, summary, or slug.",
20061
+ "enum": null,
20062
+ "name": "q",
20063
+ "required": false,
20064
+ "type": "string"
20065
+ },
20066
+ {
20067
+ "description": "Filter templates by an exact tag.",
20068
+ "enum": null,
20069
+ "name": "tag",
20070
+ "required": false,
20071
+ "type": "string"
20072
+ },
20073
+ {
20074
+ "description": "Cursor from a previous response `data.next_cursor` value.",
20075
+ "enum": null,
20076
+ "name": "cursor",
20077
+ "required": false,
20078
+ "type": "string"
20079
+ },
20080
+ {
20081
+ "default": 50,
20082
+ "description": "Maximum number of templates to return. The server caps this at 100.",
20083
+ "enum": null,
20084
+ "maximum": 100,
20085
+ "minimum": 1,
20086
+ "name": "limit",
20087
+ "required": false,
20088
+ "type": "integer"
20089
+ }
20090
+ ],
20091
+ "requestSchema": null,
20092
+ "responseSchema": {
20093
+ "type": "object",
20094
+ "properties": {
20095
+ "items": {
20096
+ "type": "array",
20097
+ "items": {
20098
+ "type": "object",
20099
+ "properties": {
20100
+ "id": {
20101
+ "type": "string",
20102
+ "format": "uuid"
20103
+ },
20104
+ "slug": {
20105
+ "type": "string",
20106
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
20107
+ "description": "Stable template slug used in template URLs and install commands."
20108
+ },
20109
+ "title": { "type": "string" },
20110
+ "summary": { "type": "string" },
20111
+ "author": {
20112
+ "type": "object",
20113
+ "additionalProperties": false,
20114
+ "properties": {
20115
+ "id": {
20116
+ "type": "string",
20117
+ "minLength": 1
20118
+ },
20119
+ "name": {
20120
+ "type": "string",
20121
+ "minLength": 1
20122
+ },
20123
+ "url": {
20124
+ "type": "string",
20125
+ "format": "uri"
20126
+ }
20127
+ },
20128
+ "required": ["id", "name"]
20129
+ },
20130
+ "tags": {
20131
+ "type": "array",
20132
+ "items": { "type": "string" }
20133
+ },
20134
+ "verified": { "type": "boolean" },
20135
+ "install_count": {
20136
+ "type": "integer",
20137
+ "minimum": 0
20138
+ },
20139
+ "github_repo": {
20140
+ "type": "string",
20141
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
20142
+ "description": "GitHub repository in owner/repo form."
20143
+ },
20144
+ "created_at": {
20145
+ "type": "string",
20146
+ "format": "date-time"
20147
+ },
20148
+ "updated_at": {
20149
+ "type": "string",
20150
+ "format": "date-time"
20151
+ }
20152
+ },
20153
+ "required": [
20154
+ "id",
20155
+ "slug",
20156
+ "title",
20157
+ "summary",
20158
+ "author",
20159
+ "tags",
20160
+ "verified",
20161
+ "install_count",
20162
+ "github_repo",
20163
+ "created_at",
20164
+ "updated_at"
20165
+ ]
20166
+ }
20167
+ },
20168
+ "next_cursor": {
20169
+ "type": ["string", "null"],
20170
+ "description": "Cursor to pass as the next `cursor` query value, or null when there are no more templates."
20171
+ }
20172
+ },
20173
+ "required": ["items", "next_cursor"]
20174
+ },
20175
+ "sdkName": "listTemplates",
20176
+ "summary": "List function templates",
20177
+ "tag": "Templates",
20178
+ "tagCommand": "templates"
18873
20179
  },
18874
20180
  {
18875
20181
  "binaryResponse": false,