@pylonsync/functions 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +137 -0
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/runtime.ts +80 -0
- package/src/types.ts +140 -0
package/dist/index.d.ts
CHANGED
|
@@ -26,4 +26,4 @@ export type { WorkflowDefinition, WorkflowRun, WorkflowRunRequest, WorkflowRunne
|
|
|
26
26
|
export { resetDb, installTestIsolation } from "./testing";
|
|
27
27
|
export { slugifyName, availableSlug } from "./slugify";
|
|
28
28
|
export type { SsrResponse, SsrCookieOptions, SsrMetadata, Sitemap, SitemapEntry, Robots, RobotsRule, } from "./ssr-runtime";
|
|
29
|
-
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, MemberRow, Workflows, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, } from "./types";
|
|
29
|
+
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, MemberRow, Workflows, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, Domains, TenantDomainResult, TenantDomainDns, DomainAvailability, DomainContact, RegisterDomainOptions, RegisteredDomainResult, } from "./types";
|
package/dist/types.d.ts
CHANGED
|
@@ -775,6 +775,140 @@ export interface MutationCtx<R extends AuthRequirement = "optional"> {
|
|
|
775
775
|
signal?: AbortSignal;
|
|
776
776
|
}
|
|
777
777
|
/** Context for action handlers (external I/O, non-transactional). */
|
|
778
|
+
/** One DNS record a tenant must set (name + value), as returned by the
|
|
779
|
+
* registrar/CDN. Used for the CNAME target's DCV + ownership TXT records. */
|
|
780
|
+
export interface TenantDomainDns {
|
|
781
|
+
name: string;
|
|
782
|
+
value: string;
|
|
783
|
+
}
|
|
784
|
+
/** The result of attaching / polling a tenant (platform) custom domain —
|
|
785
|
+
* everything your app shows its end-customer to complete DNS setup. */
|
|
786
|
+
export interface TenantDomainResult {
|
|
787
|
+
hostname: string;
|
|
788
|
+
/** "provisioning" until the cert is active, then "ready". */
|
|
789
|
+
status: string;
|
|
790
|
+
/** Whether the hostname + TLS certificate are both active. */
|
|
791
|
+
active?: boolean;
|
|
792
|
+
/** The single CNAME the customer points their hostname at. */
|
|
793
|
+
cnameTarget: string;
|
|
794
|
+
/** TXT record proving domain ownership before DNS cutover (or null). */
|
|
795
|
+
ownership: TenantDomainDns | null;
|
|
796
|
+
/** TXT records that issue the DV certificate. */
|
|
797
|
+
dcv: TenantDomainDns[];
|
|
798
|
+
/** Human-readable provisioning errors, empty when healthy. */
|
|
799
|
+
errors: string[];
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Platform domains: attach / register / detach custom domains for your app's
|
|
803
|
+
* OWN end-customers, so each tenant can reach your app on their own hostname.
|
|
804
|
+
*
|
|
805
|
+
* Cloud-only — proxies to the Pylon Cloud control plane (which holds the
|
|
806
|
+
* Cloudflare/registrar credentials the app never sees). On a self-hosted Pylon
|
|
807
|
+
* every method throws a typed `DOMAINS_NOT_CONFIGURED` error.
|
|
808
|
+
*
|
|
809
|
+
* A newly attached hostname is trusted by the app's CORS / WebSocket / SSR
|
|
810
|
+
* gates automatically (the runtime refreshes the trusted-host set from the
|
|
811
|
+
* control plane) — no redeploy per tenant.
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* // In an action, when your customer adds their domain:
|
|
816
|
+
* const d = await ctx.domains.add("app.customer.com");
|
|
817
|
+
* // Show them: CNAME app.customer.com -> d.cnameTarget, plus d.dcv TXT records.
|
|
818
|
+
* // Later, poll:
|
|
819
|
+
* const s = await ctx.domains.status("app.customer.com"); // s.active === true
|
|
820
|
+
* ```
|
|
821
|
+
*/
|
|
822
|
+
/** One domain-availability / pricing result from a search. */
|
|
823
|
+
export interface DomainAvailability {
|
|
824
|
+
domainName: string;
|
|
825
|
+
sld: string;
|
|
826
|
+
tld: string;
|
|
827
|
+
purchasable: boolean;
|
|
828
|
+
premium?: boolean;
|
|
829
|
+
/** First-term price (USD), when purchasable. */
|
|
830
|
+
purchasePrice?: number;
|
|
831
|
+
renewalPrice?: number;
|
|
832
|
+
purchaseType?: string;
|
|
833
|
+
/** Why it isn't purchasable, when unavailable. */
|
|
834
|
+
reason?: string | null;
|
|
835
|
+
}
|
|
836
|
+
/** A registrant/admin/tech/billing contact for a domain registration. */
|
|
837
|
+
export interface DomainContact {
|
|
838
|
+
firstName: string;
|
|
839
|
+
lastName: string;
|
|
840
|
+
companyName?: string;
|
|
841
|
+
address1: string;
|
|
842
|
+
address2?: string;
|
|
843
|
+
city: string;
|
|
844
|
+
state: string;
|
|
845
|
+
zip: string;
|
|
846
|
+
country: string;
|
|
847
|
+
email: string;
|
|
848
|
+
phone: string;
|
|
849
|
+
fax?: string;
|
|
850
|
+
}
|
|
851
|
+
/** Options for {@link Domains.register}. `purchasePrice` is a price ceiling —
|
|
852
|
+
* registration is refused if the real price is higher, so a premium name can't
|
|
853
|
+
* surprise-charge. Contacts default to the platform account's when omitted. */
|
|
854
|
+
export interface RegisterDomainOptions {
|
|
855
|
+
years?: number;
|
|
856
|
+
autorenewEnabled?: boolean;
|
|
857
|
+
privacyEnabled?: boolean;
|
|
858
|
+
nameservers?: string[];
|
|
859
|
+
contacts?: {
|
|
860
|
+
registrant: DomainContact;
|
|
861
|
+
admin?: DomainContact;
|
|
862
|
+
tech?: DomainContact;
|
|
863
|
+
billing?: DomainContact;
|
|
864
|
+
};
|
|
865
|
+
purchasePrice?: number;
|
|
866
|
+
promoCode?: string;
|
|
867
|
+
}
|
|
868
|
+
/** Result of a domain registration. */
|
|
869
|
+
export interface RegisteredDomainResult {
|
|
870
|
+
domain: {
|
|
871
|
+
domainName: string;
|
|
872
|
+
createDate?: string;
|
|
873
|
+
expireDate?: string;
|
|
874
|
+
autorenewEnabled?: boolean;
|
|
875
|
+
locked?: boolean;
|
|
876
|
+
privacyEnabled?: boolean;
|
|
877
|
+
nameservers?: string[];
|
|
878
|
+
renewalPrice?: number;
|
|
879
|
+
};
|
|
880
|
+
order?: number;
|
|
881
|
+
totalPaid?: number;
|
|
882
|
+
}
|
|
883
|
+
export interface Domains {
|
|
884
|
+
/** Attach a custom domain for one of your end-customers. Returns the DNS the
|
|
885
|
+
* customer must set (the CNAME target + ownership/DCV TXT records). */
|
|
886
|
+
add(hostname: string): Promise<TenantDomainResult>;
|
|
887
|
+
/** Poll a tenant domain's verification + certificate status. */
|
|
888
|
+
status(hostname: string): Promise<TenantDomainResult>;
|
|
889
|
+
/** Detach a tenant domain (deletes the hostname + frees the slot). */
|
|
890
|
+
remove(hostname: string): Promise<{
|
|
891
|
+
hostname: string;
|
|
892
|
+
removed: boolean;
|
|
893
|
+
}>;
|
|
894
|
+
/** The hostnames currently ready (trusted) for this app — owner + tenant. */
|
|
895
|
+
list(): Promise<{
|
|
896
|
+
hosts: string[];
|
|
897
|
+
}>;
|
|
898
|
+
/** Search domain availability + pricing to buy. A `query` with a dot is an
|
|
899
|
+
* exact check ("acme.com"); a bare keyword ("acme") returns suggestions.
|
|
900
|
+
* Requires the registrar (name.com) to be configured on the control plane. */
|
|
901
|
+
search(query: string, opts?: {
|
|
902
|
+
suggest?: boolean;
|
|
903
|
+
tldFilter?: string[];
|
|
904
|
+
}): Promise<{
|
|
905
|
+
results: DomainAvailability[];
|
|
906
|
+
}>;
|
|
907
|
+
/** REGISTER (buy) a domain for your end-customer. Spends money on the
|
|
908
|
+
* platform's registrar account; requires a paid plan. Buying does not by
|
|
909
|
+
* itself serve the app — attach a host with `add()` afterward. */
|
|
910
|
+
register(domainName: string, opts?: RegisterDomainOptions): Promise<RegisteredDomainResult>;
|
|
911
|
+
}
|
|
778
912
|
export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
779
913
|
auth: AuthInfo<R>;
|
|
780
914
|
stream: Stream;
|
|
@@ -789,6 +923,9 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
789
923
|
connections: Connections;
|
|
790
924
|
/** Durable workflows: start / deliver events — see {@link Workflows}. */
|
|
791
925
|
workflows: Workflows;
|
|
926
|
+
/** Attach / register custom domains for your app's OWN end-customers
|
|
927
|
+
* (platform domains) — see {@link Domains}. Cloud-only. */
|
|
928
|
+
domains: Domains;
|
|
792
929
|
/** Environment variables / secrets. */
|
|
793
930
|
env: Record<string, string>;
|
|
794
931
|
/** Signed file-download URLs — see {@link Files}. */
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -90,4 +90,13 @@ export type {
|
|
|
90
90
|
LlmCompleteResponse,
|
|
91
91
|
LlmStreamEvent,
|
|
92
92
|
Rooms,
|
|
93
|
+
// Platform domains — app authors name these when handling ctx.domains
|
|
94
|
+
// results (the DNS the end-customer must set).
|
|
95
|
+
Domains,
|
|
96
|
+
TenantDomainResult,
|
|
97
|
+
TenantDomainDns,
|
|
98
|
+
DomainAvailability,
|
|
99
|
+
DomainContact,
|
|
100
|
+
RegisterDomainOptions,
|
|
101
|
+
RegisteredDomainResult,
|
|
93
102
|
} from "./types";
|
package/src/runtime.ts
CHANGED
|
@@ -31,6 +31,11 @@ import type {
|
|
|
31
31
|
Rooms,
|
|
32
32
|
Workflows,
|
|
33
33
|
Connections,
|
|
34
|
+
Domains,
|
|
35
|
+
TenantDomainResult,
|
|
36
|
+
DomainAvailability,
|
|
37
|
+
RegisterDomainOptions,
|
|
38
|
+
RegisteredDomainResult,
|
|
34
39
|
QueryCtx,
|
|
35
40
|
MutationCtx,
|
|
36
41
|
ActionCtx,
|
|
@@ -1056,6 +1061,80 @@ function buildConnections(callId: string): Connections {
|
|
|
1056
1061
|
};
|
|
1057
1062
|
}
|
|
1058
1063
|
|
|
1064
|
+
/**
|
|
1065
|
+
* `ctx.domains` — platform (tenant) custom domains. Pure TS: proxies to the
|
|
1066
|
+
* Pylon Cloud control plane over HTTP, authed by the machine's own
|
|
1067
|
+
* `PYLON_DOMAINS_TOKEN` (a plain env var stamped at deploy — not a shared
|
|
1068
|
+
* credential, so no Rust-side transport hook like ctx.email needs). Fails LOUD
|
|
1069
|
+
* with `DOMAINS_NOT_CONFIGURED` when the cloud env is absent (self-host), rather
|
|
1070
|
+
* than silently no-opping — a call that looks like it attached a domain but
|
|
1071
|
+
* didn't would be a worse footgun.
|
|
1072
|
+
*/
|
|
1073
|
+
function buildDomains(): Domains {
|
|
1074
|
+
const cloudUrl = (process.env.PYLON_CLOUD_URL || "").replace(/\/+$/, "");
|
|
1075
|
+
const token = process.env.PYLON_DOMAINS_TOKEN || "";
|
|
1076
|
+
|
|
1077
|
+
async function call<T>(
|
|
1078
|
+
endpoint: string,
|
|
1079
|
+
body: Record<string, unknown>,
|
|
1080
|
+
): Promise<T> {
|
|
1081
|
+
if (!cloudUrl || !token) {
|
|
1082
|
+
const e = new Error(
|
|
1083
|
+
"custom domains require Pylon Cloud (PYLON_CLOUD_URL / PYLON_DOMAINS_TOKEN are not set on this machine)",
|
|
1084
|
+
);
|
|
1085
|
+
(e as any).code = "DOMAINS_NOT_CONFIGURED";
|
|
1086
|
+
throw e;
|
|
1087
|
+
}
|
|
1088
|
+
const res = await fetch(`${cloudUrl}/api/fn/${endpoint}`, {
|
|
1089
|
+
method: "POST",
|
|
1090
|
+
headers: {
|
|
1091
|
+
"Content-Type": "application/json",
|
|
1092
|
+
Authorization: `Bearer ${token}`,
|
|
1093
|
+
},
|
|
1094
|
+
body: JSON.stringify(body),
|
|
1095
|
+
});
|
|
1096
|
+
const text = await res.text();
|
|
1097
|
+
let json: any = {};
|
|
1098
|
+
try {
|
|
1099
|
+
json = text ? JSON.parse(text) : {};
|
|
1100
|
+
} catch {
|
|
1101
|
+
json = {};
|
|
1102
|
+
}
|
|
1103
|
+
// /api/fn returns the handler's raw value on 200, or
|
|
1104
|
+
// {error:{code,message}} on failure (crates/router json_error).
|
|
1105
|
+
if (!res.ok || json?.error) {
|
|
1106
|
+
const err = new Error(
|
|
1107
|
+
json?.error?.message || `platform-domains ${endpoint} failed (${res.status})`,
|
|
1108
|
+
);
|
|
1109
|
+
(err as any).code = json?.error?.code || "DOMAINS_REQUEST_FAILED";
|
|
1110
|
+
throw err;
|
|
1111
|
+
}
|
|
1112
|
+
return json as T;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
return {
|
|
1116
|
+
add: (hostname: string) =>
|
|
1117
|
+
call<TenantDomainResult>("provisionTenantDomain", { hostname }),
|
|
1118
|
+
status: (hostname: string) =>
|
|
1119
|
+
call<TenantDomainResult>("getTenantDomainStatus", { hostname }),
|
|
1120
|
+
remove: (hostname: string) =>
|
|
1121
|
+
call<{ hostname: string; removed: boolean }>("removeTenantDomain", {
|
|
1122
|
+
hostname,
|
|
1123
|
+
}),
|
|
1124
|
+
list: () => call<{ hosts: string[] }>("listProjectTrustedHosts", {}),
|
|
1125
|
+
search: (query: string, opts?: { suggest?: boolean; tldFilter?: string[] }) =>
|
|
1126
|
+
call<{ results: DomainAvailability[] }>("searchAvailableDomains", {
|
|
1127
|
+
query,
|
|
1128
|
+
...(opts ?? {}),
|
|
1129
|
+
}),
|
|
1130
|
+
register: (domainName: string, opts?: RegisterDomainOptions) =>
|
|
1131
|
+
call<RegisteredDomainResult>("registerCustomerDomain", {
|
|
1132
|
+
domainName,
|
|
1133
|
+
...(opts ?? {}),
|
|
1134
|
+
}),
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1059
1138
|
function buildActionCtx(
|
|
1060
1139
|
callId: string,
|
|
1061
1140
|
auth: AuthInfo,
|
|
@@ -1089,6 +1168,7 @@ function buildActionCtx(
|
|
|
1089
1168
|
rooms,
|
|
1090
1169
|
connections,
|
|
1091
1170
|
workflows: buildWorkflows(callId),
|
|
1171
|
+
domains: buildDomains(),
|
|
1092
1172
|
env: process.env as Record<string, string>,
|
|
1093
1173
|
async runQuery(fnName, args) {
|
|
1094
1174
|
return rpc(callId, {
|
package/src/types.ts
CHANGED
|
@@ -873,6 +873,143 @@ export interface MutationCtx<R extends AuthRequirement = "optional"> {
|
|
|
873
873
|
}
|
|
874
874
|
|
|
875
875
|
/** Context for action handlers (external I/O, non-transactional). */
|
|
876
|
+
/** One DNS record a tenant must set (name + value), as returned by the
|
|
877
|
+
* registrar/CDN. Used for the CNAME target's DCV + ownership TXT records. */
|
|
878
|
+
export interface TenantDomainDns {
|
|
879
|
+
name: string;
|
|
880
|
+
value: string;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/** The result of attaching / polling a tenant (platform) custom domain —
|
|
884
|
+
* everything your app shows its end-customer to complete DNS setup. */
|
|
885
|
+
export interface TenantDomainResult {
|
|
886
|
+
hostname: string;
|
|
887
|
+
/** "provisioning" until the cert is active, then "ready". */
|
|
888
|
+
status: string;
|
|
889
|
+
/** Whether the hostname + TLS certificate are both active. */
|
|
890
|
+
active?: boolean;
|
|
891
|
+
/** The single CNAME the customer points their hostname at. */
|
|
892
|
+
cnameTarget: string;
|
|
893
|
+
/** TXT record proving domain ownership before DNS cutover (or null). */
|
|
894
|
+
ownership: TenantDomainDns | null;
|
|
895
|
+
/** TXT records that issue the DV certificate. */
|
|
896
|
+
dcv: TenantDomainDns[];
|
|
897
|
+
/** Human-readable provisioning errors, empty when healthy. */
|
|
898
|
+
errors: string[];
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Platform domains: attach / register / detach custom domains for your app's
|
|
903
|
+
* OWN end-customers, so each tenant can reach your app on their own hostname.
|
|
904
|
+
*
|
|
905
|
+
* Cloud-only — proxies to the Pylon Cloud control plane (which holds the
|
|
906
|
+
* Cloudflare/registrar credentials the app never sees). On a self-hosted Pylon
|
|
907
|
+
* every method throws a typed `DOMAINS_NOT_CONFIGURED` error.
|
|
908
|
+
*
|
|
909
|
+
* A newly attached hostname is trusted by the app's CORS / WebSocket / SSR
|
|
910
|
+
* gates automatically (the runtime refreshes the trusted-host set from the
|
|
911
|
+
* control plane) — no redeploy per tenant.
|
|
912
|
+
*
|
|
913
|
+
* @example
|
|
914
|
+
* ```ts
|
|
915
|
+
* // In an action, when your customer adds their domain:
|
|
916
|
+
* const d = await ctx.domains.add("app.customer.com");
|
|
917
|
+
* // Show them: CNAME app.customer.com -> d.cnameTarget, plus d.dcv TXT records.
|
|
918
|
+
* // Later, poll:
|
|
919
|
+
* const s = await ctx.domains.status("app.customer.com"); // s.active === true
|
|
920
|
+
* ```
|
|
921
|
+
*/
|
|
922
|
+
/** One domain-availability / pricing result from a search. */
|
|
923
|
+
export interface DomainAvailability {
|
|
924
|
+
domainName: string;
|
|
925
|
+
sld: string;
|
|
926
|
+
tld: string;
|
|
927
|
+
purchasable: boolean;
|
|
928
|
+
premium?: boolean;
|
|
929
|
+
/** First-term price (USD), when purchasable. */
|
|
930
|
+
purchasePrice?: number;
|
|
931
|
+
renewalPrice?: number;
|
|
932
|
+
purchaseType?: string;
|
|
933
|
+
/** Why it isn't purchasable, when unavailable. */
|
|
934
|
+
reason?: string | null;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/** A registrant/admin/tech/billing contact for a domain registration. */
|
|
938
|
+
export interface DomainContact {
|
|
939
|
+
firstName: string;
|
|
940
|
+
lastName: string;
|
|
941
|
+
companyName?: string;
|
|
942
|
+
address1: string;
|
|
943
|
+
address2?: string;
|
|
944
|
+
city: string;
|
|
945
|
+
state: string;
|
|
946
|
+
zip: string;
|
|
947
|
+
country: string;
|
|
948
|
+
email: string;
|
|
949
|
+
phone: string;
|
|
950
|
+
fax?: string;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/** Options for {@link Domains.register}. `purchasePrice` is a price ceiling —
|
|
954
|
+
* registration is refused if the real price is higher, so a premium name can't
|
|
955
|
+
* surprise-charge. Contacts default to the platform account's when omitted. */
|
|
956
|
+
export interface RegisterDomainOptions {
|
|
957
|
+
years?: number;
|
|
958
|
+
autorenewEnabled?: boolean;
|
|
959
|
+
privacyEnabled?: boolean;
|
|
960
|
+
nameservers?: string[];
|
|
961
|
+
contacts?: {
|
|
962
|
+
registrant: DomainContact;
|
|
963
|
+
admin?: DomainContact;
|
|
964
|
+
tech?: DomainContact;
|
|
965
|
+
billing?: DomainContact;
|
|
966
|
+
};
|
|
967
|
+
purchasePrice?: number;
|
|
968
|
+
promoCode?: string;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/** Result of a domain registration. */
|
|
972
|
+
export interface RegisteredDomainResult {
|
|
973
|
+
domain: {
|
|
974
|
+
domainName: string;
|
|
975
|
+
createDate?: string;
|
|
976
|
+
expireDate?: string;
|
|
977
|
+
autorenewEnabled?: boolean;
|
|
978
|
+
locked?: boolean;
|
|
979
|
+
privacyEnabled?: boolean;
|
|
980
|
+
nameservers?: string[];
|
|
981
|
+
renewalPrice?: number;
|
|
982
|
+
};
|
|
983
|
+
order?: number;
|
|
984
|
+
totalPaid?: number;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
export interface Domains {
|
|
988
|
+
/** Attach a custom domain for one of your end-customers. Returns the DNS the
|
|
989
|
+
* customer must set (the CNAME target + ownership/DCV TXT records). */
|
|
990
|
+
add(hostname: string): Promise<TenantDomainResult>;
|
|
991
|
+
/** Poll a tenant domain's verification + certificate status. */
|
|
992
|
+
status(hostname: string): Promise<TenantDomainResult>;
|
|
993
|
+
/** Detach a tenant domain (deletes the hostname + frees the slot). */
|
|
994
|
+
remove(hostname: string): Promise<{ hostname: string; removed: boolean }>;
|
|
995
|
+
/** The hostnames currently ready (trusted) for this app — owner + tenant. */
|
|
996
|
+
list(): Promise<{ hosts: string[] }>;
|
|
997
|
+
/** Search domain availability + pricing to buy. A `query` with a dot is an
|
|
998
|
+
* exact check ("acme.com"); a bare keyword ("acme") returns suggestions.
|
|
999
|
+
* Requires the registrar (name.com) to be configured on the control plane. */
|
|
1000
|
+
search(
|
|
1001
|
+
query: string,
|
|
1002
|
+
opts?: { suggest?: boolean; tldFilter?: string[] },
|
|
1003
|
+
): Promise<{ results: DomainAvailability[] }>;
|
|
1004
|
+
/** REGISTER (buy) a domain for your end-customer. Spends money on the
|
|
1005
|
+
* platform's registrar account; requires a paid plan. Buying does not by
|
|
1006
|
+
* itself serve the app — attach a host with `add()` afterward. */
|
|
1007
|
+
register(
|
|
1008
|
+
domainName: string,
|
|
1009
|
+
opts?: RegisterDomainOptions,
|
|
1010
|
+
): Promise<RegisteredDomainResult>;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
876
1013
|
export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
877
1014
|
auth: AuthInfo<R>;
|
|
878
1015
|
stream: Stream;
|
|
@@ -887,6 +1024,9 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
887
1024
|
connections: Connections;
|
|
888
1025
|
/** Durable workflows: start / deliver events — see {@link Workflows}. */
|
|
889
1026
|
workflows: Workflows;
|
|
1027
|
+
/** Attach / register custom domains for your app's OWN end-customers
|
|
1028
|
+
* (platform domains) — see {@link Domains}. Cloud-only. */
|
|
1029
|
+
domains: Domains;
|
|
890
1030
|
/** Environment variables / secrets. */
|
|
891
1031
|
env: Record<string, string>;
|
|
892
1032
|
/** Signed file-download URLs — see {@link Files}. */
|