openxiangda 1.0.164 → 1.0.166

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 (33) hide show
  1. package/README.md +9 -7
  2. package/lib/change-baseline.js +74 -6
  3. package/lib/cli.js +2508 -167
  4. package/lib/sdd.js +320 -6
  5. package/lib/utils.js +76 -2
  6. package/openxiangda-skills/SKILL.md +13 -6
  7. package/openxiangda-skills/references/pages/publish-flow.md +15 -16
  8. package/openxiangda-skills/references/resource-manifest-cheatsheet.md +24 -2
  9. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +14 -6
  10. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +10 -9
  11. package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +2 -0
  12. package/package.json +2 -1
  13. package/packages/sdk/dist/runtime/index.cjs +164 -48
  14. package/packages/sdk/dist/runtime/index.cjs.map +1 -1
  15. package/packages/sdk/dist/runtime/index.d.mts +1 -1
  16. package/packages/sdk/dist/runtime/index.d.ts +1 -1
  17. package/packages/sdk/dist/runtime/index.mjs +164 -48
  18. package/packages/sdk/dist/runtime/index.mjs.map +1 -1
  19. package/packages/sdk/dist/runtime/react.cjs +164 -48
  20. package/packages/sdk/dist/runtime/react.cjs.map +1 -1
  21. package/packages/sdk/dist/runtime/react.d.mts +79 -1
  22. package/packages/sdk/dist/runtime/react.d.ts +79 -1
  23. package/packages/sdk/dist/runtime/react.mjs +164 -48
  24. package/packages/sdk/dist/runtime/react.mjs.map +1 -1
  25. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda-resources.mdc +1 -0
  26. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda-resources.md +1 -0
  27. package/templates/openxiangda-react-spa/AGENTS.md +12 -10
  28. package/templates/openxiangda-react-spa/scripts/build-js-code.mjs +20 -2
  29. package/templates/openxiangda-react-spa/scripts/deploy.mjs +2 -2
  30. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-resources.mdc +2 -0
  31. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-resources.md +1 -0
  32. package/templates/sy-lowcode-app-workspace/AGENTS.md +5 -3
  33. package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +20 -2
