@layervai/qurl 0.3.0 → 0.4.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.
Files changed (75) hide show
  1. package/README.md +340 -23
  2. package/dist/cjs/client.d.ts +180 -13
  3. package/dist/cjs/client.js +1126 -96
  4. package/dist/cjs/errors.d.ts +15 -11
  5. package/dist/cjs/errors.js +30 -21
  6. package/dist/cjs/index.d.ts +3 -3
  7. package/dist/cjs/index.js +4 -1
  8. package/dist/cjs/internal.d.ts +4 -0
  9. package/dist/cjs/internal.js +16 -0
  10. package/dist/cjs/node/deployment.d.ts +44 -0
  11. package/dist/cjs/node/deployment.js +167 -0
  12. package/dist/cjs/node/native-udp.d.ts +37 -0
  13. package/dist/cjs/node/native-udp.js +294 -0
  14. package/dist/cjs/node/nhp-wire.d.ts +35 -0
  15. package/dist/cjs/node/nhp-wire.js +261 -0
  16. package/dist/cjs/node/portal-opener.d.ts +83 -0
  17. package/dist/cjs/node/portal-opener.js +767 -0
  18. package/dist/cjs/node/qv2.d.ts +38 -0
  19. package/dist/cjs/node/qv2.js +292 -0
  20. package/dist/cjs/node/strict-json.d.ts +12 -0
  21. package/dist/cjs/node/strict-json.js +174 -0
  22. package/dist/cjs/node.d.ts +3 -0
  23. package/dist/cjs/node.js +11 -0
  24. package/dist/cjs/types.d.ts +90 -18
  25. package/dist/cjs/version.d.ts +1 -1
  26. package/dist/cjs/version.js +1 -1
  27. package/dist/esm/client.d.ts +180 -13
  28. package/dist/esm/client.d.ts.map +1 -1
  29. package/dist/esm/client.js +1125 -96
  30. package/dist/esm/client.js.map +1 -1
  31. package/dist/esm/errors.d.ts +15 -11
  32. package/dist/esm/errors.d.ts.map +1 -1
  33. package/dist/esm/errors.js +29 -20
  34. package/dist/esm/errors.js.map +1 -1
  35. package/dist/esm/index.d.ts +3 -3
  36. package/dist/esm/index.d.ts.map +1 -1
  37. package/dist/esm/index.js +2 -2
  38. package/dist/esm/index.js.map +1 -1
  39. package/dist/esm/internal.d.ts +5 -0
  40. package/dist/esm/internal.d.ts.map +1 -0
  41. package/dist/esm/internal.js +14 -0
  42. package/dist/esm/internal.js.map +1 -0
  43. package/dist/esm/node/deployment.d.ts +45 -0
  44. package/dist/esm/node/deployment.d.ts.map +1 -0
  45. package/dist/esm/node/deployment.js +163 -0
  46. package/dist/esm/node/deployment.js.map +1 -0
  47. package/dist/esm/node/native-udp.d.ts +38 -0
  48. package/dist/esm/node/native-udp.d.ts.map +1 -0
  49. package/dist/esm/node/native-udp.js +291 -0
  50. package/dist/esm/node/native-udp.js.map +1 -0
  51. package/dist/esm/node/nhp-wire.d.ts +36 -0
  52. package/dist/esm/node/nhp-wire.d.ts.map +1 -0
  53. package/dist/esm/node/nhp-wire.js +257 -0
  54. package/dist/esm/node/nhp-wire.js.map +1 -0
  55. package/dist/esm/node/portal-opener.d.ts +84 -0
  56. package/dist/esm/node/portal-opener.d.ts.map +1 -0
  57. package/dist/esm/node/portal-opener.js +757 -0
  58. package/dist/esm/node/portal-opener.js.map +1 -0
  59. package/dist/esm/node/qv2.d.ts +39 -0
  60. package/dist/esm/node/qv2.d.ts.map +1 -0
  61. package/dist/esm/node/qv2.js +286 -0
  62. package/dist/esm/node/qv2.js.map +1 -0
  63. package/dist/esm/node/strict-json.d.ts +13 -0
  64. package/dist/esm/node/strict-json.d.ts.map +1 -0
  65. package/dist/esm/node/strict-json.js +171 -0
  66. package/dist/esm/node/strict-json.js.map +1 -0
  67. package/dist/esm/node.d.ts +4 -0
  68. package/dist/esm/node.d.ts.map +1 -0
  69. package/dist/esm/node.js +2 -0
  70. package/dist/esm/node.js.map +1 -0
  71. package/dist/esm/types.d.ts +90 -18
  72. package/dist/esm/types.d.ts.map +1 -1
  73. package/dist/esm/version.d.ts +1 -1
  74. package/dist/esm/version.js +1 -1
  75. package/package.json +25 -6
