Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/licenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class Licenses {
/**
* Get a license's activation code
*
* Available until the license is activated or revoked.
* Available until the license is activated or revoked; for an ephemeral license, until revoked.
*/
public retrieveActivationCode(
licenseId: string,
Expand Down
13 changes: 13 additions & 0 deletions src/models/issueLicenseRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { decodeBoolean, decodeInteger, decodeObject, decodeString } from "../dec
export interface IssueLicenseRequest {
/** Customer ID or alias */
customerId: string;
/**
* Ephemeral, for CI and other short-lived installations: the activation code can be used
* any number of times, each activation gets a license of this many hours (1 to 24) for the
* installation activating, and nothing is refreshed. Not with `offline` or `validity_days`.
*/
ephemeralHours?: number | null | undefined;
/**
* Offline only. The installation's id as it reports it, up to 255 characters without
* spaces: the license names it (`aud`) and stays bound to it. Without one, the license is
Expand Down Expand Up @@ -35,12 +41,17 @@ export const IssueLicenseRequestSerializer = {
return {
...extraProperties(json, [
"customer_id",
"ephemeral_hours",
"instance_id",
"offline",
"subscription_id",
"validity_days",
]),
customerId: decodeString(json["customer_id"], path, "customer_id"),
ephemeralHours:
json["ephemeral_hours"] != null
? decodeInteger(json["ephemeral_hours"], path, "ephemeral_hours")
: json["ephemeral_hours"],
instanceId:
json["instance_id"] != null
? decodeString(json["instance_id"], path, "instance_id")
Expand All @@ -64,12 +75,14 @@ export const IssueLicenseRequestSerializer = {
return {
...extraProperties(value, [
"customerId",
"ephemeralHours",
"instanceId",
"offline",
"subscriptionId",
"validityDays",
]),
customer_id: value.customerId,
ephemeral_hours: value.ephemeralHours,
instance_id: value.instanceId,
offline: value.offline,
subscription_id: value.subscriptionId,
Expand Down
5 changes: 4 additions & 1 deletion src/models/issueLicenseResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { decodeObject, decodePath, decodeString } from "../decode.js";
import { type License, LicenseSerializer } from "./license.js";

export interface IssueLicenseResponse {
/** Online: one-time code the customer enters in their installation to activate the license. */
/**
* Online: one-time code the customer enters in their installation to activate the license.
* Ephemeral: the reusable code, e.g. a CI secret.
*/
activationCode?: string | null | undefined;
license: License;
/** Offline: the signed license (a JWT) to install in the installation. */
Expand Down
9 changes: 9 additions & 0 deletions src/models/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface License {
createdAt: Date;
customerId: CustomerId;
customerName: string;
/** Ephemeral: each activation of the reusable code gets a license of this many hours. */
ephemeralHours?: number | null | undefined;
/** Whether the activation code can still be retrieved: only until activation or revocation. */
hasActivationCode: boolean;
id: LicenseId;
Expand Down Expand Up @@ -53,6 +55,7 @@ export const LicenseSerializer = {
"created_at",
"customer_id",
"customer_name",
"ephemeral_hours",
"has_activation_code",
"id",
"instance_id",
Expand All @@ -72,6 +75,10 @@ export const LicenseSerializer = {
decodePath(path, "customer_id")
),
customerName: decodeString(json["customer_name"], path, "customer_name"),
ephemeralHours:
json["ephemeral_hours"] != null
? decodeInteger(json["ephemeral_hours"], path, "ephemeral_hours")
: json["ephemeral_hours"],
hasActivationCode: decodeBoolean(
json["has_activation_code"],
path,
Expand Down Expand Up @@ -119,6 +126,7 @@ export const LicenseSerializer = {
"createdAt",
"customerId",
"customerName",
"ephemeralHours",
"hasActivationCode",
"id",
"instanceId",
Expand All @@ -135,6 +143,7 @@ export const LicenseSerializer = {
created_at: value.createdAt,
customer_id: CustomerIdSerializer.serialize(value.customerId),
customer_name: value.customerName,
ephemeral_hours: value.ephemeralHours,
has_activation_code: value.hasActivationCode,
id: LicenseIdSerializer.serialize(value.id),
instance_id: value.instanceId,
Expand Down
8 changes: 4 additions & 4 deletions tests/api/licenses.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ test("licenses.list", async () => {
const { client, requests } = mock({
status: 200,
contentType: "application/json",
body: '{"data":[{"auto_issued":false,"created_at":"2023-12-31T23:59:59.999-05:30","customer_id":"customer_id_2","customer_name":"sample","has_activation_code":false,"id":"license_id_0","offline":false,"revoked_immediately":false,"status":"REVOKED","validity_days":-123456789}]}',
body: '{"data":[{"auto_issued":false,"created_at":"2023-12-31T23:59:59.999-05:30","customer_id":"customer_id_2","customer_name":"sample","has_activation_code":true,"id":"license_id_78","offline":false,"revoked_immediately":false,"status":"PENDING","validity_days":2147483647}]}',
});
await client.licenses.list();
assert.deepEqual(requests, ["GET /api/v1/licenses"]);
Expand All @@ -23,7 +23,7 @@ test("licenses.create", async () => {
const { client, requests } = mock({
status: 200,
contentType: "application/json",
body: '{"license":{"auto_issued":false,"created_at":"2023-12-31T23:59:59.999-05:30","customer_id":"customer_id_37","customer_name":"sample","has_activation_code":true,"id":"license_id_40","offline":true,"revoked_immediately":true,"status":"PENDING","validity_days":123456789}}',
body: '{"license":{"auto_issued":false,"created_at":"2023-12-31T23:59:59.999-05:30","customer_id":"customer_id_37","customer_name":"sample","has_activation_code":true,"id":"license_id_32","offline":true,"revoked_immediately":false,"status":"REVOKED","validity_days":2147483647}}',
});
await client.licenses.create(
IssueLicenseRequestSerializer.parse(parseJson('{"customer_id":"sample"}'))
Expand All @@ -35,7 +35,7 @@ test("licenses.retrieve", async () => {
const { client, requests } = mock({
status: 200,
contentType: "application/json",
body: '{"auto_issued":false,"created_at":"2024-03-15T10:30:45.123+02:00","customer_id":"customer_id_79","customer_name":"sample","has_activation_code":false,"id":"license_id_90","offline":false,"revoked_immediately":true,"status":"PENDING","validity_days":-123456789}',
body: '{"auto_issued":false,"created_at":"2024-03-15T10:30:45.123+02:00","customer_id":"customer_id_79","customer_name":"sample","has_activation_code":true,"id":"license_id_13","offline":true,"revoked_immediately":false,"status":"PENDING","validity_days":-2147483648}',
});
await client.licenses.retrieve("license_id");
assert.deepEqual(requests, ["GET /api/v1/licenses/license_id"]);
Expand Down Expand Up @@ -68,7 +68,7 @@ test("licenses.revoke", async () => {
const { client, requests } = mock({
status: 200,
contentType: "application/json",
body: '{"auto_issued":false,"created_at":"2024-03-15T10:30:45.123+02:00","customer_id":"customer_id_79","customer_name":"sample","has_activation_code":false,"id":"license_id_90","offline":false,"revoked_immediately":true,"status":"PENDING","validity_days":-123456789}',
body: '{"auto_issued":false,"created_at":"2024-03-15T10:30:45.123+02:00","customer_id":"customer_id_79","customer_name":"sample","has_activation_code":true,"id":"license_id_13","offline":true,"revoked_immediately":false,"status":"PENDING","validity_days":-2147483648}',
});
await client.licenses.revoke(
"license_id",
Expand Down