@@ -8955,6 +8955,8 @@ var resolveAppTypeFromLocation = () => {
8955
8955
  var import_react20 = require("react");
8956
8956
 
8957
8957
  // packages/sdk/src/runtime/core/publicAccess.ts
8958
+ var PUBLIC_SESSION_RENEW_WINDOW_MS = 5 * 60 * 1e3;
8959
+ var publicSessionInflight = /* @__PURE__ */ new Map();
8958
8960
  var PublicAccessClientError = class extends Error {
8959
8961
  constructor(message3, options = {}) {
8960
8962
  super(message3);
@@ -8982,48 +8984,144 @@ var createPublicAccessClient = ({
8982
8984
  userAgent: input.userAgent || getCurrentUserAgent(),
8983
8985
  guestIdentifier: input.guestIdentifier || getOrCreatePublicGuestIdentifier(normalizedAppType)
8984
8986
  };
8985
- const response = await boundFetch(
8986
- buildServiceUrl3(
8987
- servicePrefix,
8988
- `/openxiangda-api/v1/apps/${encodeURIComponent(
8989
- normalizedAppType
8990
- )}/public/session`
8991
- ),
8992
- {
8993
- method: "POST",
8994
- credentials: "include",
8995
- headers: {
8996
- accept: "application/json",
8997
- "content-type": "application/json"
8998
- },
8999
- body: JSON.stringify(body)
9000
- }
8987
+ const identity = buildPublicSessionIdentity(
8988
+ normalizedAppType,
8989
+ servicePrefix,
8990
+ body
9001
8991
  );
9002
- const payload = await readPayload2(response);
9003
- const code = getRecordValue3(payload, "code");
9004
- const success = getRecordValue3(payload, "success");
9005
- if (!response.ok || success === false || !isSuccessCode7(code)) {
9006
- throw new PublicAccessClientError(
9007
- String(
9008
- getRecordValue3(payload, "message") || `Public access session failed: ${response.status}`
8992
+ const cached = readCachedPublicSession(identity);
8993
+ if (cached) return cached;
8994
+ const existing = publicSessionInflight.get(identity);
8995
+ if (existing) return existing;
8996
+ const pending = (async () => {
8997
+ const response = await boundFetch(
8998
+ buildServiceUrl3(
8999
+ servicePrefix,
9000
+ `/openxiangda-api/v1/apps/${encodeURIComponent(
9001
+ normalizedAppType
9002
+ )}/public/session`
9009
9003
  ),
9010
- { status: response.status, code, payload }
9004
+ {
9005
+ method: "POST",
9006
+ credentials: "include",
9007
+ headers: {
9008
+ accept: "application/json",
9009
+ "content-type": "application/json"
9010
+ },
9011
+ body: JSON.stringify(body)
9012
+ }
9011
9013
  );
9014
+ const payload = await readPayload2(response);
9015
+ const code = getRecordValue3(payload, "code");
9016
+ const success = getRecordValue3(payload, "success");
9017
+ if (!response.ok || success === false || !isSuccessCode7(code)) {
9018
+ throw new PublicAccessClientError(
9019
+ String(
9020
+ getRecordValue3(payload, "message") || `Public access session failed: ${response.status}`
9021
+ ),
9022
+ { status: response.status, code, payload }
9023
+ );
9024
+ }
9025
+ const data = getRecordValue3(payload, "data");
9026
+ const extra = getRecordValue3(payload, "extra");
9027
+ const session = {
9028
+ ...data,
9029
+ publicAccess: extra?.publicAccess || null,
9030
+ raw: payload
9031
+ };
9032
+ writeCachedPublicSession(identity, session);
9033
+ return session;
9034
+ })();
9035
+ publicSessionInflight.set(identity, pending);
9036
+ try {
9037
+ return await pending;
9038
+ } finally {
9039
+ if (publicSessionInflight.get(identity) === pending) {
9040
+ publicSessionInflight.delete(identity);
9041
+ }
9012
9042
  }
9013
- const data = getRecordValue3(payload, "data");
9014
- const extra = getRecordValue3(payload, "extra");
9015
- return {
9016
- ...data,
9017
- publicAccess: extra?.publicAccess || null,
9018
- raw: payload
9019
- };
9020
9043
  };
9021
9044
  return {
9022
9045
  appType: normalizedAppType,
9023
9046
  servicePrefix,
9024
- startSession: request
9047
+ startSession: request,
9048
+ clearSession: (input = {}) => {
9049
+ const body = {
9050
+ ...input,
9051
+ path: input.path || getCurrentPathname2(),
9052
+ domain: input.domain || getCurrentDomain(),
9053
+ userAgent: input.userAgent || getCurrentUserAgent(),
9054
+ guestIdentifier: input.guestIdentifier || getOrCreatePublicGuestIdentifier(normalizedAppType)
9055
+ };
9056
+ clearCachedPublicSession(
9057
+ buildPublicSessionIdentity(normalizedAppType, servicePrefix, body)
9058
+ );
9059
+ }
9025
9060
  };
9026
9061
  };
9062
+ var buildPublicSessionIdentity = (appType, servicePrefix, input) => JSON.stringify({
9063
+ appType,
9064
+ servicePrefix: servicePrefix.replace(/\/$/, ""),
9065
+ path: input.path || "",
9066
+ policyCode: input.policyCode || "",
9067
+ routeCode: input.routeCode || "",
9068
+ ticket: input.ticket || "",
9069
+ guestIdentifier: input.guestIdentifier || "",
9070
+ domain: input.domain || ""
9071
+ });
9072
+ var publicSessionStorageKey = (identity) => {
9073
+ let hash = 2166136261;
9074
+ for (let index = 0; index < identity.length; index += 1) {
9075
+ hash ^= identity.charCodeAt(index);
9076
+ hash = Math.imul(hash, 16777619);
9077
+ }
9078
+ return `openxiangda:public:session:v1:${identity.length}:${(hash >>> 0).toString(16)}`;
9079
+ };
9080
+ var readCachedPublicSession = (identity) => {
9081
+ try {
9082
+ if (typeof window === "undefined" || !window.sessionStorage) return null;
9083
+ const raw = window.sessionStorage.getItem(publicSessionStorageKey(identity));
9084
+ if (!raw) return null;
9085
+ const parsed = JSON.parse(raw);
9086
+ if (parsed.identity !== identity || !parsed.session) return null;
9087
+ if (!isPublicSessionReusable(parsed.session)) {
9088
+ clearCachedPublicSession(identity);
9089
+ return null;
9090
+ }
9091
+ return parsed.session;
9092
+ } catch {
9093
+ return null;
9094
+ }
9095
+ };
9096
+ var writeCachedPublicSession = (identity, session) => {
9097
+ if (!isPublicSessionReusable(session)) return;
9098
+ try {
9099
+ if (typeof window === "undefined" || !window.sessionStorage) return;
9100
+ const { raw: _raw, ...cacheableSession } = session;
9101
+ window.sessionStorage.setItem(
9102
+ publicSessionStorageKey(identity),
9103
+ JSON.stringify({ identity, session: cacheableSession })
9104
+ );
9105
+ } catch {
9106
+ }
9107
+ };
9108
+ var clearCachedPublicSession = (identity) => {
9109
+ try {
9110
+ if (typeof window !== "undefined" && window.sessionStorage) {
9111
+ window.sessionStorage.removeItem(publicSessionStorageKey(identity));
9112
+ }
9113
+ } catch {
9114
+ }
9115
+ };
9116
+ var isPublicSessionReusable = (session) => {
9117
+ const accessTokenExpiresAt = Number(session.accessTokenExpiresAt);
9118
+ if (!Number.isFinite(accessTokenExpiresAt) || accessTokenExpiresAt <= 0) {
9119
+ return false;
9120
+ }
9121
+ const policyExpiresAt = session.publicAccess?.expiresAt ? new Date(session.publicAccess.expiresAt).getTime() : Number.POSITIVE_INFINITY;
9122
+ const expiresAt = Math.min(accessTokenExpiresAt, policyExpiresAt);
9123
+ return expiresAt - Date.now() >= PUBLIC_SESSION_RENEW_WINDOW_MS;
9124
+ };
9027
9125
  var buildServiceUrl3 = (servicePrefix, path) => {
9028
9126
  const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
9029
9127
  const suffix = path.startsWith("/") ? path : `/${path}`;
@@ -9106,29 +9204,40 @@ var usePublicAccess = (options = {}) => {
9106
9204
  setError(null);
9107
9205
  try {
9108
9206
  const resolvedPath = input.path || stableSessionInput.path || readPathFromLocation();
9109
- const data = await client.startSession({
9207
+ const resolvedInput = {
9110
9208
  ...stableSessionInput,
9111
9209
  ...input,
9112
9210
  ticket: input.ticket || stableSessionInput.ticket || readTicketFromLocation(),
9113
9211
  path: resolvedPath
9114
- });
9115
- if (!mountedRef.current) return data;
9116
- activeSessionRef.current = {
9117
- accessToken: data.accessToken,
9118
- path: resolvedPath
9119
9212
  };
9120
- setSession(data);
9121
- setAccessToken(data.accessToken, {
9122
- scope: "public",
9123
- path: resolvedPath
9124
- });
9125
- await reloadRuntime({
9126
- accessToken: data.accessToken,
9127
- accessTokenOptions: {
9213
+ let data = await client.startSession(resolvedInput);
9214
+ if (!mountedRef.current) return data;
9215
+ const activateSession = async (next) => {
9216
+ activeSessionRef.current = {
9217
+ accessToken: next.accessToken,
9218
+ path: resolvedPath
9219
+ };
9220
+ setSession(next);
9221
+ setAccessToken(next.accessToken, {
9128
9222
  scope: "public",
9129
9223
  path: resolvedPath
9130
- }
9131
- });
9224
+ });
9225
+ await reloadRuntime({
9226
+ accessToken: next.accessToken,
9227
+ accessTokenOptions: {
9228
+ scope: "public",
9229
+ path: resolvedPath
9230
+ }
9231
+ });
9232
+ };
9233
+ try {
9234
+ await activateSession(data);
9235
+ } catch (activationError) {
9236
+ if (!isUnauthorizedPublicSessionError(activationError)) throw activationError;
9237
+ client.clearSession(resolvedInput);
9238
+ data = await client.startSession(resolvedInput);
9239
+ await activateSession(data);
9240
+ }
9132
9241
  if (!mountedRef.current) return data;
9133
9242
  setLoading(false);
9134
9243
  return data;
@@ -9190,4 +9299,11 @@ var readTicketFromLocation = () => {
9190
9299
  return new URLSearchParams(window.location.search).get("ticket") || void 0;
9191
9300
  };
9192
9301
  var readPathFromLocation = () => typeof window === "undefined" ? void 0 : window.location.pathname;
9302
+ var isUnauthorizedPublicSessionError = (error) => {
9303
+ if (!error || typeof error !== "object") return false;
9304
+ const status = Number(
9305
+ error.status ?? error.statusCode
9306
+ );
9307
+ return status === 401 || status === 403;
9308
+ };
9193
9309
  //# sourceMappingURL=react.cjs.map