@phpsandbox/sdk 0.5.0 → 0.6.0-canary.1
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/README.md +22 -0
- package/dist/browser/phpsandbox-sdk.esm.js +97 -6
- package/dist/browser/phpsandbox-sdk.esm.min.js +9 -9
- package/dist/browser/phpsandbox-sdk.iife.js +97 -6
- package/dist/browser/phpsandbox-sdk.iife.min.js +9 -9
- package/dist/customers.d.ts +190 -1
- package/dist/customers.js +103 -2
- package/dist/index.d.ts +2 -0
- package/dist/publication/types.d.ts +20 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,8 +80,30 @@ const checkout = await platform.payments.checkout({
|
|
|
80
80
|
|
|
81
81
|
Persist an opaque UUID on each app account for its external customer identity; separate databases must not reuse sequential IDs. Initialize this client only on the app server. It reads the provisioned app configuration and exposes only app runtime capabilities, without notebook or organization administration. Production uses its own identity and never falls back to development. Select `{ mode: 'test' }` once for an intentional sandbox run. Runtimes without `process.env` can supply server bindings through `{ env }`.
|
|
82
82
|
|
|
83
|
+
Applications can configure their own organization conversion stages and one event follow-up. Configuration never activates a journey:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
await app.customers.configure({
|
|
87
|
+
funnel: {
|
|
88
|
+
title: 'Learning outcomes',
|
|
89
|
+
stages: [{ id: 'lesson', label: 'Completed a lesson', measure: 'event', event: 'lesson.completed' }],
|
|
90
|
+
},
|
|
91
|
+
followUp: { label: 'Help learners', triggerEvent: 'lesson.stalled', prerequisiteEvent: null, stopOnPayment: false },
|
|
92
|
+
emailTemplate: '<html><body><h1>{{subject}}</h1><main>{{content}}</main></body></html>',
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Stages support `event`, `first_payment`, and `event_after_payment` measures. Historical imports never count as new conversions or trigger event follow-ups. The existing `credit_limit` journey identifier is retained for compatibility; its trigger, prerequisite and payment rule now come from application configuration, while its delay and reviewed content remain journey settings. Pause the journey before changing its rules, then review and activate it separately. Due follow-ups require a fresh application eligibility resolution through `pendingFollowUps()` and `resolveFollowUp()`.
|
|
97
|
+
|
|
98
|
+
HTML templates support escaped `subject`, `content`, `name`, `email` and `unsubscribeUrl` placeholders; `content` is required. Plain text remains available, and marketing messages always receive an unsubscribe footer. Set `emailTemplate: null` to use plain text. Queued messages and reviewed campaigns preserve their selected design. Production currently uses a fixed platform From address; display name and Reply-To are configurable. Custom sending domains are not supported.
|
|
99
|
+
|
|
100
|
+
|
|
83
101
|
Verify incoming payment callbacks with `platform.payments.verifyEvent(rawBody, signature)`, passing the `phpsandbox-signature` header. The client verifies the original bytes, timestamp and environment before returning the event; the app must still validate order ownership and apply revisions idempotently.
|
|
84
102
|
|
|
103
|
+
Application Customers also supports historical identification (`historical`, `joinedAt`, `lastActiveAt`), separate legacy-account eligibility (`legacyPolicy`), known unsubscribes and suppressions, organization membership snapshots, and confirmed positive payments from existing billing. Use `customers.organization()` to synchronize relationships and `customers.confirmPayment()` only after backend provider verification. Historical payments never create first-payment conversions.
|
|
104
|
+
|
|
105
|
+
For approved credit-limit journeys, an application worker pulls `customers.pendingFollowUps()`, rechecks authoritative payment, access and actual credits, then immediately calls `customers.resolveFollowUp()`. Delivery rechecks contact eligibility and requires a fresh application decision. Keep original preference timestamps with `customers.preferences(..., { subscribed, source, occurredAt })`; a legacy policy does not fabricate consent.
|
|
106
|
+
|
|
85
107
|
## Server invitations
|
|
86
108
|
|
|
87
109
|
Server administrators can invite someone by email and inspect the shared invitation state:
|
|
@@ -14527,6 +14527,39 @@ function date4(params) {
|
|
|
14527
14527
|
config(en_default());
|
|
14528
14528
|
|
|
14529
14529
|
// src/customers.ts
|
|
14530
|
+
var eventName = external_exports.string().trim().min(1).max(100);
|
|
14531
|
+
var customerConfigurationSchema = external_exports.object({
|
|
14532
|
+
funnel: external_exports.object({
|
|
14533
|
+
title: external_exports.string().trim().min(1).max(100),
|
|
14534
|
+
stages: external_exports.array(
|
|
14535
|
+
external_exports.discriminatedUnion("measure", [
|
|
14536
|
+
external_exports.object({
|
|
14537
|
+
id: external_exports.string().regex(/^[a-zA-Z0-9_-]+$/).max(50),
|
|
14538
|
+
label: external_exports.string().trim().min(1).max(100),
|
|
14539
|
+
measure: external_exports.literal("event"),
|
|
14540
|
+
event: eventName
|
|
14541
|
+
}),
|
|
14542
|
+
external_exports.object({
|
|
14543
|
+
id: external_exports.string().regex(/^[a-zA-Z0-9_-]+$/).max(50),
|
|
14544
|
+
label: external_exports.string().trim().min(1).max(100),
|
|
14545
|
+
measure: external_exports.literal("first_payment")
|
|
14546
|
+
}),
|
|
14547
|
+
external_exports.object({
|
|
14548
|
+
id: external_exports.string().regex(/^[a-zA-Z0-9_-]+$/).max(50),
|
|
14549
|
+
label: external_exports.string().trim().min(1).max(100),
|
|
14550
|
+
measure: external_exports.literal("event_after_payment"),
|
|
14551
|
+
event: eventName
|
|
14552
|
+
})
|
|
14553
|
+
])
|
|
14554
|
+
).max(12)
|
|
14555
|
+
}).nullable(),
|
|
14556
|
+
followUp: external_exports.object({
|
|
14557
|
+
label: external_exports.string().trim().min(1).max(100),
|
|
14558
|
+
triggerEvent: eventName,
|
|
14559
|
+
prerequisiteEvent: eventName.nullable(),
|
|
14560
|
+
stopOnPayment: external_exports.boolean()
|
|
14561
|
+
}).nullable()
|
|
14562
|
+
});
|
|
14530
14563
|
var customerModeSchema = external_exports.enum(["test", "live"]);
|
|
14531
14564
|
var customerSchema = external_exports.object({
|
|
14532
14565
|
id: external_exports.string(),
|
|
@@ -14535,6 +14568,12 @@ var customerSchema = external_exports.object({
|
|
|
14535
14568
|
name: external_exports.string().nullable(),
|
|
14536
14569
|
source: external_exports.string().nullable(),
|
|
14537
14570
|
marketingSubscribed: external_exports.boolean(),
|
|
14571
|
+
communicationBasis: external_exports.enum(["unknown", "legacy_account", "explicit_opt_in", "unsubscribed"]).optional(),
|
|
14572
|
+
legacyPolicy: external_exports.string().nullable().optional(),
|
|
14573
|
+
joinedAt: external_exports.string().nullable().optional(),
|
|
14574
|
+
importedAt: external_exports.string().nullable().optional(),
|
|
14575
|
+
lastActiveAt: external_exports.string().nullable().optional(),
|
|
14576
|
+
billingStatus: external_exports.enum(["unknown", "free", "paid"]).optional(),
|
|
14538
14577
|
suppressionReason: external_exports.string().nullable(),
|
|
14539
14578
|
activatedAt: external_exports.string().nullable(),
|
|
14540
14579
|
createdAt: external_exports.string().nullable()
|
|
@@ -14548,6 +14587,8 @@ var spaceSchema = external_exports.object({
|
|
|
14548
14587
|
replyTo: external_exports.string().nullable(),
|
|
14549
14588
|
senderVerified: external_exports.boolean(),
|
|
14550
14589
|
domainRecords: external_exports.string().nullable(),
|
|
14590
|
+
configuration: customerConfigurationSchema.optional(),
|
|
14591
|
+
emailTemplate: external_exports.string().nullable().optional(),
|
|
14551
14592
|
provisionedAt: external_exports.string().nullable().optional(),
|
|
14552
14593
|
lastRequestAt: external_exports.string().nullable().optional(),
|
|
14553
14594
|
processedAt: external_exports.string().nullable().optional()
|
|
@@ -14560,7 +14601,7 @@ var journeyInputSchema = external_exports.object({
|
|
|
14560
14601
|
activationEvent: external_exports.string()
|
|
14561
14602
|
});
|
|
14562
14603
|
var journeySchema = journeyInputSchema.extend({
|
|
14563
|
-
kind: external_exports.enum(["welcome", "setup", "purchase"]),
|
|
14604
|
+
kind: external_exports.enum(["welcome", "setup", "purchase", "credit_limit"]),
|
|
14564
14605
|
version: external_exports.number().int().optional(),
|
|
14565
14606
|
startsAt: external_exports.string().nullable().optional(),
|
|
14566
14607
|
draft: journeyInputSchema.nullable().optional()
|
|
@@ -14576,16 +14617,18 @@ var messageSchema = external_exports.object({
|
|
|
14576
14617
|
dueAt: external_exports.string().nullable().optional(),
|
|
14577
14618
|
attemptedAt: external_exports.string().nullable().optional(),
|
|
14578
14619
|
receivedAt: external_exports.string().nullable().optional(),
|
|
14579
|
-
journeyKind: external_exports.enum(["welcome", "setup", "purchase"]).nullable().optional(),
|
|
14620
|
+
journeyKind: external_exports.enum(["welcome", "setup", "purchase", "credit_limit"]).nullable().optional(),
|
|
14580
14621
|
journeyVersion: external_exports.number().int().nullable().optional(),
|
|
14581
14622
|
category: external_exports.enum(["marketing", "service"]).optional(),
|
|
14582
14623
|
from: external_exports.string().nullable().optional(),
|
|
14583
14624
|
replyTo: external_exports.string().nullable().optional(),
|
|
14584
14625
|
renderedText: external_exports.string().nullable().optional(),
|
|
14626
|
+
renderedHtml: external_exports.string().nullable().optional(),
|
|
14585
14627
|
unsubscribeUrl: external_exports.string().nullable().optional(),
|
|
14586
14628
|
createdAt: external_exports.string().nullable()
|
|
14587
14629
|
});
|
|
14588
14630
|
var overviewSchema = external_exports.object({
|
|
14631
|
+
funnel: external_exports.object({ title: external_exports.string(), stages: external_exports.array(external_exports.object({ id: external_exports.string(), label: external_exports.string(), count: external_exports.number() })) }).nullable().optional(),
|
|
14589
14632
|
space: spaceSchema.nullable(),
|
|
14590
14633
|
customers: external_exports.array(customerSchema),
|
|
14591
14634
|
journeys: external_exports.array(journeySchema),
|
|
@@ -14594,10 +14637,58 @@ var overviewSchema = external_exports.object({
|
|
|
14594
14637
|
messageTotal: external_exports.number().optional(),
|
|
14595
14638
|
events: external_exports.array(external_exports.string()).optional()
|
|
14596
14639
|
});
|
|
14640
|
+
var customerOrganizationSchema = external_exports.object({
|
|
14641
|
+
id: external_exports.string(),
|
|
14642
|
+
externalId: external_exports.string(),
|
|
14643
|
+
name: external_exports.string(),
|
|
14644
|
+
ownerCustomerId: external_exports.string(),
|
|
14645
|
+
firstPaidAt: external_exports.string().nullable(),
|
|
14646
|
+
activatedAt: external_exports.string().nullable()
|
|
14647
|
+
});
|
|
14597
14648
|
var CustomerRuntime = class {
|
|
14598
14649
|
constructor(client) {
|
|
14599
14650
|
this.client = client;
|
|
14600
14651
|
}
|
|
14652
|
+
/** Configure this application's event funnel and follow-up rules. Does not activate messaging. */
|
|
14653
|
+
async configure(input) {
|
|
14654
|
+
const configuration = customerConfigurationSchema.parse(input);
|
|
14655
|
+
return customerConfigurationSchema.parse(
|
|
14656
|
+
(await this.client.put("/platform/customers/runtime/configuration", {
|
|
14657
|
+
...configuration,
|
|
14658
|
+
...input.emailTemplate !== void 0 ? { emailTemplate: input.emailTemplate } : {}
|
|
14659
|
+
})).data
|
|
14660
|
+
);
|
|
14661
|
+
}
|
|
14662
|
+
/** Inspect the workspace and environment selected by this app credential. */
|
|
14663
|
+
async context() {
|
|
14664
|
+
return external_exports.object({ id: external_exports.string(), notebookId: external_exports.string(), mode: customerModeSchema }).parse((await this.client.get("/platform/customers/runtime/context")).data);
|
|
14665
|
+
}
|
|
14666
|
+
/** Pull due conversion follow-ups, then recheck authoritative billing, credit and access. */
|
|
14667
|
+
async pendingFollowUps() {
|
|
14668
|
+
return external_exports.array(external_exports.object({ messageId: external_exports.string(), organizationExternalId: external_exports.string(), actorExternalId: external_exports.string() })).parse((await this.client.get("/platform/customers/runtime/follow-ups")).data);
|
|
14669
|
+
}
|
|
14670
|
+
/** Eligible deliveries run immediately; expired checks are never reused by a later worker. */
|
|
14671
|
+
async resolveFollowUp(messageId, resolution) {
|
|
14672
|
+
return messageSchema.parse(
|
|
14673
|
+
(await this.client.post(`/platform/customers/runtime/follow-ups/${encodeURIComponent(messageId)}/resolve`, {
|
|
14674
|
+
resolution
|
|
14675
|
+
})).data
|
|
14676
|
+
);
|
|
14677
|
+
}
|
|
14678
|
+
async organization(input) {
|
|
14679
|
+
return customerOrganizationSchema.parse(
|
|
14680
|
+
(await this.client.put("/platform/customers/runtime/organizations", input)).data
|
|
14681
|
+
);
|
|
14682
|
+
}
|
|
14683
|
+
/** Report only server-confirmed positive payments from your existing billing integration. */
|
|
14684
|
+
async confirmPayment(organizationExternalId, input) {
|
|
14685
|
+
return customerOrganizationSchema.parse(
|
|
14686
|
+
(await this.client.post(
|
|
14687
|
+
`/platform/customers/runtime/organizations/${encodeURIComponent(organizationExternalId)}/payments`,
|
|
14688
|
+
input
|
|
14689
|
+
)).data
|
|
14690
|
+
);
|
|
14691
|
+
}
|
|
14601
14692
|
async identify(input) {
|
|
14602
14693
|
return customerSchema.parse((await this.client.post("/platform/customers/runtime/identify", input)).data);
|
|
14603
14694
|
}
|
|
@@ -15242,14 +15333,14 @@ async function* readPublicationStream(input, options = {}) {
|
|
|
15242
15333
|
const reader = stream.getReader();
|
|
15243
15334
|
const decoder = new TextDecoder();
|
|
15244
15335
|
let buffer = "";
|
|
15245
|
-
let
|
|
15336
|
+
let eventName2 = "message";
|
|
15246
15337
|
let data = [];
|
|
15247
15338
|
let ended = false;
|
|
15248
15339
|
let receivedResult = false;
|
|
15249
15340
|
function dispatch() {
|
|
15250
|
-
const name =
|
|
15341
|
+
const name = eventName2;
|
|
15251
15342
|
const lines = data;
|
|
15252
|
-
|
|
15343
|
+
eventName2 = "message";
|
|
15253
15344
|
data = [];
|
|
15254
15345
|
if (!lines.length || !PublishStreamSseEventNameSchema.safeParse(name).success) {
|
|
15255
15346
|
return null;
|
|
@@ -15281,7 +15372,7 @@ async function* readPublicationStream(input, options = {}) {
|
|
|
15281
15372
|
content = content.slice(1);
|
|
15282
15373
|
}
|
|
15283
15374
|
if (field === "event") {
|
|
15284
|
-
|
|
15375
|
+
eventName2 = content;
|
|
15285
15376
|
}
|
|
15286
15377
|
if (field === "data") {
|
|
15287
15378
|
data.push(content);
|