@@ -1,4 +1,12 @@
1
- import type { AccessCodeListOutput, AgentBootstrapInput, AgentBootstrapOutput, ApiKey, ApiKeyListOutput, BillingInvoiceListOutput, BatchCreateInput, BatchCreateOutput, ClientOptions, ConnectorInstallation, ConnectorInstallationListOutput, CreateAccessCodeInput, CreateAccessCodeOutput, CreateApiKeyInput, CreateApiKeyOutput, CreateBillingCheckoutInput, CreateInput, CreateOutput, CreateQurlForResourceInput, CreateResourceInput, CreateWebhookInput, Customer, CheckoutSession, Domain, DomainListOutput, DomainVerifyResult, ExtendInput, Invoice, ListInput, ListOutput, ListApiKeysInput, ListBillingInvoicesInput, ListConnectorInstallationsInput, ListDomainsInput, ListWebhookDeliveriesInput, ListWebhooksInput, MintInput, MintOutput, PortalSession, QURL, QurlSummary, Quota, RedeemAccessCodeInput, RedeemAccessCodeOutput, RegisterDomainInput, Resource, ResourceDetail, ResourceListInput, ResourceListOutput, RequestOptions, ResolveInput, ResolveOutput, SessionListOutput, SessionTerminateOutput, UpdateApiKeyInput, UpdateCustomerInput, UpdateInput, UpdateResourceInput, UpdateResourceQurlInput, UpdateWebhookInput, UsageCurrentPeriod, UsageDaily, Webhook, WebhookDelivery, WebhookDeliveryListOutput, WebhookEventTypeInfo, WebhookListOutput, WebhookWithSecret } from "./types.js";
1
+ import type { AccessCodeListOutput, ApiKey, ApiKeyListOutput, BillingInvoiceListOutput, BatchCreateInput, BatchCreateOutput, ClientOptions, ConnectorInstallation, ConnectorInstallationListOutput, CreateAccessCodeInput, CreateAccessCodeOutput, CreateApiKeyInput, CreateApiKeyOutput, CreateBillingCheckoutInput, CreateInput, CreateOutput, CreatePortalOptions, CreateQurlForResourceInput, CreateResourceInput, CreateWebhookInput, Customer, CheckoutSession, Domain, DomainListOutput, DomainVerifyResult, ExtendInput, Invoice, ListInput, ListOutput, ListApiKeysInput, ListBillingInvoicesInput, ListConnectorInstallationsInput, ListDomainsInput, ListWebhookDeliveriesInput, ListWebhooksInput, MintInput, MintOutput, Portal, PortalSession, ProtectUrlOptions, QURL, QurlSummary, Quota, RedeemAccessCodeInput, RedeemAccessCodeOutput, RegisterDomainInput, Resource, ResourceDetail, ResourceHandle, ResourceListInput, ResourceListOutput, RequestOptions, ResolveInput, ResolveOutput, SessionListOutput, SessionTerminateOutput, UpdateApiKeyInput, UpdateCustomerInput, UpdateInput, UpdateResourceInput, UpdateResourceQurlInput, UpdateWebhookInput, UsageCurrentPeriod, UsageDaily, Webhook, WebhookDelivery, WebhookDeliveryListOutput, WebhookEventTypeInfo, WebhookListOutput, WebhookWithSecret } from "./types.js";
2
+ /**
3
+ * Shape of qurl-go's offline signed-fragment links: three or more
4
+ * dot-separated base64url parts (<version>.<claims>.<secret>.<sig>).
5
+ * Detected only to give those links a precise error in extractAccessToken.
6
+ *
7
+ * @internal Exported for in-package tests; not re-exported from index.ts.
8
+ */
9
+ export declare const SIGNED_FRAGMENT_RE: RegExp;
2
10
  /** qURL API client. */
3
11
  export declare class QURLClient {
4
12
  private readonly baseUrl;
@@ -49,7 +57,119 @@ export declare class QURLClient {
49
57
  */
50
58
  private validateBatchCreateResponse;
51
59
  private paginateAll;
52
- /** Create a new qURL. */
60
+ /**
61
+ * Protect a private URL — create or reuse its LayerV resource.
62
+ *
63
+ * The first step of the portal flow (qurl-go: `Client.ProtectURL`).
64
+ * Protect the URL once, then mint short-lived links for it with
65
+ * {@link ProtectedResource.createPortal}:
66
+ *
67
+ * ```ts
68
+ * const resource = await client.protectUrl("https://internal.example.com/dashboard");
69
+ * const portal = await resource.createPortal({ validFor: "5m" });
70
+ * share(portal.link);
71
+ * ```
72
+ *
73
+ * Protecting the same target URL again returns the existing resource.
74
+ * Malformed URLs and URLs with embedded credentials (userinfo) are
75
+ * rejected before any request, mirroring qurl-go. REST-shaped equivalent:
76
+ * {@link createResource}.
77
+ */
78
+ protectUrl(targetUrl: string, opts?: ProtectUrlOptions, requestOptions?: RequestOptions): Promise<ProtectedResource>;
79
+ /**
80
+ * Return a portal-minting handle for a stored resource id, without an API
81
+ * call.
82
+ *
83
+ * Use when you persisted a LayerV resource id and want to mint more
84
+ * portals for it (qurl-go: `Client.ResourceByID`):
85
+ *
86
+ * ```ts
87
+ * const resource = client.resourceById("r_demo1234567");
88
+ * const portal = await resource.createPortal({ validFor: "1h" });
89
+ * ```
90
+ *
91
+ * The handle carries no server metadata; use {@link getResource} when you
92
+ * need the full resource details.
93
+ */
94
+ resourceById(id: string): ProtectedResource;
95
+ /**
96
+ * Return the resource qURL Connector created for `connectorId`.
97
+ *
98
+ * Use when qURL Connector already protects the service — do not call
99
+ * {@link protectUrl} again for the same service. The connector id is the
100
+ * resource slug LayerV stores for that connector; the LayerV API performs
101
+ * the slug lookup, and the SDK confirms the returned alias matches
102
+ * `connectorId` before binding the handle (qurl-go:
103
+ * `Client.ConnectorResource`).
104
+ *
105
+ * Throws {@link NotFoundError} (`status: 0`, `code: "resource_not_found"`)
106
+ * when no resource exists for the connector id, {@link QURLError}
107
+ * (`code: "ambiguous_resource"`) when the lookup returns more than one
108
+ * resource, and {@link ValidationError} (`code: "unexpected_response"`)
109
+ * when the returned resource's alias is missing or does not match.
110
+ */
111
+ connectorResource(connectorId: string): Promise<ProtectedResource>;
112
+ /**
113
+ * Mint a short-lived qURL link (a portal) for a protected resource.
114
+ *
115
+ * A portal is cryptographic, just-in-time permission for one actor to
116
+ * reach one private resource. Recipients open `portal.link` directly and
117
+ * need no LayerV credentials. Prefer short lifetimes such as
118
+ * `{ validFor: "5m" }`. Accepts a {@link ProtectedResource} handle or a
119
+ * resource id (`r_` prefix). REST-shaped equivalents: {@link mintLink} /
120
+ * {@link createQurlForResource}.
121
+ *
122
+ * Duration options take a string (`"5m"`, `"24h"`; server-validated) or a
123
+ * number of milliseconds with qurl-go's client-side guardrails: whole
124
+ * seconds only, at least one minute for `validFor` and one second for
125
+ * `sessionDuration`. `maxSessions: 0` is sent explicitly and means
126
+ * unlimited; blank labels are rejected.
127
+ */
128
+ createPortal(resource: ProtectedResource | string, opts?: CreatePortalOptions, requestOptions?: RequestOptions): Promise<Portal>;
129
+ /**
130
+ * Protect `targetUrl` and mint a portal in one API call.
131
+ *
132
+ * Convenience for one-off scripts (qurl-go: `Client.CreatePortalForURL`).
133
+ * The returned resource handle is reusable for minting more portals but
134
+ * carries only the resource id and the caller-supplied target URL; use
135
+ * {@link protectUrl} when you need the full server-populated resource
136
+ * metadata. Portal options match {@link createPortal}; `targetUrl` gets
137
+ * the same malformed-URL and embedded-credentials rejection as
138
+ * {@link protectUrl}. REST-shaped equivalent: {@link create}.
139
+ */
140
+ createPortalForUrl(targetUrl: string, opts?: CreatePortalOptions, requestOptions?: RequestOptions): Promise<{
141
+ portal: Portal;
142
+ resource: ProtectedResource;
143
+ }>;
144
+ /**
145
+ * Open a qURL link programmatically and return the reachable resource.
146
+ *
147
+ * For services and agents that open received qURL links in code — human
148
+ * recipients just open the link. Accepts a full platform link
149
+ * (`https://qurl.link/#at_...`) or a bare access token. Triggers an NHP
150
+ * knock that grants network access for the caller's IP and returns a
151
+ * {@link ResourceHandle} with the reachable resource URL and access
152
+ * lifetime.
153
+ *
154
+ * Unlike qurl-go's `EnterPortal` (which verifies links locally and needs
155
+ * no LayerV credentials), this SDK opens links through the LayerV API:
156
+ * the client needs an API key with the `qurl:resolve` scope. REST-shaped
157
+ * equivalent: {@link resolve}.
158
+ *
159
+ * Throws {@link ValidationError} (`code: "client_validation"`) when no
160
+ * access token can be extracted from `qurlLink`, and
161
+ * (`code: "unexpected_response"`) when access is granted but the API
162
+ * reports no resource URL — it fails closed rather than returning an
163
+ * empty handle. Error messages never echo the link; qURL links are
164
+ * credentials.
165
+ */
166
+ enterPortal(qurlLink: string, requestOptions?: RequestOptions): Promise<ResourceHandle>;
167
+ /**
168
+ * Create a new qURL.
169
+ *
170
+ * Portal-flow equivalent: {@link createPortalForUrl} (same endpoint,
171
+ * returns a {@link Portal} plus a reusable resource handle).
172
+ */
53
173
  create(input: CreateInput, options?: RequestOptions): Promise<CreateOutput>;
54
174
  /**
55
175
  * Batch create multiple qURLs (1-`MAX_BATCH_ITEMS` items).
@@ -171,6 +291,8 @@ export declare class QURLClient {
171
291
  /**
172
292
  * Mint a new access link for a qURL.
173
293
  *
294
+ * Portal-flow equivalent: {@link createPortal}.
295
+ *
174
296
  * Accepts either a resource ID (`r_` prefix) or a qURL display ID (`q_`
175
297
  * prefix); the API resolves `q_` IDs to the parent resource automatically.
176
298
  *
@@ -182,6 +304,9 @@ export declare class QURLClient {
182
304
  /**
183
305
  * Resolve a qURL access token (headless).
184
306
  *
307
+ * Portal-flow equivalent: {@link enterPortal} (also accepts full qURL
308
+ * links and fails closed when no resource URL is returned).
309
+ *
185
310
  * Triggers an NHP knock to grant network access for the caller's IP.
186
311
  * Requires `qurl:resolve` scope on the API key.
187
312
  *
@@ -190,8 +315,6 @@ export declare class QURLClient {
190
315
  resolve(input: ResolveInput | string, options?: RequestOptions): Promise<ResolveOutput>;
191
316
  /** Get quota and usage information. */
192
317
  getQuota(): Promise<Quota>;
193
- /** Bootstrap a LayerV qURL Connector agent. */
194
- bootstrapAgent(input: AgentBootstrapInput, options?: RequestOptions): Promise<AgentBootstrapOutput>;
195
318
  /** List resources from the `/v1/resources` API. */
196
319
  listResources(input?: ResourceListInput): Promise<ResourceListOutput>;
197
320
  /**
@@ -201,7 +324,12 @@ export declare class QURLClient {
201
324
  * iteration begins.
202
325
  */
203
326
  listAllResources(input?: Omit<ResourceListInput, "cursor">): AsyncGenerator<Resource, void, undefined>;
204
- /** Create a resource directly. */
327
+ /**
328
+ * Create a resource directly.
329
+ *
330
+ * Portal-flow equivalent for URL resources: {@link protectUrl} (returns
331
+ * a portal-minting handle).
332
+ */
205
333
  createResource(input: CreateResourceInput, options?: RequestOptions): Promise<Resource>;
206
334
  /** Get one resource plus its bounded qURL preview. */
207
335
  getResource(id: string): Promise<ResourceDetail>;
@@ -209,7 +337,11 @@ export declare class QURLClient {
209
337
  updateResource(id: string, input: UpdateResourceInput, options?: RequestOptions): Promise<Resource>;
210
338
  /** Revoke a resource and all of its qURLs. */
211
339
  deleteResource(id: string): Promise<void>;
212
- /** Mint a qURL against an existing resource. */
340
+ /**
341
+ * Mint a qURL against an existing resource.
342
+ *
343
+ * Portal-flow equivalent: {@link createPortal} (same endpoint).
344
+ */
213
345
  createQurlForResource(id: string, input?: CreateQurlForResourceInput, options?: RequestOptions): Promise<CreateOutput>;
214
346
  /** Revoke a specific qURL token on a resource. */
215
347
  revokeResourceQurl(id: string, qurlId: string): Promise<void>;
@@ -223,13 +355,7 @@ export declare class QURLClient {
223
355
  * this page and emits a debug log rather than pretending it fetched all pages.
224
356
  */
225
357
  listResourceSessions(id: string): Promise<SessionListOutput>;
226
- /**
227
- * Terminate all active sessions for a resource.
228
- *
229
- * The returned count is best-effort under retries: if the first DELETE
230
- * succeeds server-side but the response is lost, a retried request may
231
- * return `0` because there are no sessions left to terminate.
232
- */
358
+ /** Terminate all active sessions for a resource and return the server count. */
233
359
  terminateAllResourceSessions(id: string): Promise<SessionTerminateOutput>;
234
360
  /** Terminate a specific resource session. */
235
361
  terminateResourceSession(id: string, sessionId: string): Promise<void>;
@@ -342,6 +468,12 @@ export declare class QURLClient {
342
468
  /** Revoke an access code. */
343
469
  revokeAccessCode(id: string): Promise<void>;
344
470
  private request;
471
+ /**
472
+ * Require the service's exact 204 response with no response bytes exposed by
473
+ * Fetch. A standards-compliant Fetch implementation discards any forbidden
474
+ * wire body on 204, so the SDK cannot detect bytes that Fetch did not expose.
475
+ */
476
+ private requestNoContent;
345
477
  /**
346
478
  * Issue an HTTP request and parse the JSON response.
347
479
  *
@@ -369,4 +501,39 @@ export declare class QURLClient {
369
501
  */
370
502
  private retryDelay;
371
503
  private classifyFetchError;
504
+ private classifyResponseReadError;
505
+ }
506
+ /**
507
+ * A LayerV-protected resource, bound to the client that produced it.
508
+ *
509
+ * Obtained from {@link QURLClient.protectUrl},
510
+ * {@link QURLClient.connectorResource}, or {@link QURLClient.resourceById} —
511
+ * not constructed directly. Mint short-lived access links for the resource
512
+ * with {@link createPortal} (qurl-go: `qurl.Resource`).
513
+ */
514
+ export declare class ProtectedResource {
515
+ #private;
516
+ /** The LayerV resource id (`r_` prefix). */
517
+ readonly id: string;
518
+ /** The private URL protected by this resource, when known. */
519
+ readonly targetUrl?: string;
520
+ /**
521
+ * Full server-populated {@link Resource} metadata when the handle came
522
+ * from an API response; `undefined` for {@link QURLClient.resourceById}
523
+ * handles and for the one-call {@link QURLClient.createPortalForUrl} path.
524
+ */
525
+ readonly details?: Resource;
526
+ constructor(client: QURLClient, id: string, targetUrl?: string, details?: Resource);
527
+ /**
528
+ * Whether `resource` was produced by `client`. A static because the
529
+ * binding lives in a private field that only this class can read; used
530
+ * by {@link QURLClient.createPortal} to refuse handles bound to a
531
+ * different client.
532
+ */
533
+ static isBoundTo(resource: ProtectedResource, client: QURLClient): boolean;
534
+ /**
535
+ * Mint a short-lived qURL link (a portal) for this resource. See
536
+ * {@link QURLClient.createPortal} for the option reference.
537
+ */
538
+ createPortal(opts?: CreatePortalOptions, requestOptions?: RequestOptions): Promise<Portal>;
372
539
  }